Решение на Трета задача от Деян Хаджиев

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

Към профила на Деян Хаджиев

Резултати

  • 4 точки от тестове
  • 0 бонус точки
  • 4 точки общо
  • 50 успешни тест(а)
  • 19 неуспешни тест(а)

Код

module Graphics
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def points
[self]
end
def eql?(other_point)
x == other_point.x and y == other_point.y
end
alias == eql?
def hash
"(#{x},#{y})".hash
end
end
class Line
attr_reader :from, :to
def initialize(first, second)
if first.x < second.x or (first.x == second.x and first.y < second.y)
@from, @to = first, second
else
@from, @to = second, first
end
end
def eql?(other_line)
@from == other_line.from and @to == other_line.to
end
alias == eql?
def hash
"(#{@from.x},#{@from.y})-(#{@to.x},#{@to.y})".hash
end
def points
bresenham(@from, @to)
end
private
def bresenham(from, to)
steep = (to.y - from.y).abs > (to.x - from.x).abs
if steep then from, to = Point.new(from.y, from.x), Point.new(to.y, to.x) end
if from.x > to.x then from, to = to, from end
deltas = bresenham_calculate_delta_and_step(from, to)
delta_x, delta_y, step_y = deltas[:delta_x], deltas[:delta_y], deltas[:step_y]
bresenham_loop from.x, to.x, from.y, delta_x / 2, delta_x, delta_y, step_y, steep
end
def bresenham_loop(start_x, end_x, y, error, delta_x, delta_y, step_y, steep)
start_x.upto(end_x).to_a.map do |x|
point = steep ? Point.new(y, x) : Point.new(x, y)
error -= delta_y
if error <= 0
y, error = y + step_y, error + delta_x
end
point
end
end
def bresenham_calculate_delta_and_step(from, to)
result = {}
result[:delta_x] = to.x - from.x
result[:delta_y] = (to.y - from.y).abs
result[:step_y] = from.y < to.y ? 1 : -1
result
end
end
class Rectangle
attr_reader :left, :right
def initialize(first, second)
if first.x < second.x or (first.x == second.x and first.y < second.y)
@left, @right = first, second
else
@left, @right = second, first
end
end
def top_left
Point.new left.x, [left.y, right.y].min
end
def top_right
Point.new right.x, [left.y, right.y].min
end
def bottom_left
Point.new left.x, [left.y, right.y].max
end
def bottom_right
Point.new right.x, [left.y, right.y].max
end
def eql?(other)
top_left.eql? other.top_left and bottom_right.eql? other.bottom_right
end
alias == eql?
def hash
"(#{top_left.x},#{top_left.y}):(#{bottom_right.x},#{bottom_right.y})".hash
end
def points
points = []
points << horizontal_points(top_left, top_right)
points << vertical_points(top_right, bottom_right)
points << horizontal_points(bottom_left, bottom_right)
points << vertical_points(top_left, bottom_left)
points.flatten
end
private
def horizontal_points(left, right)
if left.y != right.y
[]
else
left.x.upto(right.x).to_a.map { |x| Point.new x, left.y }
end
end
def vertical_points(top, bottom)
if top.x != bottom.x
[]
else
top.y.upto(bottom.y).to_a.map { |y| Point.new top.x, y }
end
end
end
module Renderer
class Generic
class << self
def render_canvas(canvas)
canvas_matrix = Array.new (canvas.height) do |row|
Array.new (canvas.width) { |column| canvas.pixel_at?(column, row) }
end
strings = canvas_matrix.map { |line| line.map { |pixel| render_pixel pixel } }
strings = strings.map { |line| line.join }.join render_new_line
end
end
end
class Ascii < Generic
HEADER = ""
FOOTER = ""
class << self
def render_pixel(pixel)
pixel ? "@" : "-"
end
def render_new_line
"\n"
end
end
end
class Html < Generic
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>'
class << self
def render_pixel(pixel)
pixel ? "<b></b>" : "<i></i>"
end
def render_new_line
"<br>\n"
end
end
end
end
class Canvas
class OutOfBounds < StandardError
end
attr_reader :width, :height
def initialize( width, height)
@width = width
@height = height
@canvas = {}
0.upto(height).each { |index| @canvas[index] = {} }
end
def set_pixel(x, y)
@canvas[y][x] = true
end
def pixel_at?(x, y)
@canvas[y][x].nil? ? false : true
end
def draw(object)
points = object.points
points.each { |point| set_pixel(point.x, point.y) }
end
def render_as(renderer)
output = renderer::HEADER
output << renderer.render_canvas(self)
output << renderer::FOOTER
end
end
end

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

........F.FFFFFFFFFFFFFFFFFF.........................................

Failures:

  1) Graphics Canvas drawing of shapes and rasterization renders multiple drawn shapes
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/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 = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/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 simple horizontal lines
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:73: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 vertical lines
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:84: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 lines with a small slope
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/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)>'

  6) Graphics Canvas drawing of shapes and rasterization of lines works with lines with a significant slope, with swapped ends
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/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)>'

  7) Graphics Canvas drawing of shapes and rasterization of lines works with multiple lines
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/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)>'

  8) Graphics Canvas drawing of shapes and rasterization of lines draws lines with two equal ends as points
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:145: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 Canvas drawing of shapes and rasterization of rectangles works with simple rects
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:158: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 Canvas drawing of shapes and rasterization of rectangles works with rects defined with their bottom left and top right points
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:171: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 Canvas drawing of shapes and rasterization of rectangles works with rects with a zero height as a line
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:184: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 Canvas drawing of shapes and rasterization of rectangles works with rects with a zero width and height as a single point
     Failure/Error: ascii = canvas.render_as(Graphics::Renderers::Ascii)
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:623:in `check_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:195: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)>'

  13) Graphics Renderers Ascii renders a grid of the size of the canvas
     Failure/Error: let(:ascii) { Graphics::Renderers::Ascii }
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:234:in `block (4 levels) in <top (required)>'
     # /tmp/d20131223-4637-1izrttl/spec.rb:238: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)>'

  14) Graphics Renderers Ascii renders blank canvases
     Failure/Error: let(:ascii) { Graphics::Renderers::Ascii }
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:234:in `block (4 levels) in <top (required)>'
     # /tmp/d20131223-4637-1izrttl/spec.rb:245: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)>'

  15) Graphics Renderers Ascii renders simple canvases
     Failure/Error: let(:ascii) { Graphics::Renderers::Ascii }
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:234:in `block (4 levels) in <top (required)>'
     # /tmp/d20131223-4637-1izrttl/spec.rb:256: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)>'

  16) Graphics Renderers Html returns html
     Failure/Error: let(:html)        { Graphics::Renderers::Html }
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:265:in `block (4 levels) in <top (required)>'
     # /tmp/d20131223-4637-1izrttl/spec.rb:272: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)>'

  17) Graphics Renderers Html renders a grid of the size of the canvas
     Failure/Error: let(:html)        { Graphics::Renderers::Html }
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:265:in `block (4 levels) in <top (required)>'
     # /tmp/d20131223-4637-1izrttl/spec.rb:309:in `html_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:281: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)>'

  18) Graphics Renderers Html renders simple canvases
     Failure/Error: let(:html)        { Graphics::Renderers::Html }
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:265:in `block (4 levels) in <top (required)>'
     # /tmp/d20131223-4637-1izrttl/spec.rb:309:in `html_rendering_of'
     # /tmp/d20131223-4637-1izrttl/spec.rb:291: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)>'

  19) Graphics Renderers Html returns the same rendering when called twice
     Failure/Error: let(:html)        { Graphics::Renderers::Html }
     NameError:
       uninitialized constant Graphics::Renderers
     # /tmp/d20131223-4637-1izrttl/spec.rb:265:in `block (4 levels) in <top (required)>'
     # /tmp/d20131223-4637-1izrttl/spec.rb:302: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)>'

Finished in 0.07665 seconds
69 examples, 19 failures

Failed examples:

rspec /tmp/d20131223-4637-1izrttl/spec.rb:203 # Graphics Canvas drawing of shapes and rasterization renders multiple drawn shapes
rspec /tmp/d20131223-4637-1izrttl/spec.rb:51 # Graphics Canvas drawing of shapes and rasterization of points works for multiple ones
rspec /tmp/d20131223-4637-1izrttl/spec.rb:69 # Graphics Canvas drawing of shapes and rasterization of lines works with simple horizontal lines
rspec /tmp/d20131223-4637-1izrttl/spec.rb:80 # Graphics Canvas drawing of shapes and rasterization of lines works with vertical lines
rspec /tmp/d20131223-4637-1izrttl/spec.rb:96 # Graphics Canvas drawing of shapes and rasterization of lines works with lines with a small slope
rspec /tmp/d20131223-4637-1izrttl/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-1izrttl/spec.rb:127 # Graphics Canvas drawing of shapes and rasterization of lines works with multiple lines
rspec /tmp/d20131223-4637-1izrttl/spec.rb:141 # Graphics Canvas drawing of shapes and rasterization of lines draws lines with two equal ends as points
rspec /tmp/d20131223-4637-1izrttl/spec.rb:154 # Graphics Canvas drawing of shapes and rasterization of rectangles works with simple rects
rspec /tmp/d20131223-4637-1izrttl/spec.rb:167 # Graphics Canvas drawing of shapes and rasterization of rectangles works with rects defined with their bottom left and top right points
rspec /tmp/d20131223-4637-1izrttl/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-1izrttl/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-1izrttl/spec.rb:237 # Graphics Renderers Ascii renders a grid of the size of the canvas
rspec /tmp/d20131223-4637-1izrttl/spec.rb:244 # Graphics Renderers Ascii renders blank canvases
rspec /tmp/d20131223-4637-1izrttl/spec.rb:252 # Graphics Renderers Ascii renders simple canvases
rspec /tmp/d20131223-4637-1izrttl/spec.rb:271 # Graphics Renderers Html returns html
rspec /tmp/d20131223-4637-1izrttl/spec.rb:280 # Graphics Renderers Html renders a grid of the size of the canvas
rspec /tmp/d20131223-4637-1izrttl/spec.rb:287 # Graphics Renderers Html renders simple canvases
rspec /tmp/d20131223-4637-1izrttl/spec.rb:298 # Graphics Renderers Html returns the same rendering when called twice

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

Деян обнови решението на 20.12.2013 01:07 (преди над 10 години)

+module Graphics
+ #Figures
+ class Point
+ attr_reader :x, :y
+
+ def initialize(x, y)
+ @x = x
+ @y = y
+ self
+ end
+
+ def get_points
+ [self]
+ end
+
+ def in_bounds?(width, height)
+ x >= 0 and x < width and y >= 0 and y < height
+ end
+
+ def ==(other_point)
+ eql? other_point
+ end
+
+ def eql?(other_point)
+ x == other_point.x and y == other_point.y
+ end
+
+ def hash
+ "(#{x},#{y})".hash
+ end
+ end
+
+ class Line
+ attr_reader :from, :to
+
+ def initialize(first, second)
+ if first.x < second.x or (first.x == second.x and first.y < second.y)
+ @from, @to = first, second
+ else
+ @from, @to = second, first
+ end
+ end
+
+ def eql?(other_line)
+ @from == other_line.from and @to == other_line.to
+ end
+
+ def ==(other_line)
+ eql? other_line
+ end
+
+ def hash
+ "(#{@from.x},#{@from.y})-(#{@to.x},#{@to.y})".hash
+ end
+
+ def in_bounds?(width, height)
+ @from.in_bounds?(width, height) and @to.in_bounds?(width, height)
+ end
+
+ def get_points
+ bresenham(@from, @to)
+ end
+
+ def bresenham(from, to)
+ steep = (to.y - from.y).abs > (to.x - from.x).abs
+ if steep then from, to = Point.new(from.y, from.x), Point.new(to.y, to.x) end
+ if from.x > to.x then from, to = to, from end
+ delta_x, step_y = to.x - from.x, from.y < to.y ? 1 : -1
+ delta_y = (to.y - from.y).abs
+ bresenham_loop from.x, to.x, from.y, delta_x / 2, delta_x, delta_y, step_y, steep
+ end
+
+ def bresenham_loop(start_x, end_x, y, error, delta_x, delta_y, step_y, steep)
+ start_x.upto(end_x).to_a.map do |x|
+ point = steep ? Point.new(y, x) : Point.new(x, y)
+ error -= delta_y
+ if error <= 0
+ y, error = y + step_y, error + delta_x
+ end
+ point
+ end
+ end
+
+ private :bresenham, :bresenham_loop
+ end
+
+ class Rectangle
+ attr_reader :left, :right
+
+ def initialize(first, second)
+ if first.x < second.x or (first.x == second.x and first.y < second.y)
+ @left, @right = first, second
+ else
+ @left, @right = second, first
+ end
+ end
+
+ def top_left
+ Point.new left.x, [left.y, right.y].min
+ end
+
+ def top_right
+ Point.new right.x, [left.y, right.y].min
+ end
+
+ def bottom_left
+ Point.new left.x, [left.y, right.y].max
+ end
+
+ def bottom_right
+ Point.new right.x, [left.y, right.y].max
+ end
+
+ def eql?(other)
+ top_left.eql? other.top_left and bottom_right.eql? other.bottom_right
+ end
+
+ def ==(other)
+ eql? other
+ end
+
+ def hash
+ "(#{top_left.x},#{top_left.y}):(#{bottom_right.x},#{bottom_right.y})".hash
+ end
+
+ def in_bounds?(width, height)
+ top_left.in_bounds?(width, height) and bottom_right.in_bounds?(width, height)
+ end
+
+ def get_points
+ points = []
+ points.concat get_horizontal_points(top_left, top_right)
+ points.concat get_vertical_points(top_right, bottom_right)
+ points.concat get_horizontal_points(bottom_left, bottom_right)
+ points.concat get_vertical_points(top_left, bottom_left)
+ points
+ end
+
+ def get_horizontal_points(left, right)
+ if left.y != right.y
+ []
+ else
+ left.x.upto(right.x).to_a.map { |x| Point.new x, left.y }
+ end
+ end
+
+ def get_vertical_points(top, bottom)
+ if top.x != bottom.x
+ []
+ else
+ top.y.upto(bottom.y).to_a.map { |y| Point.new top.x, y }
+ end
+ end
+
+ private :get_horizontal_points, :get_vertical_points
+ end
+end
+
+module Graphics
+ #renderers
+ module Renderer
+ class Generic
+ end
+ class Ascii < Generic
+ end
+ class Html < Generic
+ end
+
+ class << Generic
+ def render(canvas)
+ output = ""
+ output << header
+ output << render_canvas(canvas)
+ output << footer
+ output
+ end
+
+ def render_canvas(canvas)
+ strings = canvas.map { |line| line.map { |pixel| render_pixel pixel } }
+ strings = strings.map { |line| line.join }.join render_new_line
+ strings
+ end
+ end
+
+ class << Ascii
+ def header
+ ""
+ end
+
+ def footer
+ ""
+ end
+
+ def render_pixel(pixel)
+ pixel ? "@" : "-"
+ end
+
+ def render_new_line
+ "\n"
+ end
+ end
+
+ class << Html
+ 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">
+ '
+
+ HTML_FOOTER =
+ '
+ </div>
+ </body>
+ </html>'
+
+ def header
+ HTML_HEADER
+ end
+
+ def footer
+ HTML_FOOTER
+ end
+
+ def render_pixel(pixel)
+ pixel ? "<b></b>" : "<i></i>"
+ end
+
+ def render_new_line
+ "<br>\n"
+ end
+ end
+ end
+end
+
+module Graphics
+ #canvas
+ class Canvas
+ class OutOfBounds < StandardError
+ end
+
+ attr_reader :width, :height, :canvas
+
+ def initialize( width, height)
+ @width = width
+ @height = height
+ @canvas = Array.new(height) { Array.new(width) { false } }
+ end
+
+ def set_pixel(x, y)
+ if x >= @width or y >= @height
+ raise OutOfBounds, "Setting a pixel out of canvas' bounds."
+ else
+ @canvas[y][x] = true
+ end
+ end
+
+ def pixel_at?(x, y)
+ if x >= @width or y >= @height
+ raise OutOfBounds, "Reaching a pixel out of canvas' bounds"
+ else
+ @canvas[y][x]
+ end
+ end
+
+ def draw(object)
+ if object.in_bounds?(width, height)
+ points = object.get_points
+ points.each { |point| set_pixel(point.x, point.y) }
+ else
+ raise OutOfBounds, "The object is out of canvas' bounds"
+ end
+ end
+
+ def render_as(renderer)
+ renderer.render(@canvas)
+ end
+ end
+end

Деян обнови решението на 20.12.2013 01:13 (преди над 10 години)

module Graphics
#Figures
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
self
end
def get_points
[self]
end
def in_bounds?(width, height)
x >= 0 and x < width and y >= 0 and y < height
end
def ==(other_point)
eql? other_point
end
def eql?(other_point)
x == other_point.x and y == other_point.y
end
def hash
"(#{x},#{y})".hash
end
end
class Line
attr_reader :from, :to
def initialize(first, second)
if first.x < second.x or (first.x == second.x and first.y < second.y)
@from, @to = first, second
else
@from, @to = second, first
end
end
def eql?(other_line)
@from == other_line.from and @to == other_line.to
end
def ==(other_line)
eql? other_line
end
def hash
"(#{@from.x},#{@from.y})-(#{@to.x},#{@to.y})".hash
end
def in_bounds?(width, height)
@from.in_bounds?(width, height) and @to.in_bounds?(width, height)
end
def get_points
bresenham(@from, @to)
end
def bresenham(from, to)
steep = (to.y - from.y).abs > (to.x - from.x).abs
if steep then from, to = Point.new(from.y, from.x), Point.new(to.y, to.x) end
if from.x > to.x then from, to = to, from end
delta_x, step_y = to.x - from.x, from.y < to.y ? 1 : -1
delta_y = (to.y - from.y).abs
bresenham_loop from.x, to.x, from.y, delta_x / 2, delta_x, delta_y, step_y, steep
end
def bresenham_loop(start_x, end_x, y, error, delta_x, delta_y, step_y, steep)
start_x.upto(end_x).to_a.map do |x|
point = steep ? Point.new(y, x) : Point.new(x, y)
error -= delta_y
if error <= 0
y, error = y + step_y, error + delta_x
end
point
end
end
private :bresenham, :bresenham_loop
end
class Rectangle
attr_reader :left, :right
def initialize(first, second)
if first.x < second.x or (first.x == second.x and first.y < second.y)
@left, @right = first, second
else
@left, @right = second, first
end
end
def top_left
Point.new left.x, [left.y, right.y].min
end
def top_right
Point.new right.x, [left.y, right.y].min
end
def bottom_left
Point.new left.x, [left.y, right.y].max
end
def bottom_right
Point.new right.x, [left.y, right.y].max
end
def eql?(other)
top_left.eql? other.top_left and bottom_right.eql? other.bottom_right
end
def ==(other)
eql? other
end
def hash
"(#{top_left.x},#{top_left.y}):(#{bottom_right.x},#{bottom_right.y})".hash
end
def in_bounds?(width, height)
top_left.in_bounds?(width, height) and bottom_right.in_bounds?(width, height)
end
def get_points
points = []
points.concat get_horizontal_points(top_left, top_right)
points.concat get_vertical_points(top_right, bottom_right)
points.concat get_horizontal_points(bottom_left, bottom_right)
points.concat get_vertical_points(top_left, bottom_left)
points
end
def get_horizontal_points(left, right)
if left.y != right.y
[]
else
left.x.upto(right.x).to_a.map { |x| Point.new x, left.y }
end
end
def get_vertical_points(top, bottom)
if top.x != bottom.x
[]
else
top.y.upto(bottom.y).to_a.map { |y| Point.new top.x, y }
end
end
private :get_horizontal_points, :get_vertical_points
end
end
module Graphics
#renderers
module Renderer
class Generic
end
class Ascii < Generic
end
class Html < Generic
end
class << Generic
def render(canvas)
output = ""
output << header
output << render_canvas(canvas)
output << footer
output
end
def render_canvas(canvas)
strings = canvas.map { |line| line.map { |pixel| render_pixel pixel } }
strings = strings.map { |line| line.join }.join render_new_line
strings
end
end
class << Ascii
def header
""
end
def footer
""
end
def render_pixel(pixel)
pixel ? "@" : "-"
end
def render_new_line
"\n"
end
end
class << Html
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">
'
HTML_FOOTER =
'
</div>
</body>
</html>'
def header
HTML_HEADER
end
def footer
HTML_FOOTER
end
def render_pixel(pixel)
pixel ? "<b></b>" : "<i></i>"
end
def render_new_line
"<br>\n"
end
end
end
end
module Graphics
#canvas
class Canvas
class OutOfBounds < StandardError
end
- attr_reader :width, :height, :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)
- if x >= @width or y >= @height
+ if x < 0 or x >= @width or y < 0 or y >= @height
raise OutOfBounds, "Setting a pixel out of canvas' bounds."
else
@canvas[y][x] = true
end
end
def pixel_at?(x, y)
- if x >= @width or y >= @height
+ if x < 0 or x >= @width or y < 0 or y >= @height
raise OutOfBounds, "Reaching a pixel out of canvas' bounds"
else
@canvas[y][x]
end
end
def draw(object)
if object.in_bounds?(width, height)
points = object.get_points
points.each { |point| set_pixel(point.x, point.y) }
else
raise OutOfBounds, "The object is out of canvas' bounds"
end
end
def render_as(renderer)
renderer.render(@canvas)
end
end
end

Деян обнови решението на 20.12.2013 10:57 (преди над 10 години)

module Graphics
- #Figures
+ #figures
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
- self
end
def get_points
[self]
end
def in_bounds?(width, height)
x >= 0 and x < width and y >= 0 and y < height
end
def ==(other_point)
eql? other_point
end
def eql?(other_point)
x == other_point.x and y == other_point.y
end
def hash
"(#{x},#{y})".hash
end
end
class Line
attr_reader :from, :to
def initialize(first, second)
if first.x < second.x or (first.x == second.x and first.y < second.y)
@from, @to = first, second
else
@from, @to = second, first
end
end
def eql?(other_line)
@from == other_line.from and @to == other_line.to
end
def ==(other_line)
eql? other_line
end
def hash
"(#{@from.x},#{@from.y})-(#{@to.x},#{@to.y})".hash
end
def in_bounds?(width, height)
@from.in_bounds?(width, height) and @to.in_bounds?(width, height)
end
def get_points
bresenham(@from, @to)
end
def bresenham(from, to)
steep = (to.y - from.y).abs > (to.x - from.x).abs
if steep then from, to = Point.new(from.y, from.x), Point.new(to.y, to.x) end
if from.x > to.x then from, to = to, from end
delta_x, step_y = to.x - from.x, from.y < to.y ? 1 : -1
delta_y = (to.y - from.y).abs
bresenham_loop from.x, to.x, from.y, delta_x / 2, delta_x, delta_y, step_y, steep
end
def bresenham_loop(start_x, end_x, y, error, delta_x, delta_y, step_y, steep)
start_x.upto(end_x).to_a.map do |x|
point = steep ? Point.new(y, x) : Point.new(x, y)
error -= delta_y
if error <= 0
y, error = y + step_y, error + delta_x
end
point
end
end
private :bresenham, :bresenham_loop
end
class Rectangle
attr_reader :left, :right
def initialize(first, second)
if first.x < second.x or (first.x == second.x and first.y < second.y)
@left, @right = first, second
else
@left, @right = second, first
end
end
def top_left
Point.new left.x, [left.y, right.y].min
end
def top_right
Point.new right.x, [left.y, right.y].min
end
def bottom_left
Point.new left.x, [left.y, right.y].max
end
def bottom_right
Point.new right.x, [left.y, right.y].max
end
def eql?(other)
top_left.eql? other.top_left and bottom_right.eql? other.bottom_right
end
def ==(other)
eql? other
end
def hash
"(#{top_left.x},#{top_left.y}):(#{bottom_right.x},#{bottom_right.y})".hash
end
def in_bounds?(width, height)
top_left.in_bounds?(width, height) and bottom_right.in_bounds?(width, height)
end
def get_points
points = []
points.concat get_horizontal_points(top_left, top_right)
points.concat get_vertical_points(top_right, bottom_right)
points.concat get_horizontal_points(bottom_left, bottom_right)
points.concat get_vertical_points(top_left, bottom_left)
points
end
def get_horizontal_points(left, right)
if left.y != right.y
[]
else
left.x.upto(right.x).to_a.map { |x| Point.new x, left.y }
end
end
def get_vertical_points(top, bottom)
if top.x != bottom.x
[]
else
top.y.upto(bottom.y).to_a.map { |y| Point.new top.x, y }
end
end
private :get_horizontal_points, :get_vertical_points
end
end
module Graphics
#renderers
module Renderer
class Generic
end
class Ascii < Generic
end
class Html < Generic
end
class << Generic
def render(canvas)
output = ""
output << header
output << render_canvas(canvas)
output << footer
output
end
def render_canvas(canvas)
strings = canvas.map { |line| line.map { |pixel| render_pixel pixel } }
strings = strings.map { |line| line.join }.join render_new_line
strings
end
end
class << Ascii
def header
""
end
def footer
""
end
def render_pixel(pixel)
pixel ? "@" : "-"
end
def render_new_line
"\n"
end
end
class << Html
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">
'
HTML_FOOTER =
'
</div>
</body>
</html>'
def header
HTML_HEADER
end
def footer
HTML_FOOTER
end
def render_pixel(pixel)
pixel ? "<b></b>" : "<i></i>"
end
def render_new_line
"<br>\n"
end
end
end
end
module Graphics
#canvas
class Canvas
class OutOfBounds < StandardError
end
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)
if x < 0 or x >= @width or y < 0 or y >= @height
raise OutOfBounds, "Setting a pixel out of canvas' bounds."
else
@canvas[y][x] = true
end
end
def pixel_at?(x, y)
if x < 0 or x >= @width or y < 0 or y >= @height
raise OutOfBounds, "Reaching a pixel out of canvas' bounds"
else
@canvas[y][x]
end
end
def draw(object)
if object.in_bounds?(width, height)
points = object.get_points
points.each { |point| set_pixel(point.x, point.y) }
else
raise OutOfBounds, "The object is out of canvas' bounds"
end
end
def render_as(renderer)
renderer.render(@canvas)
end
end
end

Бележки:

  • Струва ми се, че within_bounds? е по-добро име от in_bounds?.
  • В Ruby няма практика да има думата get_ в името на методите; тази дума просто генерира шум и не носи информация.
  • Може да ползваш синоними на методи, за да дефинираш единия от методите на равенството на фигури.
  • Махни коментарите.
  • В Line#hash може да се възползваш от факта, че имаш Point#hash. Същото и за правоъгълник.
  • Методът bresenham ми е малко нагъчкан и нечетим. Опитай да го подобриш.
  • Нека да напомня, че празните редове не се броят от skeptic и е добра практика да се слагат на места в методи, за да разделят блокове от код.
  • Струва ми се, че може да се измисли по-добро име от bresenham_loop за този метод.
  • Дефинираш тези два метода като private по неидиоматичен начин. Просто сложи private м/у редове 61 и 63. Същото и за правоъгълник.
  • Rectangle#get_points може да стане с литерален синтаксис за масив, плюс flatten, например. Пробвай.
  • Не разбирам защо прекъсващ дефиницията на модула Graphics на ред 156-158, както и още веднъж по-надолу. Може спокойно да си я продължиш до края на условието.
  • Ако искаш да сложиш класови методи в Generic, идиоматичният начин за това би бил:

      ...
      module Renderers
        class Generic
          class << self
            def render(...)
              ...
            end
    
            ...
          end
        end
      end
    

    Същото важи и за Ascii и Html.

  • Няма нужда от методите Html.header и Html.footer, може да ползваш директно константите, така: Html::HTML_HEADER. Тук виждаш и малко тафтология, може да я отстраниш, ако искаш.
  • Виждам, че тези два метода ги ползваш, за да преизползваш логика от Generic. Може да стане и без тях, помисли как :)
  • render и render_canvas методите не ми харесват. Поработи да ги рефакторираш (това включва не само имена и код, а може и да означава да не са два метода).
  • Имплементацията трябва да поддържа чертане на фигури, които са частично извън паното и това е по-интуитивното нещо от двете. Никъде в условието не се иска да се хвърля грешка, ако обект излиза частично от паното.

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

Деян обнови решението на 22.12.2013 17:02 (преди над 10 години)

module Graphics
- #figures
class Point
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
- def get_points
+ def points
[self]
end
- def in_bounds?(width, height)
- x >= 0 and x < width and y >= 0 and y < height
- end
-
- def ==(other_point)
- eql? other_point
- end
-
def eql?(other_point)
x == other_point.x and y == other_point.y
end
+ alias == eql?
+
def hash
"(#{x},#{y})".hash
end
end
class Line
attr_reader :from, :to
def initialize(first, second)
if first.x < second.x or (first.x == second.x and first.y < second.y)
@from, @to = first, second
else
@from, @to = second, first
end
end
def eql?(other_line)
@from == other_line.from and @to == other_line.to
end
- def ==(other_line)
- eql? other_line
- end
+ alias == eql?
def hash
"(#{@from.x},#{@from.y})-(#{@to.x},#{@to.y})".hash
end
- def in_bounds?(width, height)
- @from.in_bounds?(width, height) and @to.in_bounds?(width, height)
- end
-
- def get_points
+ def points
bresenham(@from, @to)
end
+ private
+
def bresenham(from, to)
steep = (to.y - from.y).abs > (to.x - from.x).abs
+
if steep then from, to = Point.new(from.y, from.x), Point.new(to.y, to.x) end
if from.x > to.x then from, to = to, from end
- delta_x, step_y = to.x - from.x, from.y < to.y ? 1 : -1
- delta_y = (to.y - from.y).abs
+
+ deltas = bresenham_calculate_delta_and_step(from, to)
+ delta_x, delta_y, step_y = deltas[:delta_x], deltas[:delta_y], deltas[:step_y]
+
bresenham_loop from.x, to.x, from.y, delta_x / 2, delta_x, delta_y, step_y, steep
end
def bresenham_loop(start_x, end_x, y, error, delta_x, delta_y, step_y, steep)
start_x.upto(end_x).to_a.map do |x|
point = steep ? Point.new(y, x) : Point.new(x, y)
error -= delta_y
if error <= 0
y, error = y + step_y, error + delta_x
end
point
end
end
- private :bresenham, :bresenham_loop
+ def bresenham_calculate_delta_and_step(from, to)
+ result = {}
+ result[:delta_x] = to.x - from.x
+ result[:delta_y] = (to.y - from.y).abs
+ result[:step_y] = from.y < to.y ? 1 : -1
+ result
+ end
end
class Rectangle
attr_reader :left, :right
def initialize(first, second)
if first.x < second.x or (first.x == second.x and first.y < second.y)
@left, @right = first, second
else
@left, @right = second, first
end
end
def top_left
Point.new left.x, [left.y, right.y].min
end
def top_right
Point.new right.x, [left.y, right.y].min
end
def bottom_left
Point.new left.x, [left.y, right.y].max
end
def bottom_right
Point.new right.x, [left.y, right.y].max
end
def eql?(other)
top_left.eql? other.top_left and bottom_right.eql? other.bottom_right
end
- def ==(other)
- eql? other
- end
+ alias == eql?
def hash
"(#{top_left.x},#{top_left.y}):(#{bottom_right.x},#{bottom_right.y})".hash
end
- def in_bounds?(width, height)
- top_left.in_bounds?(width, height) and bottom_right.in_bounds?(width, height)
- end
-
- def get_points
+ def points
points = []
- points.concat get_horizontal_points(top_left, top_right)
- points.concat get_vertical_points(top_right, bottom_right)
- points.concat get_horizontal_points(bottom_left, bottom_right)
- points.concat get_vertical_points(top_left, bottom_left)
- points
+ points << horizontal_points(top_left, top_right)
+ points << vertical_points(top_right, bottom_right)
+ points << horizontal_points(bottom_left, bottom_right)
+ points << vertical_points(top_left, bottom_left)
+ points.flatten
end
- def get_horizontal_points(left, right)
+ private
+
+ def horizontal_points(left, right)
if left.y != right.y
[]
else
left.x.upto(right.x).to_a.map { |x| Point.new x, left.y }
end
end
- def get_vertical_points(top, bottom)
+ def vertical_points(top, bottom)
if top.x != bottom.x
[]
else
top.y.upto(bottom.y).to_a.map { |y| Point.new top.x, y }
end
end
-
- private :get_horizontal_points, :get_vertical_points
end
-end
-module Graphics
- #renderers
module Renderer
class Generic
- end
- class Ascii < Generic
- end
- class Html < Generic
- end
+ class << self
+ def render_canvas(canvas)
+ canvas_matrix = Array.new (canvas.height) do |row|
+ Array.new (canvas.width) { |column| canvas.pixel_at?(column, row) }
+ end
- class << Generic
- def render(canvas)
- output = ""
- output << header
- output << render_canvas(canvas)
- output << footer
- output
+ strings = canvas_matrix.map { |line| line.map { |pixel| render_pixel pixel } }
+ strings = strings.map { |line| line.join }.join render_new_line
+ end
end
-
- def render_canvas(canvas)
- strings = canvas.map { |line| line.map { |pixel| render_pixel pixel } }
- strings = strings.map { |line| line.join }.join render_new_line
- strings
- end
end
- class << Ascii
- def header
- ""
- end
+ class Ascii < Generic
+ HEADER = ""
- def footer
- ""
- end
+ FOOTER = ""
- def render_pixel(pixel)
- pixel ? "@" : "-"
- end
+ class << self
+ def render_pixel(pixel)
+ pixel ? "@" : "-"
+ end
- def render_new_line
- "\n"
+ def render_new_line
+ "\n"
+ end
end
end
- class << Html
- HTML_HEADER =
+ class Html < Generic
+ 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">
- '
+ <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_FOOTER =
+ FOOTER =
'
- </div>
- </body>
- </html>'
+ </div>
+ </body>
+ </html>'
- def header
- HTML_HEADER
- end
+ class << self
+ def render_pixel(pixel)
+ pixel ? "<b></b>" : "<i></i>"
+ end
- def footer
- HTML_FOOTER
+ def render_new_line
+ "<br>\n"
+ end
end
-
- def render_pixel(pixel)
- pixel ? "<b></b>" : "<i></i>"
- end
-
- def render_new_line
- "<br>\n"
- end
end
end
-end
-module Graphics
- #canvas
class Canvas
class OutOfBounds < StandardError
end
attr_reader :width, :height
def initialize( width, height)
@width = width
@height = height
- @canvas = Array.new(height) { Array.new(width) { false } }
+ @canvas = {}
+ 0.upto(height).each { |index| @canvas[index] = {} }
end
def set_pixel(x, y)
- if x < 0 or x >= @width or y < 0 or y >= @height
- raise OutOfBounds, "Setting a pixel out of canvas' bounds."
- else
- @canvas[y][x] = true
- end
+ @canvas[y][x] = true
end
def pixel_at?(x, y)
- if x < 0 or x >= @width or y < 0 or y >= @height
- raise OutOfBounds, "Reaching a pixel out of canvas' bounds"
- else
- @canvas[y][x]
- end
+ @canvas[y][x].nil? ? false : true
end
def draw(object)
- if object.in_bounds?(width, height)
- points = object.get_points
- points.each { |point| set_pixel(point.x, point.y) }
- else
- raise OutOfBounds, "The object is out of canvas' bounds"
- end
+ points = object.points
+ points.each { |point| set_pixel(point.x, point.y) }
end
def render_as(renderer)
- renderer.render(@canvas)
+ output = renderer::HEADER
+ output << renderer.render_canvas(self)
+ output << renderer::FOOTER
end
end
end
  • Не ми харесва да базираш hash методите на низ, виж аз как съм го направил в моето решение.
  • Окей е pixel_at? да връща nil, вместо false.
  • Представянето на пано можеше да е просто един хеш, като ключът е списък с двете координати. Виж моето решение за справка.
  • Ако искаш да имаш хеш от хешове, което е по-бързо, прави се така: @canvas = Hash.new { |hash, key| hash[key] = {} }.
  • Не виждам смисъл от променливата points на ред 248.
  • Не виждам OutOfBounds да се ползва някъде.

Другите неща са станали горе-долу прилични, но има още места, които могат да се подобрят. Виж моето решение за справка.