Решение на Трета задача от Александър Попов

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

Към профила на Александър Попов

Резултати

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

Код

module Graphics
class Canvas
attr_reader :width, :height
attr_accessor :canvas
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width) }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x]
end
def draw(figure)
figure.path.each { |coordinate| set_pixel coordinate[0], coordinate[1] }
end
def render_as(renderer)
renderer.render(self)
end
end
module Renderers
module Ascii
def self.render(canvas)
canvas.canvas.map { |row| Renderers.process_row(row, '@', '-') }.join("\n")
end
end
module Html
HEADER = <<-EOS
<!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">
EOS
FOOTER = <<-EOS
</div>
</body>
</html>
EOS
def self.render(canvas)
HEADER +
canvas.canvas.map { |row| Renderers.process_row(row, '<b></b>', '<i></i>') }
.join("<br>\n") +
FOOTER
end
end
private
def self.fill_pixel(pixel, color, transparent)
pixel ? color : transparent
end
def self.process_row(row, color, transparent)
row.map { |pixel| Renderers.fill_pixel(pixel, color, transparent) }.join
end
end
class Point
include Graphics
attr_reader :x, :y, :path
def initialize(x, y)
@x = x
@y = y
@path = [[@x, @y]]
end
end
class Line
include Graphics
attr_reader :from, :to, :path
def initialize(from, to)
@from, @to = from, to
@delta_x, @delta_y = (@to.x - @from.x).abs, -(@to.y - @from.y).abs
@step_x, @step_y = (@from.x < @to.x ? 1 : -1), (@from.y < @to.y ? 1 : -1)
@err, @x, @y = @delta_x + @delta_y, @from.x, @from.y
@path = [[@x, @y]]
set_path
end
private
def set_path
begin
@error_2 = 2 * @err
correct_x
correct_y
@path << [@x, @y]
end until (@x == @to.x && @y == @to.y)
end
def correct_x
if @error_2 >= @delta_y
@err += @delta_y
@x += @step_x
end
end
def correct_y
if @error_2 <= @delta_x
@err += @delta_x
@y += @step_y
end
end
end
class Rectangle
include Graphics
attr_reader :left, :right, :top_left, :top_right,
:bottom_left, :bottom_right, :path
def initialize(first, second)
@min_x, @max_x = [first.x, second.x].min, [first.x, second.x].max
@min_y, @max_y = [first.y, second.y].min, [first.y, second.y].max
set_corners
set_path
end
private
def set_corners
@top_left = @left = Point.new @min_x, @min_y
@top_right = Point.new @max_x, @min_y
@bottom_left = Point.new @min_x, @max_y
@bottom_right = @right = Point.new @max_x, @max_y
end
def set_path
@path = Line.new(@top_left, @top_right).path +
Line.new(@top_right, @bottom_right).path +
Line.new(@bottom_right, @bottom_left).path +
Line.new(@top_left, @bottom_left).path
end
end
def eql?(other)
path == other.path
end
alias :== :eql?
def hash
@path.hash
end
end

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

..........F.....F..FF....................FFFF..FF.F.....F............

Failures:

  1) 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-yk2x4g/solution.rb:13:in `set_pixel'
     # /tmp/d20131223-4637-yk2x4g/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)>'

  2) Graphics Canvas drawing of shapes and rasterization of lines draws lines with two equal ends as points
     Failure/Error: Graphics::Line.new(*args)
     Timeout::Error:
       execution expired
     # /tmp/d20131223-4637-yk2x4g/solution.rb:122:in `set_path'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:111:in `initialize'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:611:in `new'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:611:in `make_line'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:143: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 rectangles works with rects with a zero height as a line
     Failure/Error: Graphics::Rectangle.new(*args)
     Timeout::Error:
       execution expired
     # /tmp/d20131223-4637-yk2x4g/solution.rb:133:in `correct_y'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:120:in `set_path'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:111:in `initialize'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:163:in `new'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:163:in `set_path'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:149:in `initialize'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:615:in `new'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:615:in `make_rectangle'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:182: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 rectangles works with rects with a zero width and height as a single point
     Failure/Error: Graphics::Rectangle.new(*args)
     Timeout::Error:
       execution expired
     # /tmp/d20131223-4637-yk2x4g/solution.rb:133:in `correct_y'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:120:in `set_path'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:111:in `initialize'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:162:in `new'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:162:in `set_path'
     # /tmp/d20131223-4637-yk2x4g/solution.rb:149:in `initialize'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:615:in `new'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:615:in `make_rectangle'
     # /tmp/d20131223-4637-yk2x4g/spec.rb:193: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-yk2x4g/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-yk2x4g/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-yk2x4g/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-yk2x4g/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-yk2x4g/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-yk2x4g/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 Line comparison for equality returns the same hash if the lines are the same
     Failure/Error: a.hash.should eq b.hash
       
       expected: 65896175
            got: -82766305
       
       (compared using ==)
     # /tmp/d20131223-4637-yk2x4g/spec.rb:465: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 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-yk2x4g/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 3.37 seconds
69 examples, 12 failures

Failed examples:

rspec /tmp/d20131223-4637-yk2x4g/spec.rb:51 # Graphics Canvas drawing of shapes and rasterization of points works for multiple ones
rspec /tmp/d20131223-4637-yk2x4g/spec.rb:141 # Graphics Canvas drawing of shapes and rasterization of lines draws lines with two equal ends as points
rspec /tmp/d20131223-4637-yk2x4g/spec.rb:180 # Graphics Canvas drawing of shapes and rasterization of rectangles works with rects with a zero height as a line
rspec /tmp/d20131223-4637-yk2x4g/spec.rb:191 # Graphics Canvas drawing of shapes and rasterization of rectangles works with rects with a zero width and height as a single point
rspec /tmp/d20131223-4637-yk2x4g/spec.rb:401 # Graphics shapes Line initialization with swapped points puts the leftmost point in the from field
rspec /tmp/d20131223-4637-yk2x4g/spec.rb:406 # Graphics shapes Line initialization with swapped points puts the rightmost point in the to field
rspec /tmp/d20131223-4637-yk2x4g/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-yk2x4g/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-yk2x4g/spec.rb:438 # Graphics shapes Line comparison for equality is true if line ends are the same, even if swapped
rspec /tmp/d20131223-4637-yk2x4g/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-yk2x4g/spec.rb:461 # Graphics shapes Line comparison for equality returns the same hash if the lines are the same
rspec /tmp/d20131223-4637-yk2x4g/spec.rb:504 # Graphics shapes Rectangle initialization puts the leftmost point in its left field

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

Александър обнови решението на 17.12.2013 12:25 (преди почти 11 години)

+module Graphics
+ class Canvas
+ attr_reader :width, :height
+ attr_accessor :canvas
+
+ def initialize(width, height)
+ @width = width
+ @height = height
+ @canvas = Array.new(height) { Array.new(width) }
+ end
+
+ def set_pixel(x, y)
+ @canvas[y][x] = true
+ end
+
+ def pixel_at?(x, y)
+ @canvas[y][x]
+ end
+
+ def draw(figure)
+ if figure.class == Point
+ set_pixel figure.x, figure.y
+ else
+ figure.path.each { |coordinate| set_pixel coordinate[0], coordinate[1] }
+ end
+ end
+
+ def render_as(renderer)
+ renderer.render(self)
+ end
+ end
+
+ module Renderers
+ module Ascii
+ def self.render(canvas)
+ canvas.canvas.map { |row| row.map { |pixel| fill_pixel(pixel) }.join }.join("\n")
+ end
+
+ def self.fill_pixel(pixel)
+ pixel ? '@' : '-'
+ end
+ end
+
+ module Html
+ HEADER = <<-EOS
+ <!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">
+ EOS
+
+ FOOTER = <<-EOS
+ </div>
+ </body>
+ </html>
+ EOS
+
+ def self.render(canvas)
+ HEADER +
+ canvas.canvas.map { |row| row.map { |pixel| fill_pixel(pixel) }.join }
+ .join("<br>\n") +
+ FOOTER
+ end
+
+ def self.fill_pixel(pixel)
+ pixel ? '<b></b>' : '<i></i>'
+ end
+ end
+ end
+
+ class Point
+ attr_reader :x, :y
+
+ def initialize(x, y)
+ @x = x
+ @y = y
+ end
+
+ def eql?(other)
+ x == other.x and y == other.y
+ end
+
+ alias :== :eql?
+ end
+
+ class Line
+ attr_reader :from, :to, :path
+
+ def initialize(from, to)
+ @from, @to = from, to
+ @delta_x, @delta_y = (@to.x - @from.x).abs, -(@to.y - @from.y).abs
+ @step_x, @step_y = (@from.x < @to.x ? 1 : -1), (@from.y < @to.y ? 1 : -1)
+ @err, @x, @y = @delta_x + @delta_y, @from.x, @from.y
+ @path = Set.new [[@x, @y]]
+ set_path
+ end
+
+ def set_path
+ begin
+ @error_2 = 2 * @err
+ correct_x
+ correct_y
+ @path << [@x, @y]
+ end until (@x == @to.x && @y == @to.y)
+ end
+
+ def correct_x
+ if @error_2 >= @delta_y
+ @err += @delta_y
+ @x += @step_x
+ end
+ end
+
+ def correct_y
+ if @error_2 <= @delta_x
+ @err += @delta_x
+ @y += @step_y
+ end
+ end
+
+ def eql?(other)
+ from == other.from and to == other.to
+ end
+
+ alias :== :eql?
+
+ private :set_path, :correct_x, :correct_y
+ end
+
+ class Rectangle
+ attr_reader :left, :right, :top_left, :top_right,
+ :bottom_left, :bottom_right, :path
+
+ def initialize(first, second)
+ @min_x, @max_x = [first.x, second.x].min, [first.x, second.x].max
+ @min_y, @max_y = [first.y, second.y].min, [first.y, second.y].max
+ set_corners
+ set_path
+ end
+
+ def set_corners
+ @top_left = @left = Point.new @min_x, @min_y
+ @top_right = Point.new @max_x, @min_y
+ @bottom_left = Point.new @min_x, @max_y
+ @bottom_right = @right = Point.new @max_x, @max_y
+ end
+
+ def set_path
+ @path = Line.new(@top_left, @top_right).path +
+ Line.new(@top_right, @bottom_right).path +
+ Line.new(@bottom_right, @bottom_left).path +
+ Line.new(@top_left, @bottom_left).path
+ end
+
+ def eql?(other)
+ left == other.left and right == other.right
+ end
+
+ alias :== :eql?
+ end
+end

Александър обнови решението на 17.12.2013 13:01 (преди почти 11 години)

+require 'set'
+
module Graphics
class Canvas
attr_reader :width, :height
attr_accessor :canvas
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width) }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x]
end
def draw(figure)
if figure.class == Point
set_pixel figure.x, figure.y
else
figure.path.each { |coordinate| set_pixel coordinate[0], coordinate[1] }
end
end
def render_as(renderer)
renderer.render(self)
end
end
module Renderers
module Ascii
def self.render(canvas)
canvas.canvas.map { |row| row.map { |pixel| fill_pixel(pixel) }.join }.join("\n")
end
def self.fill_pixel(pixel)
pixel ? '@' : '-'
end
end
module Html
HEADER = <<-EOS
<!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">
EOS
FOOTER = <<-EOS
</div>
</body>
</html>
EOS
def self.render(canvas)
HEADER +
canvas.canvas.map { |row| row.map { |pixel| fill_pixel(pixel) }.join }
.join("<br>\n") +
FOOTER
end
def self.fill_pixel(pixel)
pixel ? '<b></b>' : '<i></i>'
end
end
end
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def eql?(other)
x == other.x and y == other.y
end
alias :== :eql?
end
class Line
attr_reader :from, :to, :path
def initialize(from, to)
@from, @to = from, to
@delta_x, @delta_y = (@to.x - @from.x).abs, -(@to.y - @from.y).abs
@step_x, @step_y = (@from.x < @to.x ? 1 : -1), (@from.y < @to.y ? 1 : -1)
@err, @x, @y = @delta_x + @delta_y, @from.x, @from.y
@path = Set.new [[@x, @y]]
set_path
end
def set_path
begin
@error_2 = 2 * @err
correct_x
correct_y
@path << [@x, @y]
end until (@x == @to.x && @y == @to.y)
end
def correct_x
if @error_2 >= @delta_y
@err += @delta_y
@x += @step_x
end
end
def correct_y
if @error_2 <= @delta_x
@err += @delta_x
@y += @step_y
end
end
def eql?(other)
from == other.from and to == other.to
end
alias :== :eql?
private :set_path, :correct_x, :correct_y
end
class Rectangle
attr_reader :left, :right, :top_left, :top_right,
:bottom_left, :bottom_right, :path
def initialize(first, second)
@min_x, @max_x = [first.x, second.x].min, [first.x, second.x].max
@min_y, @max_y = [first.y, second.y].min, [first.y, second.y].max
set_corners
set_path
end
def set_corners
@top_left = @left = Point.new @min_x, @min_y
@top_right = Point.new @max_x, @min_y
@bottom_left = Point.new @min_x, @max_y
@bottom_right = @right = Point.new @max_x, @max_y
end
def set_path
@path = Line.new(@top_left, @top_right).path +
Line.new(@top_right, @bottom_right).path +
Line.new(@bottom_right, @bottom_left).path +
Line.new(@top_left, @bottom_left).path
end
def eql?(other)
left == other.left and right == other.right
end
alias :== :eql?
end
end

Александър обнови решението на 17.12.2013 15:00 (преди почти 11 години)

require 'set'
module Graphics
class Canvas
attr_reader :width, :height
attr_accessor :canvas
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width) }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x]
end
def draw(figure)
- if figure.class == Point
- set_pixel figure.x, figure.y
- else
- figure.path.each { |coordinate| set_pixel coordinate[0], coordinate[1] }
- end
+ figure.path.each { |coordinate| set_pixel coordinate[0], coordinate[1] }
end
def render_as(renderer)
renderer.render(self)
end
end
module Renderers
module Ascii
def self.render(canvas)
- canvas.canvas.map { |row| row.map { |pixel| fill_pixel(pixel) }.join }.join("\n")
+ canvas.canvas.map { |row| Renderers.process_row(row, '@', '-') }.join("\n")
end
-
- def self.fill_pixel(pixel)
- pixel ? '@' : '-'
- end
end
module Html
HEADER = <<-EOS
<!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">
EOS
FOOTER = <<-EOS
</div>
</body>
</html>
EOS
def self.render(canvas)
HEADER +
- canvas.canvas.map { |row| row.map { |pixel| fill_pixel(pixel) }.join }
+ canvas.canvas.map { |row| Renderers.process_row(row, '<b></b>', '<i></i>') }
.join("<br>\n") +
FOOTER
end
+ end
- def self.fill_pixel(pixel)
- pixel ? '<b></b>' : '<i></i>'
- end
+ private
+
+ def self.fill_pixel(pixel, color, transparent)
+ pixel ? color : transparent
end
+
+ def self.process_row(row, color, transparent)
+ row.map { |pixel| Renderers.fill_pixel(pixel, color, transparent) }.join
+ end
end
class Point
- attr_reader :x, :y
+ attr_reader :x, :y, :path
def initialize(x, y)
@x = x
@y = y
+ @path = [[@x, @y]]
end
def eql?(other)
x == other.x and y == other.y
end
alias :== :eql?
end
class Line
attr_reader :from, :to, :path
def initialize(from, to)
@from, @to = from, to
@delta_x, @delta_y = (@to.x - @from.x).abs, -(@to.y - @from.y).abs
@step_x, @step_y = (@from.x < @to.x ? 1 : -1), (@from.y < @to.y ? 1 : -1)
@err, @x, @y = @delta_x + @delta_y, @from.x, @from.y
@path = Set.new [[@x, @y]]
set_path
end
+ def eql?(other)
+ from == other.from and to == other.to
+ end
+
+ alias :== :eql?
+
+ private
+
def set_path
begin
@error_2 = 2 * @err
correct_x
correct_y
@path << [@x, @y]
end until (@x == @to.x && @y == @to.y)
end
def correct_x
if @error_2 >= @delta_y
@err += @delta_y
@x += @step_x
end
end
def correct_y
if @error_2 <= @delta_x
@err += @delta_x
@y += @step_y
end
end
-
- def eql?(other)
- from == other.from and to == other.to
- end
-
- alias :== :eql?
-
- private :set_path, :correct_x, :correct_y
end
class Rectangle
attr_reader :left, :right, :top_left, :top_right,
:bottom_left, :bottom_right, :path
def initialize(first, second)
@min_x, @max_x = [first.x, second.x].min, [first.x, second.x].max
@min_y, @max_y = [first.y, second.y].min, [first.y, second.y].max
set_corners
set_path
end
+ def eql?(other)
+ left == other.left and right == other.right
+ end
+
+ alias :== :eql?
+
+ private
+
def set_corners
@top_left = @left = Point.new @min_x, @min_y
@top_right = Point.new @max_x, @min_y
@bottom_left = Point.new @min_x, @max_y
@bottom_right = @right = Point.new @max_x, @max_y
end
def set_path
@path = Line.new(@top_left, @top_right).path +
Line.new(@top_right, @bottom_right).path +
Line.new(@bottom_right, @bottom_left).path +
Line.new(@top_left, @bottom_left).path
end
-
- def eql?(other)
- left == other.left and right == other.right
- end
-
- alias :== :eql?
end
end

Александър обнови решението на 17.12.2013 16:00 (преди почти 11 години)

-require 'set'
-
module Graphics
class Canvas
attr_reader :width, :height
attr_accessor :canvas
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width) }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x]
end
def draw(figure)
figure.path.each { |coordinate| set_pixel coordinate[0], coordinate[1] }
end
def render_as(renderer)
renderer.render(self)
end
end
module Renderers
module Ascii
def self.render(canvas)
canvas.canvas.map { |row| Renderers.process_row(row, '@', '-') }.join("\n")
end
end
module Html
HEADER = <<-EOS
- <!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">
+<!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">
EOS
FOOTER = <<-EOS
- </div>
- </body>
- </html>
+ </div>
+</body>
+</html>
EOS
def self.render(canvas)
HEADER +
canvas.canvas.map { |row| Renderers.process_row(row, '<b></b>', '<i></i>') }
.join("<br>\n") +
FOOTER
end
end
private
def self.fill_pixel(pixel, color, transparent)
pixel ? color : transparent
end
def self.process_row(row, color, transparent)
row.map { |pixel| Renderers.fill_pixel(pixel, color, transparent) }.join
end
end
class Point
+ include Graphics
attr_reader :x, :y, :path
def initialize(x, y)
@x = x
@y = y
@path = [[@x, @y]]
end
-
- def eql?(other)
- x == other.x and y == other.y
- end
-
- alias :== :eql?
end
class Line
+ include Graphics
attr_reader :from, :to, :path
def initialize(from, to)
@from, @to = from, to
@delta_x, @delta_y = (@to.x - @from.x).abs, -(@to.y - @from.y).abs
@step_x, @step_y = (@from.x < @to.x ? 1 : -1), (@from.y < @to.y ? 1 : -1)
@err, @x, @y = @delta_x + @delta_y, @from.x, @from.y
- @path = Set.new [[@x, @y]]
+ @path = [[@x, @y]]
set_path
end
- def eql?(other)
- from == other.from and to == other.to
- end
-
- alias :== :eql?
-
private
def set_path
begin
@error_2 = 2 * @err
correct_x
correct_y
@path << [@x, @y]
end until (@x == @to.x && @y == @to.y)
end
def correct_x
if @error_2 >= @delta_y
@err += @delta_y
@x += @step_x
end
end
def correct_y
if @error_2 <= @delta_x
@err += @delta_x
@y += @step_y
end
end
end
class Rectangle
+ include Graphics
attr_reader :left, :right, :top_left, :top_right,
:bottom_left, :bottom_right, :path
def initialize(first, second)
@min_x, @max_x = [first.x, second.x].min, [first.x, second.x].max
@min_y, @max_y = [first.y, second.y].min, [first.y, second.y].max
set_corners
set_path
end
- def eql?(other)
- left == other.left and right == other.right
- end
-
- alias :== :eql?
-
private
def set_corners
@top_left = @left = Point.new @min_x, @min_y
@top_right = Point.new @max_x, @min_y
@bottom_left = Point.new @min_x, @max_y
@bottom_right = @right = Point.new @max_x, @max_y
end
def set_path
@path = Line.new(@top_left, @top_right).path +
Line.new(@top_right, @bottom_right).path +
Line.new(@bottom_right, @bottom_left).path +
Line.new(@top_left, @bottom_left).path
end
end
+
+ def eql?(other)
+ path == other.path
+ end
+
+ alias :== :eql?
end

Александър обнови решението на 17.12.2013 16:11 (преди почти 11 години)

module Graphics
class Canvas
attr_reader :width, :height
attr_accessor :canvas
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width) }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x]
end
def draw(figure)
figure.path.each { |coordinate| set_pixel coordinate[0], coordinate[1] }
end
def render_as(renderer)
renderer.render(self)
end
end
module Renderers
module Ascii
def self.render(canvas)
canvas.canvas.map { |row| Renderers.process_row(row, '@', '-') }.join("\n")
end
end
module Html
HEADER = <<-EOS
<!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">
EOS
FOOTER = <<-EOS
</div>
</body>
</html>
EOS
def self.render(canvas)
HEADER +
canvas.canvas.map { |row| Renderers.process_row(row, '<b></b>', '<i></i>') }
.join("<br>\n") +
FOOTER
end
end
private
def self.fill_pixel(pixel, color, transparent)
pixel ? color : transparent
end
def self.process_row(row, color, transparent)
row.map { |pixel| Renderers.fill_pixel(pixel, color, transparent) }.join
end
end
class Point
include Graphics
attr_reader :x, :y, :path
def initialize(x, y)
@x = x
@y = y
@path = [[@x, @y]]
end
end
class Line
include Graphics
attr_reader :from, :to, :path
def initialize(from, to)
@from, @to = from, to
@delta_x, @delta_y = (@to.x - @from.x).abs, -(@to.y - @from.y).abs
@step_x, @step_y = (@from.x < @to.x ? 1 : -1), (@from.y < @to.y ? 1 : -1)
@err, @x, @y = @delta_x + @delta_y, @from.x, @from.y
@path = [[@x, @y]]
set_path
end
private
def set_path
begin
@error_2 = 2 * @err
correct_x
correct_y
@path << [@x, @y]
end until (@x == @to.x && @y == @to.y)
end
def correct_x
if @error_2 >= @delta_y
@err += @delta_y
@x += @step_x
end
end
def correct_y
if @error_2 <= @delta_x
@err += @delta_x
@y += @step_y
end
end
end
class Rectangle
include Graphics
attr_reader :left, :right, :top_left, :top_right,
:bottom_left, :bottom_right, :path
def initialize(first, second)
@min_x, @max_x = [first.x, second.x].min, [first.x, second.x].max
@min_y, @max_y = [first.y, second.y].min, [first.y, second.y].max
set_corners
set_path
end
private
def set_corners
@top_left = @left = Point.new @min_x, @min_y
@top_right = Point.new @max_x, @min_y
@bottom_left = Point.new @min_x, @max_y
@bottom_right = @right = Point.new @max_x, @max_y
end
def set_path
@path = Line.new(@top_left, @top_right).path +
Line.new(@top_right, @bottom_right).path +
Line.new(@bottom_right, @bottom_left).path +
Line.new(@top_left, @bottom_left).path
end
end
def eql?(other)
path == other.path
end
alias :== :eql?
+
+ def hash
+ @path.hash
+ end
end

Александър обнови решението на 17.12.2013 16:24 (преди почти 11 години)

module Graphics
class Canvas
attr_reader :width, :height
attr_accessor :canvas
def initialize(width, height)
@width = width
@height = height
@canvas = Array.new(height) { Array.new(width) }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x]
end
def draw(figure)
figure.path.each { |coordinate| set_pixel coordinate[0], coordinate[1] }
end
def render_as(renderer)
renderer.render(self)
end
end
module Renderers
module Ascii
def self.render(canvas)
canvas.canvas.map { |row| Renderers.process_row(row, '@', '-') }.join("\n")
end
end
module Html
HEADER = <<-EOS
<!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">
EOS
FOOTER = <<-EOS
</div>
</body>
</html>
EOS
def self.render(canvas)
HEADER +
canvas.canvas.map { |row| Renderers.process_row(row, '<b></b>', '<i></i>') }
.join("<br>\n") +
FOOTER
end
end
private
def self.fill_pixel(pixel, color, transparent)
pixel ? color : transparent
end
def self.process_row(row, color, transparent)
row.map { |pixel| Renderers.fill_pixel(pixel, color, transparent) }.join
end
end
class Point
include Graphics
attr_reader :x, :y, :path
def initialize(x, y)
@x = x
@y = y
@path = [[@x, @y]]
end
end
class Line
include Graphics
attr_reader :from, :to, :path
def initialize(from, to)
@from, @to = from, to
@delta_x, @delta_y = (@to.x - @from.x).abs, -(@to.y - @from.y).abs
@step_x, @step_y = (@from.x < @to.x ? 1 : -1), (@from.y < @to.y ? 1 : -1)
@err, @x, @y = @delta_x + @delta_y, @from.x, @from.y
@path = [[@x, @y]]
set_path
end
private
def set_path
begin
@error_2 = 2 * @err
correct_x
correct_y
@path << [@x, @y]
end until (@x == @to.x && @y == @to.y)
end
def correct_x
if @error_2 >= @delta_y
@err += @delta_y
@x += @step_x
end
end
def correct_y
if @error_2 <= @delta_x
@err += @delta_x
@y += @step_y
end
end
end
class Rectangle
include Graphics
attr_reader :left, :right, :top_left, :top_right,
:bottom_left, :bottom_right, :path
def initialize(first, second)
@min_x, @max_x = [first.x, second.x].min, [first.x, second.x].max
@min_y, @max_y = [first.y, second.y].min, [first.y, second.y].max
set_corners
set_path
end
private
def set_corners
@top_left = @left = Point.new @min_x, @min_y
@top_right = Point.new @max_x, @min_y
@bottom_left = Point.new @min_x, @max_y
@bottom_right = @right = Point.new @max_x, @max_y
end
def set_path
@path = Line.new(@top_left, @top_right).path +
Line.new(@top_right, @bottom_right).path +
Line.new(@bottom_right, @bottom_left).path +
Line.new(@top_left, @bottom_left).path
end
end
def eql?(other)
path == other.path
end
alias :== :eql?
def hash
@path.hash
end
-end
+end

Бележки:

  • Помисли дали няма друг по-оптимален начин в Ruby за реализация вътрешното представяне на пано от двумерен масив. Тъй като Ruby не е C, можем да ползваме и други, по-удобни типове данни :)
  • Имаш дребни проблеми с идентацията тук-там, потърси ги. Иначе кодът ти е прилично подреден като цяло.
  • На ред 21, може да се възползваш от разпадането на аргументите на блок и да напишеш |x, y|, вместо coordinate. Друг, по-малко предпочитан вариант е да бъде така: { |coordinates| set_pixel *coordinates }.
  • Даваш достъп до вътрешното представяне на пано през метод canvas. Има и setter, което не е добра идея. Мисля, че в renderer-ите може да минеш и без това. Публичният интерфейс, дефиниран в пано, ти дава достатъчно информация за целта.
  • process_row не е добро име; сигнал е, че има нужда от малко рефакторинг там; виж дали няма да ти хрумне по-добра идея как да преработиш тази част от задачата. Помисли кой обект каква отговорност носи. Една основна идея на ОО-програмирането е да разпределиш различните отговорности между различни обекти. Стреми се всеки обект да отговаря за едно конкретно нещо и само за него. Напълно нормално е да имаш голям брой малки обекти в системата, с тясно специализирани отговорности.
  • Принципно няма причина да ползваш HEREDOC за дефиниция на HTML-низа, и низ с единични кавички ще свърши работа. Но ако позлваш HEREDOC, гледай ограничителите му да са тематични. Примерно, HTML, вместо EOS. И в този случай, в който правиш outdent на съдържанието, аз бих залепил ограничителя в ляво, не бих ползвал <<-, но това е по-скоро въпрос на вкус.
  • Нещо не ми харесват аргументите на fill_pixel – имената им не си съответстват. Не ми става ясно, че pixel се очаква да е флаг; би било по-добре да е is_set или нещо от сорта; след това имаме "цвят" и "прозрачен" – едното е съществително, а другото е прилагателно и няма съответствие. Целият метод е един тернарен оператор. И на всичкото отгоре, е публичен метод, какъвто е и process_row, а не мисля, че е добре да е част от публичния интерфейс на рендерерите. Всичко това са знаци, че рендерерите имат нужда от рефакторинг.
  • Имплементирал си методите за равенство и hash по много странен начин. По-добре ги премести в отделен модул в Graphics. Няма причина да са top level публични методи в Graphics, а и е много странно да го include-ваш по този начин във фигурите.
  • Не ми харесва конструкторът на Line. Твърде много ternary оператори, твърде наблъскан и неподреден ми е. Рефакторирай :)
  • Ако ще ползваш until (ред 122), не го прави така – лоша идея е да е в края на реда. Започни с until @x == @to.x and @y == @to.y, или пък с по-логичното while @x != @to_x or @y != @to_y.
  • error_2 е лошо име на променлива; correct_x/y също са неясни; какво коригират? Не е ли по-добре calculate_next_x, примерно?