Решение на Трета задача от Стефан Василев

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

Към профила на Стефан Василев

Резултати

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

Код

module Graphics
class Renderers
class Ascii
def initialize(canvas)
@canvas = canvas
end
def render
output = ""
@canvas.pixels.each_index do |index|
output << (@canvas.pixels[index] ? "@" : "-")
output << "\n" if ((index + 1).remainder (@canvas.width)) == 0
end
output.chomp
end
end
class Html
def initialize(canvas)
@canvas = canvas
@html_code = ['
<!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">',
'
</div>
</body>
</html>']
end
def render
output = @html_code[0]
@canvas.pixels.each_index do |index|
output << (@canvas.pixels[index] ? "<b></b>" : "<i></i>")
output << "<br>\n" if ((index + 1).remainder (@canvas.width)) == 0
end
output.chomp.chop.chop.chop.chop << @html_code[1]
end
end
end
class Canvas
attr_reader :width, :height, :pixels
def initialize(width, height)
@width = width
@height = height
@pixels = []
(width * height).times { @pixels << false }
end
def set_pixel(x, y)
@pixels[x + width * y] = true
end
def pixel_at?(x, y)
@pixels[x + width * y]
end
def draw(shape)
shape.points.each do |point|
set_pixel point.x, point.y
end
end
def render_as(renderer)
renderer.new(self).render
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def points
[Point.new(x, y)]
end
def ==(other_point)
x == other_point.x and y == other_point.y
end
def eql?(other_point)
self == other_point
end
def hash
x.hash % y.hash
end
end
class Line
def initialize(from, to)
@from = from
@to = to
end
def from
Point.new @from.x <= @to.x ? @from.x : @to.x,
@from.x <= @to.x ? @from.y : @to.y
end
def to
Point.new @from.x > @to.x ? @from.x : @to.x,
@from.x > @to.x ? @from.y : @to.y
end
def points(left = from, right = to, result = [left, right])
return result if (left.x - right.x).abs <= 1 and (left.y - right.y).abs <= 1
result << Point.new((left.x + right.x) / 2, (left.y + right.y) / 2)
points left, Point.new((left.x + right.x) / 2, (left.y + right.y) / 2), result
points Point.new((left.x + right.x) / 2, (left.y + right.y) / 2), right, result
end
def ==(other_line)
from == other_line.from and to == other_line.to
end
def eql?(other_line)
self == other_line
end
def hash
from.hash + to.hash
end
end
class Rectangle
def initialize(top_left, bottom_right)
@top_left = top_left
@bottom_right = bottom_right
end
def top_left
left
end
def bottom_right
right
end
def top_right
Point.new bottom_right.x, top_left.y
end
def bottom_left
Point.new top_left.x, bottom_right.y
end
def left
Point.new @top_left.x < @bottom_right.x ? @top_left.x : @bottom_right.x,
@top_left.y < @bottom_right.y ? @top_left.y : @bottom_right.y
end
def right
Point.new @top_left.x > @bottom_right.x ? @top_left.x : @bottom_right.x,
@top_left.y > @bottom_right.y ? @top_left.y : @bottom_right.y
end
def points
[(Line.new top_left, top_right).points,
(Line.new top_left, bottom_left).points,
(Line.new top_right, bottom_right).points,
(Line.new bottom_left, bottom_right).points].flatten
end
def ==(rectangle)
top_left == rectangle.top_left and bottom_right == rectangle.bottom_right
end
def eql?(rectangle)
self == rectangle
end
def hash
top_left.hash + top_right.hash + bottom_right.hash + bottom_left.hash
end
end
end

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

........F.F..FFF...........................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-e8uh5w/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-e8uh5w/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: ascii.should eq rendering(expected)
       
       expected: "@---\n@---\n-@@-\n----"
            got: "@---\n@---\n-@@-\n----\n----\n@"
       
       (compared using ==)
       
       Diff:
       @@ -2,4 +2,6 @@
        @---
        -@@-
        ----
       +----
       +@
     # /tmp/d20131223-4637-e8uh5w/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-e8uh5w/spec.rb:59: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-e8uh5w/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-e8uh5w/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 lines with a significant slope, with swapped ends
     Failure/Error: ascii.should eq rendering(expected)
       
       expected: "----------\n-@--------\n-@--------\n--@-------\n--@-------\n--@-------\n--@-------\n---@------\n---@------\n----------"
            got: "----------\n-@--------\n-@--------\n-@--------\n--@-------\n--@-------\n--@-------\n--@-------\n---@------\n----------"
       
       (compared using ==)
       
       Diff:
       
       @@ -1,11 +1,11 @@
        ----------
        -@--------
        -@--------
       +-@--------
        --@-------
        --@-------
        --@-------
        --@-------
       ----@------
        ---@------
        ----------
     # /tmp/d20131223-4637-e8uh5w/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-e8uh5w/spec.rb:113: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 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-e8uh5w/spec.rb:624:in `check_rendering_of'
     # /tmp/d20131223-4637-e8uh5w/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)>'

  6) 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-e8uh5w/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)>'

  7) 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-e8uh5w/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)>'

  8) 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-e8uh5w/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)>'

  9) Graphics shapes Rectangle initialization puts the leftmost point in its left field
     Failure/Error: rect.left.y.should eq 1
       
       expected: 1
            got: 0
       
       (compared using ==)
     # /tmp/d20131223-4637-e8uh5w/spec.rb:508: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.08695 seconds
69 examples, 9 failures

Failed examples:

rspec /tmp/d20131223-4637-e8uh5w/spec.rb:203 # Graphics Canvas drawing of shapes and rasterization renders multiple drawn shapes
rspec /tmp/d20131223-4637-e8uh5w/spec.rb:51 # Graphics Canvas drawing of shapes and rasterization of points works for multiple ones
rspec /tmp/d20131223-4637-e8uh5w/spec.rb:96 # Graphics Canvas drawing of shapes and rasterization of lines works with lines with a small slope
rspec /tmp/d20131223-4637-e8uh5w/spec.rb:109 # Graphics Canvas drawing of shapes and rasterization of lines works with lines with a significant slope, with swapped ends
rspec /tmp/d20131223-4637-e8uh5w/spec.rb:127 # Graphics Canvas drawing of shapes and rasterization of lines works with multiple lines
rspec /tmp/d20131223-4637-e8uh5w/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-e8uh5w/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-e8uh5w/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-e8uh5w/spec.rb:504 # Graphics shapes Rectangle initialization puts the leftmost point in its left field

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

Стефан обнови решението на 17.12.2013 02:46 (преди над 10 години)

+ html_top = "<!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_end = "</div>
+ </body>
+ </html>"
+
+module Graphics
+ class Renderers
+ class Ascii
+ def initialize(canvas)
+ @canvas = canvas
+ end
+ def render
+ output = ""
+ @canvas.pixels.each_index do |index|
+ output << (@canvas.pixels[index] == true ? "@" : "-")
+ output << "\n" if ((index + 1).remainder (@canvas.height)) == 0
+ end
+ output
+ end
+ end
+
+ class Html
+
+ def initialize(canvas)
+ @canvas = canvas
+ @code = ["<!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\">", " </div>
+ </body>
+</html>"]
+ end
+ def render
+ output = @code[0]
+ @canvas.pixels.each_index do |index|
+ output << (@canvas.pixels[index] == true ? "<b></b>" : "<i></i>")
+ output << "<br/>\n" if ((index + 1).remainder (@canvas.height)) == 0
+ end
+ output << @code[1]
+ end
+ end
+ end
+
+ class Canvas
+ attr_reader :width, :height, :pixels
+
+ def initialize(width, height)
+ @width = width
+ @height = height
+ @pixels = []
+ (width * height).times { @pixels << false }
+ end
+
+ def set_pixel(x, y)
+ @pixels[x + height * y] = true
+ end
+
+ def pixel_at?(x, y)
+ @pixels[x + height * y] == true
+ end
+
+ def draw(shape)
+ shape.points.each do |point|
+ set_pixel point.x, point.y
+ end
+ end
+
+ def render_as(symbols)
+ (symbols.new self).render
+ end
+ end
+
+ class Point
+ attr_reader :x, :y
+
+ def initialize(x, y)
+ @x = x
+ @y = y
+ end
+
+ def points
+ [(Point.new x, y)]
+ end
+
+ def ==(other_point)
+ x == other_point.x and y == other_point.y
+ end
+
+ def eql?(other_point)
+ self.== other_point
+ end
+ end
+
+ class Line
+ attr_reader :from, :to
+
+ def initialize(from, to)
+ @from = from
+ @to = to
+ end
+
+ def points(left = from, right = to, result = [left, right])
+ return result if (left.x - right.x).abs <= 1 and (left.y - right.y).abs <= 1
+ result << (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2)
+ points(left, (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), result)
+ points((Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), right, result)
+ end
+
+ def ==(other_line)
+ from == other_point.from and to == other_point.to
+ end
+
+ def eql?(other_line)
+ self.== other_point
+ end
+ end
+
+ class Rectangle
+ attr_reader :top_left, :bottom_right
+
+ def initialize(top_left, bottom_right)
+ @top_left = top_left
+ @bottom_right = bottom_right
+ end
+
+ def top_right
+ Point.new bottom_right.x, top_left.y
+ end
+
+ def bottom_left
+ Point.new top_left.x, bottom_right.y
+ end
+
+ def left
+ @top_left
+ end
+
+ def right
+ @top_right
+ end
+
+ def points
+ [(Line.new top_left, top_right).points,
+ (Line.new top_left, bottom_left).points,
+ (Line.new top_right, bottom_right).points,
+ (Line.new bottom_left, bottom_right).points].flatten
+ end
+
+ def ==(rectangle)
+ top_left == rectangle.top_left and bottom_right == rectangle.bottom_right
+ end
+
+ def eql?(rectangle)
+ self.== rectangle
+ end
+ end
+end
+
+#canvas = Graphics::Canvas.new 5, 5
+
+#canvas.set_pixel(0, 0)
+#canvas.set_pixel(1, 1)
+#canvas.set_pixel(2, 1)
+#canvas.set_pixel(3, 0)
+
+#canvas.draw Graphics::Point.new 4, 0
+
+
+#a = Graphics::Renderers::Ascii
+#p a.symbols
+
+#point_1 = Graphics::Point.new 3, 3#2,1#1, 4#2, 4#1, 4
+#point_2 = Graphics::Point.new 1, 1#2,4#12, 9#4, 4#12, 9
+
+#p point_2.eql? point_1
+
+#neka_a_e_liniqta = Graphics::Line.new point_1, point_2
+#p neka_a_e_liniqta.points.size
+#canvas.draw(neka_a_e_liniqta)
+
+#puts canvas.render_as(Graphics::Renderers::Ascii)
+
+
+#a = Graphics::Renderers::Ascii.new
+#p a.symbols
+
+canvas = Graphics::Canvas.new 30, 30
+
+# Door frame and window
+canvas.draw Graphics::Rectangle.new(Graphics::Point.new(3, 3), Graphics::Point.new(1, 1))
+canvas.draw Graphics::Rectangle.new(Graphics::Point.new(1, 1), Graphics::Point.new(2, 2))
+
+# Door knob
+canvas.draw Graphics::Line.new(Graphics::Point.new(4, 15), Graphics::Point.new(7, 15))
+canvas.draw Graphics::Point.new(4, 16)
+
+# Big "R"
+canvas.draw Graphics::Line.new(Graphics::Point.new(8, 5), Graphics::Point.new(8, 10))
+canvas.draw Graphics::Line.new(Graphics::Point.new(9, 5), Graphics::Point.new(12, 5))
+canvas.draw Graphics::Line.new(Graphics::Point.new(9, 7), Graphics::Point.new(12, 7))
+canvas.draw Graphics::Point.new(13, 6)
+canvas.draw Graphics::Line.new(Graphics::Point.new(12, 8), Graphics::Point.new(13, 10))
+
+puts canvas.render_as(Graphics::Renderers::Html)
+
+ #a = Graphics::Renderers::Ascii
+ #p a

Стефан обнови решението на 17.12.2013 03:40 (преди над 10 години)

- html_top = "<!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_end = "</div>
- </body>
- </html>"
-
module Graphics
class Renderers
class Ascii
def initialize(canvas)
@canvas = canvas
end
def render
output = ""
@canvas.pixels.each_index do |index|
output << (@canvas.pixels[index] == true ? "@" : "-")
- output << "\n" if ((index + 1).remainder (@canvas.height)) == 0
+ output << "\n" if ((index + 1).remainder (@canvas.width)) == 0
end
output
end
end
class Html
def initialize(canvas)
@canvas = canvas
- @code = ["<!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\">", " </div>
- </body>
-</html>"]
+ @html_code = ["
+ <!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\">",
+ "
+ </div>
+ </body>
+ </html>"]
end
def render
- output = @code[0]
+ output = @html_code[0]
@canvas.pixels.each_index do |index|
output << (@canvas.pixels[index] == true ? "<b></b>" : "<i></i>")
- output << "<br/>\n" if ((index + 1).remainder (@canvas.height)) == 0
+ output << "<br/>\n" if ((index + 1).remainder (@canvas.width)) == 0
end
- output << @code[1]
+ output << @html_code[1]
end
end
end
class Canvas
attr_reader :width, :height, :pixels
def initialize(width, height)
@width = width
@height = height
@pixels = []
(width * height).times { @pixels << false }
end
def set_pixel(x, y)
- @pixels[x + height * y] = true
+ @pixels[x + width * y] = true
end
def pixel_at?(x, y)
- @pixels[x + height * y] == true
+ @pixels[x + width * y] == true
end
def draw(shape)
shape.points.each do |point|
set_pixel point.x, point.y
end
end
- def render_as(symbols)
- (symbols.new self).render
+ def render_as(renderer)
+ (renderer.new self).render
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def points
[(Point.new x, y)]
end
def ==(other_point)
x == other_point.x and y == other_point.y
end
def eql?(other_point)
self.== other_point
end
end
class Line
attr_reader :from, :to
def initialize(from, to)
@from = from
@to = to
end
def points(left = from, right = to, result = [left, right])
return result if (left.x - right.x).abs <= 1 and (left.y - right.y).abs <= 1
result << (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2)
points(left, (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), result)
points((Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), right, result)
end
def ==(other_line)
from == other_point.from and to == other_point.to
end
def eql?(other_line)
self.== other_point
end
end
class Rectangle
attr_reader :top_left, :bottom_right
def initialize(top_left, bottom_right)
@top_left = top_left
@bottom_right = bottom_right
end
def top_right
Point.new bottom_right.x, top_left.y
end
def bottom_left
Point.new top_left.x, bottom_right.y
end
def left
- @top_left
+ Point.new top_left.x, top_left.y < bottom_left.y ? top_left.y : bottom_left.y
end
def right
- @top_right
+ Point.new bottom_right.x, left.y + (bottom_right.y - top_right.y).abs
end
def points
[(Line.new top_left, top_right).points,
(Line.new top_left, bottom_left).points,
(Line.new top_right, bottom_right).points,
(Line.new bottom_left, bottom_right).points].flatten
end
def ==(rectangle)
top_left == rectangle.top_left and bottom_right == rectangle.bottom_right
end
def eql?(rectangle)
self.== rectangle
end
end
-end
-
+end
-#canvas = Graphics::Canvas.new 5, 5
-
-#canvas.set_pixel(0, 0)
-#canvas.set_pixel(1, 1)
-#canvas.set_pixel(2, 1)
-#canvas.set_pixel(3, 0)
-
-#canvas.draw Graphics::Point.new 4, 0
-
-
-#a = Graphics::Renderers::Ascii
-#p a.symbols
-
-#point_1 = Graphics::Point.new 3, 3#2,1#1, 4#2, 4#1, 4
-#point_2 = Graphics::Point.new 1, 1#2,4#12, 9#4, 4#12, 9
-
-#p point_2.eql? point_1
-
-#neka_a_e_liniqta = Graphics::Line.new point_1, point_2
-#p neka_a_e_liniqta.points.size
-#canvas.draw(neka_a_e_liniqta)
-
-#puts canvas.render_as(Graphics::Renderers::Ascii)
-
-
-#a = Graphics::Renderers::Ascii.new
-#p a.symbols
-
-canvas = Graphics::Canvas.new 30, 30
-
-# Door frame and window
-canvas.draw Graphics::Rectangle.new(Graphics::Point.new(3, 3), Graphics::Point.new(1, 1))
-canvas.draw Graphics::Rectangle.new(Graphics::Point.new(1, 1), Graphics::Point.new(2, 2))
-
-# Door knob
-canvas.draw Graphics::Line.new(Graphics::Point.new(4, 15), Graphics::Point.new(7, 15))
-canvas.draw Graphics::Point.new(4, 16)
-
-# Big "R"
-canvas.draw Graphics::Line.new(Graphics::Point.new(8, 5), Graphics::Point.new(8, 10))
-canvas.draw Graphics::Line.new(Graphics::Point.new(9, 5), Graphics::Point.new(12, 5))
-canvas.draw Graphics::Line.new(Graphics::Point.new(9, 7), Graphics::Point.new(12, 7))
-canvas.draw Graphics::Point.new(13, 6)
-canvas.draw Graphics::Line.new(Graphics::Point.new(12, 8), Graphics::Point.new(13, 10))
-
-puts canvas.render_as(Graphics::Renderers::Html)
-
- #a = Graphics::Renderers::Ascii
- #p a

Стефан обнови решението на 17.12.2013 04:52 (преди над 10 години)

module Graphics
class Renderers
class Ascii
def initialize(canvas)
@canvas = canvas
end
def render
output = ""
@canvas.pixels.each_index do |index|
output << (@canvas.pixels[index] == true ? "@" : "-")
output << "\n" if ((index + 1).remainder (@canvas.width)) == 0
end
- output
+ output.chomp
end
end
class Html
def initialize(canvas)
@canvas = canvas
@html_code = ["
<!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\">",
"
</div>
</body>
</html>"]
end
def render
output = @html_code[0]
@canvas.pixels.each_index do |index|
output << (@canvas.pixels[index] == true ? "<b></b>" : "<i></i>")
- output << "<br/>\n" if ((index + 1).remainder (@canvas.width)) == 0
+ output << "<br>\n" if ((index + 1).remainder (@canvas.width)) == 0
end
- output << @html_code[1]
+ output.chomp.chop.chop.chop.chop << @html_code[1]
end
end
end
class Canvas
attr_reader :width, :height, :pixels
def initialize(width, height)
@width = width
@height = height
@pixels = []
(width * height).times { @pixels << false }
end
def set_pixel(x, y)
@pixels[x + width * y] = true
end
def pixel_at?(x, y)
@pixels[x + width * y] == true
end
def draw(shape)
shape.points.each do |point|
set_pixel point.x, point.y
end
end
def render_as(renderer)
(renderer.new self).render
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def points
[(Point.new x, y)]
end
def ==(other_point)
x == other_point.x and y == other_point.y
end
def eql?(other_point)
self.== other_point
end
end
class Line
- attr_reader :from, :to
-
def initialize(from, to)
@from = from
@to = to
end
+ def from
+ Point.new @from.x <= @to.x ? @from.x : @to.x,
+ @from.x <= @to.x ? @from.y : @to.y
+ end
+
+ def to
+ Point.new @from.x > @to.x ? @from.x : @to.x,
+ @from.x > @to.x ? @from.y : @to.y
+ end
+
def points(left = from, right = to, result = [left, right])
return result if (left.x - right.x).abs <= 1 and (left.y - right.y).abs <= 1
result << (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2)
points(left, (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), result)
points((Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), right, result)
end
def ==(other_line)
from == other_point.from and to == other_point.to
end
def eql?(other_line)
self.== other_point
end
end
class Rectangle
- attr_reader :top_left, :bottom_right
-
def initialize(top_left, bottom_right)
@top_left = top_left
@bottom_right = bottom_right
end
+ def top_left
+ left
+ end
+
+ def bottom_right
+ right
+ end
+
def top_right
Point.new bottom_right.x, top_left.y
end
def bottom_left
Point.new top_left.x, bottom_right.y
end
def left
- Point.new top_left.x, top_left.y < bottom_left.y ? top_left.y : bottom_left.y
+ Point.new @top_left.x < @bottom_right.x ? @top_left.x : @bottom_right.x,
+ @top_left.y < @bottom_right.y ? @top_left.y : @bottom_right.y
end
def right
- Point.new bottom_right.x, left.y + (bottom_right.y - top_right.y).abs
+ Point.new @top_left.x > @bottom_right.x ? @top_left.x : @bottom_right.x,
+ @top_left.y > @bottom_right.y ? @top_left.y : @bottom_right.y
end
def points
[(Line.new top_left, top_right).points,
(Line.new top_left, bottom_left).points,
(Line.new top_right, bottom_right).points,
(Line.new bottom_left, bottom_right).points].flatten
end
def ==(rectangle)
top_left == rectangle.top_left and bottom_right == rectangle.bottom_right
end
def eql?(rectangle)
self.== rectangle
end
end
end

Стефан обнови решението на 17.12.2013 04:57 (преди над 10 години)

module Graphics
class Renderers
class Ascii
def initialize(canvas)
@canvas = canvas
end
def render
output = ""
@canvas.pixels.each_index do |index|
output << (@canvas.pixels[index] == true ? "@" : "-")
output << "\n" if ((index + 1).remainder (@canvas.width)) == 0
end
output.chomp
end
end
class Html
-
def initialize(canvas)
@canvas = canvas
@html_code = ["
<!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\">",
"
</div>
</body>
</html>"]
end
def render
output = @html_code[0]
@canvas.pixels.each_index do |index|
output << (@canvas.pixels[index] == true ? "<b></b>" : "<i></i>")
output << "<br>\n" if ((index + 1).remainder (@canvas.width)) == 0
end
output.chomp.chop.chop.chop.chop << @html_code[1]
end
end
end
class Canvas
attr_reader :width, :height, :pixels
def initialize(width, height)
@width = width
@height = height
@pixels = []
(width * height).times { @pixels << false }
end
def set_pixel(x, y)
@pixels[x + width * y] = true
end
def pixel_at?(x, y)
@pixels[x + width * y] == true
end
def draw(shape)
shape.points.each do |point|
set_pixel point.x, point.y
end
end
def render_as(renderer)
(renderer.new self).render
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def points
[(Point.new x, y)]
end
def ==(other_point)
x == other_point.x and y == other_point.y
end
def eql?(other_point)
self.== other_point
end
end
class Line
def initialize(from, to)
@from = from
@to = to
end
def from
- Point.new @from.x <= @to.x ? @from.x : @to.x,
- @from.x <= @to.x ? @from.y : @to.y
+ Point.new @from.x <= @to.x ? @from.x : @to.x, @from.x <= @to.x ? @from.y : @to.y
end
def to
- Point.new @from.x > @to.x ? @from.x : @to.x,
- @from.x > @to.x ? @from.y : @to.y
+ Point.new @from.x > @to.x ? @from.x : @to.x, @from.x > @to.x ? @from.y : @to.y
end
def points(left = from, right = to, result = [left, right])
return result if (left.x - right.x).abs <= 1 and (left.y - right.y).abs <= 1
result << (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2)
points(left, (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), result)
points((Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), right, result)
end
def ==(other_line)
from == other_point.from and to == other_point.to
end
def eql?(other_line)
self.== other_point
end
end
class Rectangle
def initialize(top_left, bottom_right)
@top_left = top_left
@bottom_right = bottom_right
end
def top_left
left
end
def bottom_right
right
end
def top_right
Point.new bottom_right.x, top_left.y
end
def bottom_left
Point.new top_left.x, bottom_right.y
end
def left
Point.new @top_left.x < @bottom_right.x ? @top_left.x : @bottom_right.x,
@top_left.y < @bottom_right.y ? @top_left.y : @bottom_right.y
end
def right
Point.new @top_left.x > @bottom_right.x ? @top_left.x : @bottom_right.x,
@top_left.y > @bottom_right.y ? @top_left.y : @bottom_right.y
end
def points
[(Line.new top_left, top_right).points,
(Line.new top_left, bottom_left).points,
(Line.new top_right, bottom_right).points,
(Line.new bottom_left, bottom_right).points].flatten
end
def ==(rectangle)
top_left == rectangle.top_left and bottom_right == rectangle.bottom_right
end
def eql?(rectangle)
self.== rectangle
end
end
end

Бележки:

  • Празен ред се оставя м/у дефиниции на методи (напр. м/у ред 6 и 7).
  • Защо не пробваш как ще стане Ascii#render с map & join?
  • Изведи този дълъг текст @html_code в константа в Html. Препоръчвам ти да го дефинираш с единични кавички (няма проблем да има multiline низ в тях).
  • Пак за този HTML код, може да го направиш и без списък. Помисли как. Ще стане по-готино.
  • Методът pixel_at? не е нужно да връща false, ако няма пиксел на съответнотно място; може и да връща нещо, което се оценява на false.
  • Бих подравнил равенствата на ред 66-68.
  • Едноизмерен масив е интересна имплементация, но ми напомня на C код :) Виж дали няма да ти хрумне друга идея за вътрешно представяне на пано.
  • Canvas#draw – големият въпрос е shape.points или canvas.set_pixel? :) Тоест, дали паното ще ползва някакъв публичен интерфейс от фигурата, или фигурата ще ползва такъв на паното. Интересен въпрос. Просто коментар е това.
  • Ред 87 се записва така: renderer.new(self).render; аналогично и за ред 100
  • Нямаш нужда от точката на ред 108; може да е само self == other_point; но най-добре го направи със синоними на методи. Същото важи и за ред 138.
  • Line#from и #to изглеждат ужасно. REFACTOR!
  • Защо има възможност да се подават аргументи на Line#points? Не виждам някъде да се ползва, следователно е излишно, следователно трябва да се махне. Този метод също изглежда зле – неподредено и неясно.
  • Виждам, че обичаш ternary оператора. Разлюби го, изглежда грозно и недостатъчно ясно в този контекст. Само за много прости изрази се ползва.

И, хайде, малко подсказки:

  • Не виждам да си имлементирал hash.
  • Какво ще стане, ако дефинирам Rectangle.new Point.new(1, 5), Point.new(7, 2)? Това е валидна дефиниция по условие. Виж дали ще работи правилно при теб.

Иначе, решението ти е доста прилично. Поздравления :)

Стефан обнови решението на 18.12.2013 14:14 (преди над 10 години)

module Graphics
class Renderers
class Ascii
def initialize(canvas)
@canvas = canvas
end
+
def render
output = ""
@canvas.pixels.each_index do |index|
- output << (@canvas.pixels[index] == true ? "@" : "-")
+ output << (@canvas.pixels[index] ? "@" : "-")
output << "\n" if ((index + 1).remainder (@canvas.width)) == 0
end
output.chomp
end
end
class Html
def initialize(canvas)
@canvas = canvas
- @html_code = ["
+ @html_code = ['
<!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">',
+ '
</div>
</body>
- </html>"]
+ </html>']
end
+
def render
output = @html_code[0]
@canvas.pixels.each_index do |index|
- output << (@canvas.pixels[index] == true ? "<b></b>" : "<i></i>")
+ output << (@canvas.pixels[index] ? "<b></b>" : "<i></i>")
output << "<br>\n" if ((index + 1).remainder (@canvas.width)) == 0
end
output.chomp.chop.chop.chop.chop << @html_code[1]
end
end
end
class Canvas
attr_reader :width, :height, :pixels
def initialize(width, height)
- @width = width
+ @width = width
@height = height
@pixels = []
(width * height).times { @pixels << false }
end
def set_pixel(x, y)
@pixels[x + width * y] = true
end
def pixel_at?(x, y)
- @pixels[x + width * y] == true
+ @pixels[x + width * y]
end
def draw(shape)
shape.points.each do |point|
set_pixel point.x, point.y
end
end
def render_as(renderer)
- (renderer.new self).render
+ renderer.new(self).render
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def points
- [(Point.new x, y)]
+ [Point.new(x, y)]
end
def ==(other_point)
x == other_point.x and y == other_point.y
end
def eql?(other_point)
- self.== other_point
+ self == other_point
end
+
+ def hash
+ x.hash % y.hash
+ end
end
class Line
def initialize(from, to)
@from = from
@to = to
end
def from
- Point.new @from.x <= @to.x ? @from.x : @to.x, @from.x <= @to.x ? @from.y : @to.y
+ Point.new @from.x <= @to.x ? @from.x : @to.x,
+ @from.x <= @to.x ? @from.y : @to.y
end
def to
- Point.new @from.x > @to.x ? @from.x : @to.x, @from.x > @to.x ? @from.y : @to.y
+ Point.new @from.x > @to.x ? @from.x : @to.x,
+ @from.x > @to.x ? @from.y : @to.y
end
def points(left = from, right = to, result = [left, right])
return result if (left.x - right.x).abs <= 1 and (left.y - right.y).abs <= 1
- result << (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2)
- points(left, (Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), result)
- points((Point.new (left.x + right.x) / 2, (left.y + right.y) / 2), right, result)
+ result << Point.new((left.x + right.x) / 2, (left.y + right.y) / 2)
+ points left, Point.new((left.x + right.x) / 2, (left.y + right.y) / 2), result
+ points Point.new((left.x + right.x) / 2, (left.y + right.y) / 2), right, result
end
def ==(other_line)
- from == other_point.from and to == other_point.to
+ from == other_line.from and to == other_line.to
end
def eql?(other_line)
- self.== other_point
+ self == other_line
end
+
+ def hash
+ from.hash + to.hash
+ end
end
class Rectangle
def initialize(top_left, bottom_right)
@top_left = top_left
@bottom_right = bottom_right
end
def top_left
left
end
def bottom_right
right
end
def top_right
Point.new bottom_right.x, top_left.y
end
def bottom_left
Point.new top_left.x, bottom_right.y
end
def left
Point.new @top_left.x < @bottom_right.x ? @top_left.x : @bottom_right.x,
@top_left.y < @bottom_right.y ? @top_left.y : @bottom_right.y
end
def right
Point.new @top_left.x > @bottom_right.x ? @top_left.x : @bottom_right.x,
@top_left.y > @bottom_right.y ? @top_left.y : @bottom_right.y
end
def points
[(Line.new top_left, top_right).points,
(Line.new top_left, bottom_left).points,
(Line.new top_right, bottom_right).points,
(Line.new bottom_left, bottom_right).points].flatten
end
def ==(rectangle)
top_left == rectangle.top_left and bottom_right == rectangle.bottom_right
end
def eql?(rectangle)
- self.== rectangle
+ self == rectangle
+ end
+
+ def hash
+ top_left.hash + top_right.hash + bottom_right.hash + bottom_left.hash
end
end
end
 Към Димитър. Благодаря за подсказката с hash... Тотално я бях забравил. Оправих повечето от нещата, някои не можах да преборя.
 Относно това което сте написал:
  • Защо има възможност да се подават аргументи на Line#points? Не виждам някъде да се ползва, следователно е излишно, следователно трябва да се махне. Този метод също изглежда зле – неподредено и неясно.

    Използвам функцията рекурсивно и не виждам друг начин освен да я викам с аргументи в тялото й.

 Така ли ми се стори или като пиша много текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст ви се бъгва нещо поленцето за текст и текста ми отива върху снимката ми. Използвам Firefox.
 Може да сте го видяли че се бъгва, но понеже казахте да се оплакваме и да ви даваме градивна критика ви давам сега.
 Използвам Firefox

Благодаря за бъг репорта, оправено е :) Такива неща най-добре е да ги докладваш в issue tracker-а в хранилището на проекта на сайта.

В отговор на въпроса ти, понеже Line#pointsе част от твоя публичен интерфейс на обекта Line, не е добре да приема аргументи. Намери начин да го направиш без :) Ако беше private метод, няма проблем, но за public методи това не е добра идея.

Виждам, че си адресирал някои, но не всички от моите бележки. Просто ти напомням :) Все още имаш време.

Бележки:

  • Пробвай да ползваш map и join в render метода на рендерерите, вместо да градиш низове така.
  • Удачно е HTML кодът да се изведе в константа/и в класа Html. Също така, недостатъчно ясно ми е като е в променлива html_code, която на всичкото отгоре е списък. По-ясно би било, например, да има "html header" и "html footer".
  • Имаш малко дублираща се логика в двата рендерера, свързана с обхождането на пикселите на паното. Ако смениш вътрешното представяне на пано, ще трябва да промениш и тези два метода, а това не е добре. Опитай да ползваш нещо, което не зависи от това вътрешно представяне.
  • output.chomp.chop.chop.chop.chop << @html_code[1]?! Това със сигурност трябва да се рефакторира. Ако ползваш map и join няма да трябва да го правиш, но дори и да не беше така, можеше поне да ползваш String#slice.
  • Внимавай с мутацията в рендерерите.
  • Помисли дали няма друг по-оптимален начин в Ruby за реализация вътрешното представяне на пано от двумерен масив. Ruby не е C и има по-удобни структури от данни :)
  • Също така, pixel_at? може да връща нещо, което се оценява като истина или лъжа; не е задължително да е true/false.
  • Ред 102: защо не просто [self]?
  • Може да ползваш синоними на методи, за да реализираш eql?.
  • Хм, сигурен ли си, че имплементациите ти на hash ще работят?
  • Line#points изглежда кофти. Много наблъскано и нечетимо. Освен това, методът points е част от публичния интерфейс на Line, а приема някакви аргументи, на които не им е там мястото. Намери начин да го рефакторираш.
  • Обърква ме кодът с точките на правоъгълника. По условие, правоъгълник може да се конструира и от bottom_left, top_right. Следователно, имената на променливите в конструктора са подвеждащи. Оттам и другите методи надолу.

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