Решение на Трета задача от Наталия Пацовска

Обратно към всички решения

Към профила на Наталия Пацовска

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 63 успешни тест(а)
  • 6 неуспешни тест(а)

Код

module Graphics
class Canvas
require 'set'
attr_reader :width, :height
def initialize(width, height)
@width = width
@height = height
@filled_pixels = Set.new
end
def set_pixel(x, y)
@filled_pixels.add [x, y]
end
def pixel_at?(x, y)
@filled_pixels.member? [x, y]
end
def draw(figure)
figure.pixels.each { |pixel| set_pixel pixel.x, pixel.y}
end
def render_as(renderer)
rendered_canvas = renderer.render_canvas self
puts rendered_canvas
rendered_canvas
end
def clear
@filled_pixels = Set.new
end
end
class Point
attr_reader :x, :y
alias_method :eql?, :==
def initialize(x, y)
@x = x
@y = y
end
def coordinates
[x, y]
end
def pixels
[self]
end
def <=>(other)
coordinates <=> other.coordinates
end
def ==(other)
(x == other.x and y == other.y)
end
def hash
coordinates.hash
end
end
class Line
attr_reader :from, :to
alias_method :eql?, :==
def initialize(from, to)
@from, @to = [from, to].sort
end
def ==(other)
(from == other.from and to == other.to) or (from == other.to and to == other.from)
end
def hash
[from.coordinates, to.coordinates].hash
end
def pixels
distances = [(to.x - from.x).abs, -(to.y - from.y).abs]
steps = [from.x <= to.x ? 1 : -1, from.y <= to.y ? 1 : -1]
error = distances.reduce(&:+)
line_points_bresenham(from, error, distances, steps)
end
private
def line_points_bresenham(point, error, distances, steps)
points = [point]
loop do
break if point == to or point.x < 0
point, error = calculate_next_point(point, error, distances, steps)
points << point
end
points
end
def calculate_next_point(point, error, distances, steps)
new_coordinates = point.coordinates.each_with_index.map do |coordinate, index|
if should_change_coordinates?(distances, 2 * error)[index]
coordinate += steps[index]
error += distances[(index - 1).abs]
end
coordinate
end
[Point.new(new_coordinates[0], new_coordinates[1]), error]
end
def should_change_coordinates?(distances, error)
[error >= distances[1], error < distances[0]]
end
end
class Rectangle
attr_reader :left, :right
attr_reader :top_left, :top_right, :bottom_left, :bottom_right
alias_method :eql?, :==
def initialize(first_point, second_point)
@left, @right = [first_point, second_point].sort
@top_left, @bottom_left = [left, Point.new(left.x, right.y)].sort
@top_right, @bottom_right = [right, Point.new(right.x, left.y)].sort
end
def pixels
vertexes = [top_left, top_right, bottom_right, bottom_left, top_left]
vertexes.each_cons(2).map { |from, to| Graphics::Line.new(from, to).pixels }.flatten
end
def ==(other)
top_left == other.top_left and bottom_right == other.bottom_right
end
def hash
[top_left, bottom_right].hash
end
end
module Renderers
module Renderer
def render_canvas(canvas)
@@canvas = canvas
0.upto(canvas.height - 1).map do |y|
row = 0.upto(canvas.width - 1).map { |x| render_pixel_at(x, y) } * ""
end * line_separator
end
def render_pixel_at(x, y)
@@canvas.pixel_at?(x, y) ? filled_pixel : empty_pixel
end
end
class Ascii
extend Renderer
class << self
def line_separator
"\n"
end
def filled_pixel
"@"
end
def empty_pixel
"-"
end
end
end
class Html
extend Renderer
class << self
def line_separator
"<br>"
end
def filled_pixel
"<b></b>"
end
def empty_pixel
"<i></i>"
end
def render_canvas(canvas)
output = "#{<<HTML_HEADER}#{super}#{<<HTMLL_FOOTER}"
<!DOCTYPE html><html><head><title>Rendered Canvas</title>
<style type='text/css'>
.canvas {font-size: 1px;line-height: 1px;}
.canvas * {display: inline-block;width: 10px;height: 10px;border-radius: 5px;}
.canvas i {background-color: #eee;}
.canvas b {background-color: #333;}
</style></head><body><div class="canvas">
HTML_HEADER
</div></body></html>
HTMLL_FOOTER
end
end
end
end
end

Лог от изпълнението

........@@@@@@@@@@@@@@@
@-------------@
@-@@@@@@@@@@@-@
@-@---------@-@
@-@-----@@@-@-@
@-@--@@@----@-@
@-@-@-------@-@
@-@---------@-@
@-@-@@@@----@-@
@-@-@-------@-@
@-@---------@-@
@-@---------@-@
@-@@@@@@@@@@@-@
@-------------@
@@@@@@@@@@@@@@@
F.@---
@---
-@@-
----
.--------
---@@@@-
--------
.-@------
-@------
-@------
-@------
-@------
-@------
-@------
--------
.----------
-@--------
--@@@@----
------@@@-
----------
F----------
-@--------
-@--------
--@-------
--@-------
--@-------
--@-------
---@------
---@------
----------
.-@--------
-@--------
-@@@@@----
-@----@@@-
----------
F---
-@-
---
.----------
-@@@@@@@@-
-@------@-
-@@@@@@@@-
----------
.----------
-@@@@@@@@-
-@------@-
-@@@@@@@@-
----------
.----------
-@@@@@@@@-
----------
.---
-@-
---
.----
----
----
.----
----
----
.@---
----
---@
.<!DOCTYPE html><html><head><title>Rendered Canvas</title>
 <style type='text/css'>
    .canvas {font-size: 1px;line-height: 1px;}
    .canvas * {display: inline-block;width: 10px;height: 10px;border-radius: 5px;}
    .canvas i {background-color: #eee;}
    .canvas b {background-color: #333;}
  </style></head><body><div class="canvas">
<i></i><i></i><i></i><i></i><br><i></i><i></i><i></i><i></i><br><i></i><i></i><i></i><i></i>      </div></body></html>
.<!DOCTYPE html><html><head><title>Rendered Canvas</title>
 <style type='text/css'>
    .canvas {font-size: 1px;line-height: 1px;}
    .canvas * {display: inline-block;width: 10px;height: 10px;border-radius: 5px;}
    .canvas i {background-color: #eee;}
    .canvas b {background-color: #333;}
  </style></head><body><div class="canvas">
<i></i><i></i><i></i><i></i><br><i></i><i></i><i></i><i></i><br><i></i><i></i><i></i><i></i>      </div></body></html>
.<!DOCTYPE html><html><head><title>Rendered Canvas</title>
 <style type='text/css'>
    .canvas {font-size: 1px;line-height: 1px;}
    .canvas * {display: inline-block;width: 10px;height: 10px;border-radius: 5px;}
    .canvas i {background-color: #eee;}
    .canvas b {background-color: #333;}
  </style></head><body><div class="canvas">
<i></i><i></i><i></i><i></i><br><i></i><b></b><i></i><i></i><br><i></i><b></b><i></i><i></i>      </div></body></html>
.<!DOCTYPE html><html><head><title>Rendered Canvas</title>
 <style type='text/css'>
    .canvas {font-size: 1px;line-height: 1px;}
    .canvas * {display: inline-block;width: 10px;height: 10px;border-radius: 5px;}
    .canvas i {background-color: #eee;}
    .canvas b {background-color: #333;}
  </style></head><body><div class="canvas">
<i></i><i></i><i></i><i></i><br><i></i><b></b><i></i><i></i><br><i></i><b></b><i></i><i></i>      </div></body></html>
<!DOCTYPE html><html><head><title>Rendered Canvas</title>
 <style type='text/css'>
    .canvas {font-size: 1px;line-height: 1px;}
    .canvas * {display: inline-block;width: 10px;height: 10px;border-radius: 5px;}
    .canvas i {background-color: #eee;}
    .canvas b {background-color: #333;}
  </style></head><body><div class="canvas">
<i></i><i></i><i></i><i></i><br><i></i><b></b><i></i><i></i><br><i></i><b></b><i></i><i></i>      </div></body></html>
.......F..............F...........F.......

Failures:

  1) Graphics Canvas drawing of shapes and rasterization renders multiple drawn shapes
     Failure/Error: ascii.should eq rendering(expected)
       
       expected: "@@@@@@@@@@@@@@@\n@-------------@\n@-@@@@@@@@@@@-@\n@-@---------@-@\n@-@------@@-@-@\n@-@---@@@---@-@\n@-@-@@------@-@\n@-@---------@-@\n@-@-@@@@----@-@\n@-@-@-------@-@\n@-@---------@-@\n@-@---------@-@\n@-@@@@@@@@@@@-@\n@-------------@\n@@@@@@@@@@@@@@@"
            got: "@@@@@@@@@@@@@@@\n@-------------@\n@-@@@@@@@@@@@-@\n@-@---------@-@\n@-@-----@@@-@-@\n@-@--@@@----@-@\n@-@-@-------@-@\n@-@---------@-@\n@-@-@@@@----@-@\n@-@-@-------@-@\n@-@---------@-@\n@-@---------@-@\n@-@@@@@@@@@@@-@\n@-------------@\n@@@@@@@@@@@@@@@"
       
       (compared using ==)
       
       Diff:
       @@ -2,9 +2,9 @@
        @-------------@
        @-@@@@@@@@@@@-@
        @-@---------@-@
       -@-@------@@-@-@
       -@-@---@@@---@-@
       -@-@-@@------@-@
       +@-@-----@@@-@-@
       +@-@--@@@----@-@
       +@-@-@-------@-@
        @-@---------@-@
        @-@-@@@@----@-@
        @-@-@-------@-@
     # /tmp/d20131223-4637-l3xuky/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-l3xuky/spec.rb:211:in `block (4 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Graphics Canvas drawing of shapes and rasterization of lines works with lines with a small slope
     Failure/Error: ascii.should eq rendering(expected)
       
       expected: "----------\n-@@-------\n---@@@@---\n-------@@-\n----------"
            got: "----------\n-@--------\n--@@@@----\n------@@@-\n----------"
       
       (compared using ==)
       
       Diff:
       @@ -1,6 +1,6 @@
        ----------
       --@@-------
       ----@@@@---
       --------@@-
       +-@--------
       +--@@@@----
       +------@@@-
        ----------
     # /tmp/d20131223-4637-l3xuky/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-l3xuky/spec.rb:100:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) Graphics Canvas drawing of shapes and rasterization of lines works with multiple lines
     Failure/Error: ascii.should eq rendering(expected)
       
       expected: "-@--------\n-@@-------\n-@-@@@@---\n-@-----@@-\n----------"
            got: "-@--------\n-@--------\n-@@@@@----\n-@----@@@-\n----------"
       
       (compared using ==)
       
       Diff:
       @@ -1,6 +1,6 @@
        -@--------
       --@@-------
       --@-@@@@---
       --@-----@@-
       +-@--------
       +-@@@@@----
       +-@----@@@-
        ----------
     # /tmp/d20131223-4637-l3xuky/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-l3xuky/spec.rb:132:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) Graphics shapes Point comparison for equality works for eql? as well
     Failure/Error: a1.should eql a2
       
       expected: #<Graphics::Point:0xb9ce8920 @x=4, @y=5>
            got: #<Graphics::Point:0xb9ce895c @x=4, @y=5>
       
       (compared using eql?)
       
       Diff:
       @@ -1,2 +1,2 @@
       -#<Graphics::Point:0xb9ce8920 @x=4, @y=5>
       +#<Graphics::Point:0xb9ce895c @x=4, @y=5>
     # /tmp/d20131223-4637-l3xuky/spec.rb:356:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) Graphics shapes Line comparison for equality works with eql? as well
     Failure/Error: a.should eql b
       
       expected: #<Graphics::Line:0xb9c8fac8 @from=#<Graphics::Point:0xb9c8fb18 @x=1, @y=1>, @to=#<Graphics::Point:0xb9c8faf0 @x=10, @y=14>>
            got: #<Graphics::Line:0xb9c8fbb8 @from=#<Graphics::Point:0xb9c8fc6c @x=1, @y=1>, @to=#<Graphics::Point:0xb9c8fc08 @x=10, @y=14>>
       
       (compared using eql?)
       
       Diff:
       @@ -1,4 +1,4 @@
       -#<Graphics::Line:0xb9c8fac8
       - @from=#<Graphics::Point:0xb9c8fb18 @x=1, @y=1>,
       - @to=#<Graphics::Point:0xb9c8faf0 @x=10, @y=14>>
       +#<Graphics::Line:0xb9c8fbb8
       + @from=#<Graphics::Point:0xb9c8fc6c @x=1, @y=1>,
       + @to=#<Graphics::Point:0xb9c8fc08 @x=10, @y=14>>
     # /tmp/d20131223-4637-l3xuky/spec.rb:457:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  6) Graphics shapes Rectangle comparison for equality works with eql? as well
     Failure/Error: a.should eql b
       
       expected: #<Graphics::Rectangle:0xb9c5e090 @left=#<Graphics::Point:0xb9c5e0e0 @x=1, @y=1>, @right=#<Graphics::Point:0xb9c5e0b8 @x=10, @y=14>, @top_left=#<Graphics::Point:0xb9c5e0e0 @x=1, @y=1>, @bottom_left=#<Graphics::Point:0xb9c5e018 @x=1, @y=14>, @top_right=#<Graphics::Point:0xb9c5dfa0 @x=10, @y=1>, @bottom_right=#<Graphics::Point:0xb9c5e0b8 @x=10, @y=14>>
            got: #<Graphics::Rectangle:0xb9c5e298 @left=#<Graphics::Point:0xb9c5e2e8 @x=1, @y=1>, @right=#<Graphics::Point:0xb9c5e2c0 @x=10, @y=14>, @top_left=#<Graphics::Point:0xb9c5e2e8 @x=1, @y=1>, @bottom_left=#<Graphics::Point:0xb9c5e20c @x=1, @y=14>, @top_right=#<Graphics::Point:0xb9c5e194 @x=10, @y=1>, @bottom_right=#<Graphics::Point:0xb9c5e2c0 @x=10, @y=14>>
       
       (compared using eql?)
       
       Diff:
       @@ -1,8 +1,8 @@
       -#<Graphics::Rectangle:0xb9c5e090
       - @bottom_left=#<Graphics::Point:0xb9c5e018 @x=1, @y=14>,
       - @bottom_right=#<Graphics::Point:0xb9c5e0b8 @x=10, @y=14>,
       - @left=#<Graphics::Point:0xb9c5e0e0 @x=1, @y=1>,
       - @right=#<Graphics::Point:0xb9c5e0b8 @x=10, @y=14>,
       - @top_left=#<Graphics::Point:0xb9c5e0e0 @x=1, @y=1>,
       - @top_right=#<Graphics::Point:0xb9c5dfa0 @x=10, @y=1>>
       +#<Graphics::Rectangle:0xb9c5e298
       + @bottom_left=#<Graphics::Point:0xb9c5e20c @x=1, @y=14>,
       + @bottom_right=#<Graphics::Point:0xb9c5e2c0 @x=10, @y=14>,
       + @left=#<Graphics::Point:0xb9c5e2e8 @x=1, @y=1>,
       + @right=#<Graphics::Point:0xb9c5e2c0 @x=10, @y=14>,
       + @top_left=#<Graphics::Point:0xb9c5e2e8 @x=1, @y=1>,
       + @top_right=#<Graphics::Point:0xb9c5e194 @x=10, @y=1>>
     # /tmp/d20131223-4637-l3xuky/spec.rb:548:in `block (5 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.10074 seconds
69 examples, 6 failures

Failed examples:

rspec /tmp/d20131223-4637-l3xuky/spec.rb:203 # Graphics Canvas drawing of shapes and rasterization renders multiple drawn shapes
rspec /tmp/d20131223-4637-l3xuky/spec.rb:96 # Graphics Canvas drawing of shapes and rasterization of lines works with lines with a small slope
rspec /tmp/d20131223-4637-l3xuky/spec.rb:127 # Graphics Canvas drawing of shapes and rasterization of lines works with multiple lines
rspec /tmp/d20131223-4637-l3xuky/spec.rb:355 # Graphics shapes Point comparison for equality works for eql? as well
rspec /tmp/d20131223-4637-l3xuky/spec.rb:452 # Graphics shapes Line comparison for equality works with eql? as well
rspec /tmp/d20131223-4637-l3xuky/spec.rb:543 # Graphics shapes Rectangle comparison for equality works with eql? as well

История (2 версии и 0 коментара)

Наталия обнови решението на 22.12.2013 21:54 (преди почти 11 години)

+module Graphics
+
+ class Canvas
+
+ require 'set'
+ attr_reader :width, :height
+
+ def initialize(width, height)
+ @width = width
+ @height = height
+ @filled_pixels = Set.new
+ end
+
+ def set_pixel(x, y)
+ @filled_pixels.add [x, y]
+ end
+
+ def pixel_at?(x, y)
+ @filled_pixels.member? [x, y]
+ end
+
+ def draw(figure)
+ figure.pixels.each { |pixel| set_pixel pixel.x, pixel.y}
+ end
+
+ def render_as(renderer)
+ puts renderer.render_canvas self
+ end
+
+ def clear
+ @filled_pixels = Set.new
+ end
+ end
+
+ class Point
+
+ attr_reader :x, :y
+ alias_method :eql?, :==
+
+ def initialize(x, y)
+ @x = x
+ @y = y
+ end
+
+ def coordinates
+ [x, y]
+ end
+
+ def pixels
+ [self]
+ end
+
+ def <=>(other)
+ coordinates <=> other.coordinates
+ end
+
+ def ==(other)
+ (x == other.x and y == other.y)
+ end
+
+ def hash
+ coordinates.hash
+ end
+ end
+
+ class Line
+
+ attr_reader :from, :to
+ alias_method :eql?, :==
+
+ def initialize(from, to)
+ @from, @to = [from, to].sort
+ puts "From #{from.coordinates} TO #{to.coordinates}"
+ end
+
+ def ==(other)
+ (from == other.from and to == other.to) or (from == other.to and to == other.from)
+ end
+
+ def hash
+ [from.coordinates, to.coordinates].hash
+ end
+
+ def pixels
+ distances = [(to.x - from.x).abs, -(to.y - from.y).abs]
+ steps = [from.x <= to.x ? 1 : -1, from.y <= to.y ? 1 : -1]
+ error = distances.reduce(&:+)
+ line_points_bresenham(from, error, distances, steps)
+ end
+
+ private
+
+ def line_points_bresenham(point, error, distances, steps)
+ points = [point]
+ loop do
+ break if point == to or point.x < 0
+ point, error = calculate_next_point(point, error, distances, steps)
+ points << point
+ end
+ points
+ end
+
+ def calculate_next_point(point, error, distances, steps)
+ new_coordinates = point.coordinates.each_with_index.map do |coordinate, index|
+ if should_change_coordinates?(distances, 2 * error)[index]
+ coordinate += steps[index]
+ error += distances[(index - 1).abs]
+ end
+ coordinate
+ end
+ [Point.new(new_coordinates[0], new_coordinates[1]), error]
+ end
+
+ def should_change_coordinates?(distances, error)
+ [error >= distances[1], error < distances[0]]
+ end
+
+ end
+
+ class Rectangle
+
+ attr_reader :left, :right
+ attr_reader :top_left, :top_right, :bottom_left, :bottom_right
+ alias_method :eql?, :==
+
+ def initialize(first_point, second_point)
+ @left, @right = [first_point, second_point].sort
+ @top_left, @bottom_left = [left, Point.new(left.x, right.y)].sort
+ @top_right, @bottom_right = [right, Point.new(right.x, left.y)].sort
+ end
+
+ def pixels
+ vertexes = [top_left, top_right, bottom_right, bottom_left, top_left]
+ vertexes.each_cons(2).map { |from, to| Graphics::Line.new(from, to).pixels }.flatten
+ end
+
+ def ==(other)
+ top_left == other.top_left and bottom_right == other.bottom_right
+ end
+
+ def hash
+ [top_left, bottom_right].hash
+ end
+
+ end
+
+ module Renderers
+
+ module Renderer
+ def render_canvas(canvas)
+ @@canvas = canvas
+ 0.upto(canvas.height - 1).map do |y|
+ row = 0.upto(canvas.width - 1).map { |x| render_pixel_at(x, y) } * ""
+ end * line_separator
+ end
+
+ def render_pixel_at(x, y)
+ @@canvas.pixel_at?(x, y) ? filled_pixel : empty_pixel
+ end
+ end
+
+ class Ascii
+
+ extend Renderer
+
+ class << self
+
+ def line_separator
+ "\n"
+ end
+
+ def filled_pixel
+ "@"
+ end
+
+ def empty_pixel
+ "-"
+ end
+ end
+ end
+
+ class Html
+
+ extend Renderer
+
+ class << self
+ def line_separator
+ "<br>"
+ end
+
+ def filled_pixel
+ "<b></b>"
+ end
+
+ def empty_pixel
+ "<i></i>"
+ end
+ def render_canvas(canvas)
+ output = "#{<<HTML_HEADER}#{super}#{<<HTMLL_FOOTER}"
+<!DOCTYPE html><html><head><title>Rendered Canvas</title>
+ <style type='text/css'>
+ .canvas {font-size: 1px;line-height: 1px;}
+ .canvas * {display: inline-block;width: 10px;height: 10px;border-radius: 5px;}
+ .canvas i {background-color: #eee;}
+ .canvas b {background-color: #333;}
+ </style></head><body><div class='canvas'>
+HTML_HEADER
+ </div></body></html>
+HTMLL_FOOTER
+ end
+ end
+ end
+ end
+
+end

Наталия обнови решението на 22.12.2013 22:37 (преди почти 11 години)

module Graphics
class Canvas
require 'set'
attr_reader :width, :height
def initialize(width, height)
@width = width
@height = height
@filled_pixels = Set.new
end
def set_pixel(x, y)
@filled_pixels.add [x, y]
end
def pixel_at?(x, y)
@filled_pixels.member? [x, y]
end
def draw(figure)
figure.pixels.each { |pixel| set_pixel pixel.x, pixel.y}
end
def render_as(renderer)
- puts renderer.render_canvas self
+ rendered_canvas = renderer.render_canvas self
+ puts rendered_canvas
+ rendered_canvas
end
def clear
@filled_pixels = Set.new
end
end
class Point
attr_reader :x, :y
alias_method :eql?, :==
def initialize(x, y)
@x = x
@y = y
end
def coordinates
[x, y]
end
def pixels
[self]
end
def <=>(other)
coordinates <=> other.coordinates
end
def ==(other)
(x == other.x and y == other.y)
end
def hash
coordinates.hash
end
end
class Line
attr_reader :from, :to
alias_method :eql?, :==
def initialize(from, to)
@from, @to = [from, to].sort
- puts "From #{from.coordinates} TO #{to.coordinates}"
end
def ==(other)
(from == other.from and to == other.to) or (from == other.to and to == other.from)
end
def hash
[from.coordinates, to.coordinates].hash
end
def pixels
distances = [(to.x - from.x).abs, -(to.y - from.y).abs]
steps = [from.x <= to.x ? 1 : -1, from.y <= to.y ? 1 : -1]
error = distances.reduce(&:+)
line_points_bresenham(from, error, distances, steps)
end
private
def line_points_bresenham(point, error, distances, steps)
points = [point]
loop do
break if point == to or point.x < 0
point, error = calculate_next_point(point, error, distances, steps)
points << point
end
points
end
def calculate_next_point(point, error, distances, steps)
new_coordinates = point.coordinates.each_with_index.map do |coordinate, index|
if should_change_coordinates?(distances, 2 * error)[index]
coordinate += steps[index]
error += distances[(index - 1).abs]
end
coordinate
end
[Point.new(new_coordinates[0], new_coordinates[1]), error]
end
def should_change_coordinates?(distances, error)
[error >= distances[1], error < distances[0]]
end
end
class Rectangle
attr_reader :left, :right
attr_reader :top_left, :top_right, :bottom_left, :bottom_right
alias_method :eql?, :==
def initialize(first_point, second_point)
@left, @right = [first_point, second_point].sort
@top_left, @bottom_left = [left, Point.new(left.x, right.y)].sort
@top_right, @bottom_right = [right, Point.new(right.x, left.y)].sort
end
def pixels
vertexes = [top_left, top_right, bottom_right, bottom_left, top_left]
vertexes.each_cons(2).map { |from, to| Graphics::Line.new(from, to).pixels }.flatten
end
def ==(other)
top_left == other.top_left and bottom_right == other.bottom_right
end
def hash
[top_left, bottom_right].hash
end
end
module Renderers
module Renderer
def render_canvas(canvas)
@@canvas = canvas
0.upto(canvas.height - 1).map do |y|
row = 0.upto(canvas.width - 1).map { |x| render_pixel_at(x, y) } * ""
end * line_separator
end
def render_pixel_at(x, y)
@@canvas.pixel_at?(x, y) ? filled_pixel : empty_pixel
end
end
class Ascii
extend Renderer
class << self
def line_separator
"\n"
end
def filled_pixel
"@"
end
def empty_pixel
"-"
end
end
end
class Html
extend Renderer
class << self
def line_separator
"<br>"
end
def filled_pixel
"<b></b>"
end
def empty_pixel
"<i></i>"
end
def render_canvas(canvas)
output = "#{<<HTML_HEADER}#{super}#{<<HTMLL_FOOTER}"
<!DOCTYPE html><html><head><title>Rendered Canvas</title>
<style type='text/css'>
.canvas {font-size: 1px;line-height: 1px;}
.canvas * {display: inline-block;width: 10px;height: 10px;border-radius: 5px;}
.canvas i {background-color: #eee;}
.canvas b {background-color: #333;}
- </style></head><body><div class='canvas'>
+ </style></head><body><div class="canvas">
HTML_HEADER
</div></body></html>
HTMLL_FOOTER
end
end
end
end
end