Решение на Трета задача от Росен Рачев

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

Към профила на Росен Рачев

Резултати

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

Код

module Graphics
class Canvas
attr_reader :width, :height
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width, false) }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x]
end
def draw(figure)
figure.draw(self)
end
def render_as(renderer)
renderer.render(@canvas)
end
end
module Renderers
class Ascii
def self.render(canvas)
canvas.map(&:join).join("\n").gsub('true', '@').gsub('false', '-')
end
end
class Html
HEADER = ' <!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">'
FOOTER = ' </div>
</body>
</html>'
def self.render(canvas)
HEADER +
canvas.map(&:join).join("<br>").gsub("true", "<b></b>")
.gsub("false", "<i></i>") + FOOTER
end
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
@x == other.x and @y == other.y
end
def draw(canvas)
canvas.set_pixel @x, @y
end
def hash
@x.hash + y
end
def eql?(other)
hash == other.hash
end
end
class Line
attr_reader :from, :to
def initialize(from, to)
@from = from
@to = to
end
def ==(other)
@from == other.from and @to == other.to
end
def hash
@from.hash + @to.hash
end
def eql?(other)
hash == other.hash
end
def draw(canvas)
copy_coordinates
while @from_x != @to_x or @from_y != @to_y
canvas.set_pixel(@from_x, @from_y)
move_to_next_point
end
canvas.set_pixel(@from_x, @from_y)
end
private
def move_to_next_point
if 2 * @error >= -@delta_y
@error -= @delta_y
@from_x += @step_x
end
if 2 * @error < @delta_x
@error += @delta_x
@from_y += @step_y
end
end
def copy_coordinates
@from_x = @from.x
@to_x = @to.x
@to_y = @to.y
@from_y = @from.y
calculate_error
end
def calculate_error
@delta_x = (@to_x - @from_x).abs
@delta_y = (@to_y - @from_y).abs
@step_x = @from_x < @to_x ? 1 : -1
@step_y = @from_y < @to_y ? 1 : -1
@error = @delta_x - @delta_y
end
end
class Rectangle
attr_reader :left, :right
def initialize(left, right)
@left = left
@right = right
end
def top_left
Point.new([@left.x, @right.x].min, [@left.y, @right.y].min)
end
def top_right
Point.new([@left.x, @right.x].max, [@left.y, @right.y].min)
end
def bottom_right
Point.new([@left.x, @right.x].max, [@left.y, @right.y].max)
end
def bottom_left
Point.new([@left.x, @right.x].min, [@left.y, @right.y].max)
end
def ==(other)
(@left == other.left and @right == other.right) or
(@left == other.right and @right == other.left)
end
def hash
@left.hash + @right.hash
end
def eql?(other)
hash == other.hash
end
def draw(canvas)
Line.new(Point.new(@left.x, @left.y), Point.new(@left.x, @right.y)).draw canvas
Line.new(Point.new(@left.x, @right.y), Point.new(@right.x, @right.y)).draw canvas
Line.new(Point.new(@right.x, @right.y), Point.new(@right.x, @left.y)).draw canvas
Line.new(Point.new(@left.x, @left.y), Point.new(@right.x, @left.y)).draw canvas
end
end
end

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

........F.F..F.F.........................FFFF..FF.......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-1tz38c6/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-1tz38c6/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 points works for multiple ones
     Failure/Error: canvas.set_pixel 4, 4
     NoMethodError:
       undefined method `[]=' for nil:NilClass
     # /tmp/d20131223-4637-1tz38c6/solution.rb:12:in `set_pixel'
     # /tmp/d20131223-4637-1tz38c6/spec.rb:57: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 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-1tz38c6/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-1tz38c6/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)>'

  4) 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-1tz38c6/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-1tz38c6/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)>'

  5) Graphics shapes Line initialization with swapped points puts the leftmost point in the from field
     Failure/Error: inverted_line.from.x.should eq 1
       
       expected: 1
            got: 25
       
       (compared using ==)
     # /tmp/d20131223-4637-1tz38c6/spec.rb:402:in `block (6 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 Line initialization with swapped points puts the rightmost point in the to field
     Failure/Error: inverted_line.to.x.should eq 25
       
       expected: 25
            got: 1
       
       (compared using ==)
     # /tmp/d20131223-4637-1tz38c6/spec.rb:407:in `block (6 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)>'

  7) Graphics shapes Line initialization with swapped points puts the top point of vertical lines in the from field
     Failure/Error: vertical_line.from.y.should eq 1
       
       expected: 1
            got: 8
       
       (compared using ==)
     # /tmp/d20131223-4637-1tz38c6/spec.rb:413:in `block (6 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)>'

  8) Graphics shapes Line initialization with swapped points puts the bottom point of vertical lines in the to field
     Failure/Error: vertical_line.to.y.should eq 8
       
       expected: 8
            got: 1
       
       (compared using ==)
     # /tmp/d20131223-4637-1tz38c6/spec.rb:418:in `block (6 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)>'

  9) Graphics shapes Line comparison for equality is true if line ends are the same, even if swapped
     Failure/Error: (a == b).should be_true
       expected: true value
            got: false
     # /tmp/d20131223-4637-1tz38c6/spec.rb:442: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)>'

  10) Graphics shapes Line comparison for equality is true if line is vertical and the bottom is given first
     Failure/Error: (a == b).should be_true
       expected: true value
            got: false
     # /tmp/d20131223-4637-1tz38c6/spec.rb:449: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)>'

  11) Graphics shapes Rectangle initialization puts the leftmost point in its left field
     Failure/Error: rect.left.x.should eq 4
       
       expected: 4
            got: 7
       
       (compared using ==)
     # /tmp/d20131223-4637-1tz38c6/spec.rb:507: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)>'

  12) Graphics shapes Rectangle comparison for equality is true for rectangles defined with different diagonal corners
     Failure/Error: (a == b).should be_true
       expected: true value
            got: false
     # /tmp/d20131223-4637-1tz38c6/spec.rb:540: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.08676 seconds
69 examples, 12 failures

Failed examples:

rspec /tmp/d20131223-4637-1tz38c6/spec.rb:203 # Graphics Canvas drawing of shapes and rasterization renders multiple drawn shapes
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:51 # Graphics Canvas drawing of shapes and rasterization of points works for multiple ones
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:96 # Graphics Canvas drawing of shapes and rasterization of lines works with lines with a small slope
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:127 # Graphics Canvas drawing of shapes and rasterization of lines works with multiple lines
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:401 # Graphics shapes Line initialization with swapped points puts the leftmost point in the from field
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:406 # Graphics shapes Line initialization with swapped points puts the rightmost point in the to field
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:411 # Graphics shapes Line initialization with swapped points puts the top point of vertical lines in the from field
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:416 # Graphics shapes Line initialization with swapped points puts the bottom point of vertical lines in the to field
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:438 # Graphics shapes Line comparison for equality is true if line ends are the same, even if swapped
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:445 # Graphics shapes Line comparison for equality is true if line is vertical and the bottom is given first
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:504 # Graphics shapes Rectangle initialization puts the leftmost point in its left field
rspec /tmp/d20131223-4637-1tz38c6/spec.rb:536 # Graphics shapes Rectangle comparison for equality is true for rectangles defined with different diagonal corners

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

Росен обнови решението на 18.12.2013 00:28 (преди над 10 години)

+module Graphics
+ class Canvas
+ attr_reader :width, :height
+
+ def initialize(width, height)
+ @width = width
+ @height = height
+ @canvas = Array.new(height) { Array.new(width, 0) }
+ end
+
+ def set_pixel(x, y)
+ @canvas[y][x] = 1
+ end
+
+ def pixel_at?(x, y)
+ if @canvas[y][x] == 1
+ true
+ else
+ false
+ end
+ end
+
+ def draw(figure)
+ figure.send(:draw, self)
+ end
+
+ def render_as(renderer)
+ renderer.send(:render, @canvas)
+ end
+ end
+
+ module Renderers
+ class Ascii
+ def self.render(canvas)
+ canvas.map(&:join).join("\n").gsub('1', '@').gsub('0', '-')
+ end
+ end
+
+ class Html
+ @header = " <!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\">"
+
+ @footer = " </div>
+ </body>
+ </html>"
+
+ def self.render(canvas)
+ @header +
+ canvas.map(&:join).join("<br>").gsub("1", "<b></b>")
+ .gsub("0", "<i></i>") + @footer
+ end
+ end
+ end
+
+ class Point
+ attr_reader :x, :y
+
+ def initialize(x, y)
+ @x = x
+ @y = y
+ end
+
+ def ==(other)
+ @x == other.x and @y == other.y
+ end
+
+ def draw(canvas)
+ canvas.set_pixel @x, @y
+ end
+ end
+
+ class Line
+ attr_reader :from, :to
+
+ def initialize(from, to)
+ @from = from
+ @to = to
+ end
+
+ def ==(other)
+ @from == other.from and @to == other.to
+ end
+
+ def draw(canvas)
+ #TODO
+ end
+ end
+
+ class Rectangle
+ attr_reader :left, :right
+
+ def initialize(left, right)
+ @left = left
+ @right = right
+ end
+
+ def top_left
+ Point.new([@left.x, @right.x].min, [@left.y, @right.y].min)
+ end
+
+ def top_right
+ Point.new([@left.x, @right.x].max, [@left.y, @right.y].min)
+ end
+
+ def bottom_right
+ Point.new([@left.x, @right.x].max, [@left.y, @right.y].max)
+ end
+
+ def bottom_left
+ Point.new([@left.x, @right.x].min, [@left.y, @right.y].max)
+ end
+
+ def ==(other)
+ equalizer = @left == other.left and @right == other.right
+ equalizer or @left == other.right and @right == other.left
+ end
+
+
+ def draw(canvas)
+ Line.new(Point.new(@left.x, @left.y), Point.new(@left.x, @right.y)).draw canvas
+ Line.new(Point.new(@left.x, @right.y), Point.new(@right.x, @right.y)).draw canvas
+ Line.new(Point.new(@right.x, @right.y), Point.new(@right.x, @left.y)).draw canvas
+ Line.new(Point.new(@left.x, @left.y), Point.new(@right.x, @left.y)).draw canvas
+ end
+ end
+
+end

Росен обнови решението на 19.12.2013 00:17 (преди над 10 години)

module Graphics
class Canvas
attr_reader :width, :height
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width, 0) }
end
def set_pixel(x, y)
@canvas[y][x] = 1
end
def pixel_at?(x, y)
if @canvas[y][x] == 1
true
else
false
end
end
def draw(figure)
figure.send(:draw, self)
end
def render_as(renderer)
renderer.send(:render, @canvas)
end
end
module Renderers
class Ascii
def self.render(canvas)
canvas.map(&:join).join("\n").gsub('1', '@').gsub('0', '-')
end
end
class Html
@header = " <!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\">"
@footer = " </div>
</body>
</html>"
def self.render(canvas)
@header +
canvas.map(&:join).join("<br>").gsub("1", "<b></b>")
.gsub("0", "<i></i>") + @footer
end
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
@x == other.x and @y == other.y
end
def draw(canvas)
canvas.set_pixel @x, @y
end
end
class Line
attr_reader :from, :to
def initialize(from, to)
- @from = from
- @to = to
+ if (to.y - from.y).abs > (to.x - from.x).abs
+ @from = to
+ @to = from
+ else
+ @from = from
+ @to = to
+ end
end
def ==(other)
@from == other.from and @to == other.to
end
def draw(canvas)
- #TODO
+ coordinates
+ while(@x_0 != @x_1 or @y_0 != @y_1) do
+ canvas.set_pixel(@x_0, @y_0)
+ rasterization
+ end
+ canvas.set_pixel(@x_0, @y_0)
end
+
+ private
+ def rasterization
+ if (2*@error) > -@delta_y
+ @error -= @delta_y
+ @x_0 += @step_x
+ end
+ if (2*@error) < @delta_x
+ @error += @delta_x
+ @y_0 += @step_y
+ end
+ end
+
+ private
+ def coordinates
+ @x_0 = @from.x
+ @x_1 = @to.x
+ @y_1 = @to.y
+ @y_0 = @from.y
+ error
+ end
+
+ private
+ def error
+ @delta_x = (@x_1-@x_0).abs
+ @delta_y = (@y_1-@y_0).abs
+ @step_x = @x_0 < @x_1 ? 1 : -1
+ @step_y = @y_0 < @y_1 ? 1 : -1
+ @error = @delta_x-@delta_y
+ end
end
class Rectangle
attr_reader :left, :right
def initialize(left, right)
@left = left
@right = right
end
def top_left
Point.new([@left.x, @right.x].min, [@left.y, @right.y].min)
end
def top_right
Point.new([@left.x, @right.x].max, [@left.y, @right.y].min)
end
def bottom_right
Point.new([@left.x, @right.x].max, [@left.y, @right.y].max)
end
def bottom_left
Point.new([@left.x, @right.x].min, [@left.y, @right.y].max)
end
def ==(other)
equalizer = @left == other.left and @right == other.right
equalizer or @left == other.right and @right == other.left
end
-
def draw(canvas)
Line.new(Point.new(@left.x, @left.y), Point.new(@left.x, @right.y)).draw canvas
Line.new(Point.new(@left.x, @right.y), Point.new(@right.x, @right.y)).draw canvas
Line.new(Point.new(@right.x, @right.y), Point.new(@right.x, @left.y)).draw canvas
Line.new(Point.new(@left.x, @left.y), Point.new(@right.x, @left.y)).draw canvas
end
end
-
end

Бележки:

  • Помисли дали няма друг по-оптимален начин в Ruby за реализация вътрешното представяне на пано от двумерен масив. Тъй като Ruby не е C, можем да ползваме и други, по-удобни типове данни :)
  • Пикселите имат две състояния; дали най-удачният вариант е да са представени от 0 и 1?
  • pixel_at? има нужда от рефакторинг заради сериозната тафтология там :)
  • Не виждам никакъв смисъл да ползваш send в Canvas#draw и render_as. Защо не просто figure.draw(self)?
  • Малко ми е грозна имплементацията на render в Ascii и в Html.
  • Ползвай единични кавички, HEREDOC, или друг синтаксис при дефинирането на HTML-а, за да не трябва да escape-ваш двойните кавички вътре. Също така, тези два низа е добре да са присвоени на константи.
  • Не виждам да си реализирал eql? и hash.
  • private не е "декоракция" за метод; прочети пак как работи – сменя видимостта за всички методи, дефинирани след извикването му, тоест няма нужда да го слагаш пред всеки метод; освен това се оставя празен ред м/у private и дефиницията на следващия метод (напр. м/у ред 121 и 122).
  • Поработи над имената на методите за растеризация на линия; не са достатъчно ясни и алгоритъмът не се чете добре; не помагат особено и променливите x_0, y_1 и прочее.
  • Ред 114, while condition – няма do, няма скоби и има интервал след while.
  • Слагай интервали около оператори, като * на ред 123 и 127. Там и скобите са излишни. Също така – elsif и малко подравняване ще помогнат за четимостта на този метод. Името му не е добро. Не виждам как това, което прави, е само и точно rasterization. Същото важи и за другите два private метода по-долу.
  • Rectangle#left и right не са направени така, както трябва да са по условие.
  • Нуждата от това супер странно име equalizer, коеето си ползвал в Rectangle#== трябва да те подсеща, че нещо не правиш както трябва в този метод и че трябва да го промениш.
  • Като че ли Rectangle#draw може да се DRY up-не малко и да му се подобри малко четимостта.

Иначе стилът ти е що-годе приличен и откъм дизайн си на прав път.

Росен обнови решението на 21.12.2013 19:01 (преди над 10 години)

module Graphics
class Canvas
attr_reader :width, :height
def initialize(width, height)
@width = width
@height = height
- @canvas = Array.new(height) { Array.new(width, 0) }
+ @canvas = Array.new(height) { Array.new(width, false) }
end
def set_pixel(x, y)
- @canvas[y][x] = 1
+ @canvas[y][x] = true
end
def pixel_at?(x, y)
- if @canvas[y][x] == 1
- true
- else
- false
- end
+ @canvas[y][x]
end
def draw(figure)
- figure.send(:draw, self)
+ figure.draw(self)
end
def render_as(renderer)
- renderer.send(:render, @canvas)
+ renderer.render(@canvas)
end
end
module Renderers
class Ascii
def self.render(canvas)
- canvas.map(&:join).join("\n").gsub('1', '@').gsub('0', '-')
+ canvas.map(&:join).join("\n").gsub('true', '@').gsub('false', '-')
end
end
class Html
- @header = " <!DOCTYPE html>
+ HEADER = ' <!DOCTYPE html>
<html>
<head>
<title>Rendered Canvas</title>
- <style type=\"text/css\">
+ <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\">"
+ <div class="canvas">'
- @footer = " </div>
+ FOOTER = ' </div>
</body>
- </html>"
+ </html>'
def self.render(canvas)
- @header +
- canvas.map(&:join).join("<br>").gsub("1", "<b></b>")
- .gsub("0", "<i></i>") + @footer
+ HEADER +
+ canvas.map(&:join).join("<br>").gsub("true", "<b></b>")
+ .gsub("false", "<i></i>") + FOOTER
end
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
@x == other.x and @y == other.y
end
def draw(canvas)
canvas.set_pixel @x, @y
end
+
+ def hash
+ @x.hash + y
+ end
+
+ def eql?(other)
+ hash == other.hash
+ end
end
class Line
attr_reader :from, :to
def initialize(from, to)
if (to.y - from.y).abs > (to.x - from.x).abs
@from = to
@to = from
else
@from = from
@to = to
end
end
def ==(other)
@from == other.from and @to == other.to
end
+ def hash
+ @from.hash + @to.hash
+ end
+
+ def eql?(other)
+ hash == other.hash
+ end
+
def draw(canvas)
- coordinates
- while(@x_0 != @x_1 or @y_0 != @y_1) do
- canvas.set_pixel(@x_0, @y_0)
- rasterization
+ copy_coordinates
+ while @from_x != @to_x or @from_y != @to_y
+ canvas.set_pixel(@from_x, @from_y)
+ move_to_next_point
end
- canvas.set_pixel(@x_0, @y_0)
+ canvas.set_pixel(@from_x, @from_y)
end
private
- def rasterization
- if (2*@error) > -@delta_y
+
+ def move_to_next_point
+ if 2 * @error > -@delta_y
@error -= @delta_y
- @x_0 += @step_x
+ @from_x += @step_x
end
- if (2*@error) < @delta_x
+ if 2 * @error < @delta_x
@error += @delta_x
- @y_0 += @step_y
+ @from_y += @step_y
end
end
- private
- def coordinates
- @x_0 = @from.x
- @x_1 = @to.x
- @y_1 = @to.y
- @y_0 = @from.y
- error
+ def copy_coordinates
+ @from_x = @from.x
+ @to_x = @to.x
+ @to_y = @to.y
+ @from_y = @from.y
+ calculate_error
end
- private
- def error
- @delta_x = (@x_1-@x_0).abs
- @delta_y = (@y_1-@y_0).abs
- @step_x = @x_0 < @x_1 ? 1 : -1
- @step_y = @y_0 < @y_1 ? 1 : -1
- @error = @delta_x-@delta_y
+ def calculate_error
+ @delta_x = (@to_x - @from_x).abs
+ @delta_y = (@to_y - @from_y).abs
+ @step_x = @from_x < @to_x ? 1 : -1
+ @step_y = @from_y < @to_y ? 1 : -1
+ @error = @delta_x - @delta_y
end
end
class Rectangle
attr_reader :left, :right
def initialize(left, right)
@left = left
@right = right
end
def top_left
Point.new([@left.x, @right.x].min, [@left.y, @right.y].min)
end
def top_right
Point.new([@left.x, @right.x].max, [@left.y, @right.y].min)
end
def bottom_right
Point.new([@left.x, @right.x].max, [@left.y, @right.y].max)
end
def bottom_left
Point.new([@left.x, @right.x].min, [@left.y, @right.y].max)
end
def ==(other)
- equalizer = @left == other.left and @right == other.right
- equalizer or @left == other.right and @right == other.left
+ (@left == other.left and @right == other.right) or
+ (@left == other.right and @right == other.left)
+ end
+
+ def hash
+ @left.hash + @right.hash
+ end
+
+ def eql?(other)
+ hash == other.hash
end
def draw(canvas)
Line.new(Point.new(@left.x, @left.y), Point.new(@left.x, @right.y)).draw canvas
Line.new(Point.new(@left.x, @right.y), Point.new(@right.x, @right.y)).draw canvas
Line.new(Point.new(@right.x, @right.y), Point.new(@right.x, @left.y)).draw canvas
Line.new(Point.new(@left.x, @left.y), Point.new(@right.x, @left.y)).draw canvas
end
end
end

Росен обнови решението на 22.12.2013 01:18 (преди над 10 години)

module Graphics
class Canvas
attr_reader :width, :height
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width, false) }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x]
end
def draw(figure)
figure.draw(self)
end
def render_as(renderer)
renderer.render(@canvas)
end
end
module Renderers
class Ascii
def self.render(canvas)
canvas.map(&:join).join("\n").gsub('true', '@').gsub('false', '-')
end
end
class Html
HEADER = ' <!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">'
FOOTER = ' </div>
</body>
</html>'
def self.render(canvas)
HEADER +
canvas.map(&:join).join("<br>").gsub("true", "<b></b>")
.gsub("false", "<i></i>") + FOOTER
end
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
@x == other.x and @y == other.y
end
def draw(canvas)
canvas.set_pixel @x, @y
end
def hash
@x.hash + y
end
def eql?(other)
hash == other.hash
end
end
class Line
attr_reader :from, :to
def initialize(from, to)
- if (to.y - from.y).abs > (to.x - from.x).abs
- @from = to
- @to = from
- else
- @from = from
- @to = to
- end
+ @from = from
+ @to = to
end
def ==(other)
@from == other.from and @to == other.to
end
def hash
@from.hash + @to.hash
end
def eql?(other)
hash == other.hash
end
def draw(canvas)
copy_coordinates
while @from_x != @to_x or @from_y != @to_y
canvas.set_pixel(@from_x, @from_y)
move_to_next_point
end
canvas.set_pixel(@from_x, @from_y)
end
private
def move_to_next_point
- if 2 * @error > -@delta_y
+ if 2 * @error >= -@delta_y
@error -= @delta_y
@from_x += @step_x
end
if 2 * @error < @delta_x
@error += @delta_x
@from_y += @step_y
end
end
def copy_coordinates
@from_x = @from.x
@to_x = @to.x
@to_y = @to.y
@from_y = @from.y
calculate_error
end
def calculate_error
@delta_x = (@to_x - @from_x).abs
@delta_y = (@to_y - @from_y).abs
@step_x = @from_x < @to_x ? 1 : -1
@step_y = @from_y < @to_y ? 1 : -1
@error = @delta_x - @delta_y
end
end
class Rectangle
attr_reader :left, :right
def initialize(left, right)
@left = left
@right = right
end
def top_left
Point.new([@left.x, @right.x].min, [@left.y, @right.y].min)
end
def top_right
Point.new([@left.x, @right.x].max, [@left.y, @right.y].min)
end
def bottom_right
Point.new([@left.x, @right.x].max, [@left.y, @right.y].max)
end
def bottom_left
Point.new([@left.x, @right.x].min, [@left.y, @right.y].max)
end
def ==(other)
(@left == other.left and @right == other.right) or
(@left == other.right and @right == other.left)
end
def hash
@left.hash + @right.hash
end
def eql?(other)
hash == other.hash
end
def draw(canvas)
Line.new(Point.new(@left.x, @left.y), Point.new(@left.x, @right.y)).draw canvas
Line.new(Point.new(@left.x, @right.y), Point.new(@right.x, @right.y)).draw canvas
Line.new(Point.new(@right.x, @right.y), Point.new(@right.x, @left.y)).draw canvas
Line.new(Point.new(@left.x, @left.y), Point.new(@right.x, @left.y)).draw canvas
end
end
end
  • Може би вече си видял, че имах предвид вътрешно представяне на пано като Hash :)
  • Не ми харесват тези gsub-ове на true/false в render-методите.
  • Трябваше да ползваш alias или alias_method за един от двата метода за равенство.

Решението ти е сносно като цяло, но не дотам, че да ти дам бонус точки. Има още над какво да поработиш :) Виж моето решение и решенията на колеги, на които см давал 2-3 бонус точки, за идеи и вдъхновение.