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

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

Към профила на Кристиан Ташков

Резултати

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

Код

require 'set'
module Graphics
module Renderers
module Ascii
end
module Html
end
end
class Canvas
HTML_TEMPLATE = "<!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\">
@canvas@
</div>
</body>
</html>"
attr_reader :width
attr_reader :height
def initialize(width, height)
@pixels = Set.new []
@width = width
@height = height
end
def set_pixel(x, y)
@pixels.add [x, y]
end
def pixel_at?(x, y)
@pixels.include? [x, y]
end
def draw(figure)
set_pixel(figure.x, figure.y) if figure.instance_of? Point
draw_line(figure) if figure.instance_of? Line
draw_rectangle(figure) if figure.instance_of? Rectangle
end
def draw_rectangle(rectangle)
draw_line(Line.new(rectangle.top_left, rectangle.top_right))
draw_line(Line.new(rectangle.top_left, rectangle.bottom_left))
draw_line(Line.new(rectangle.top_right, rectangle.bottom_right))
draw_line(Line.new(rectangle.bottom_left, rectangle.bottom_right))
end
def draw_line(line)
set_pixel(line.from.x, line.from.y)
bresenham(line)
end
def bresenham(line)
x, y, delta_x, delta_y, step_x, step_y, error = bresenham_initial_variables(line)
until (x == line.to.x && y == line.to.y)
y, error_change_x = bresenham_x_check(y, 2 * error, step_y, delta_x)
x, error_change_y = bresenham_y_check(x, 2 * error, step_x, delta_y)
error += error_change_x + error_change_y
set_pixel(x, y)
end
end
def bresenham_x_check(y, error, step_y, delta_x)
error_change = 0
if error <= delta_x
y += step_y
error_change += delta_x
end
[y, error_change]
end
def bresenham_y_check(x, error, step_x, delta_y)
error_change = 0
if error >= delta_y
x += step_x
error_change += delta_y
end
[x, error_change]
end
def bresenham_initial_variables(line)
delta_x = (line.to.x - line.from.x).abs
delta_y = -(line.to.y - line.from.y).abs
step_x = line.from.x < line.to.x ? 1 : -1
step_y = line.from.y < line.to.y ? 1 : -1
error = delta_x + delta_y
[line.from.x, line.from.y, delta_x, delta_y, step_x, step_y, error]
end
def render_as(renderer)
if renderer == Renderers::Ascii
render_with_symbols('@', '-', "\n")
elsif renderer == Renderers::Html
template = HTML_TEMPLATE
template.gsub("@canvas@", render_with_symbols("<b></b>", "<i></i>", "<br>\n"))
end
end
def render_with_symbols(filled, empty, line_end)
symbol_for_pixel = lambda { |x, y| pixel_at?(x, y) ? filled : empty }
rows = 0.upto(width * height - 1).each_slice(width).map do |row|
row.map do |pixel|
symbol_for_pixel.call(pixel.remainder(width), pixel.div(width))
end
end
rows.map(&:join).join(line_end)
end
end
class Point
attr_reader :x
attr_reader :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
x == other.x &&
y == other.y
end
def eql?(other)
self == other
end
def hash
x.hash ^ y.hash
end
def left_compared_to?(other)
return true if x < other.x
return false if x > other.x
return y < other.y
end
end
class Line
attr_reader :from
attr_reader :to
def initialize(from, to)
from, to = to, from if to.left_compared_to? from
@from = from
@to = to
end
def ==(other)
(from == other.from) &&
(to == other.to)
end
def eql?(other)
self == other
end
def hash
@from.hash ^ @to.hash
end
end
class Rectangle
attr_reader :left
attr_reader :right
attr_reader :top_left
attr_reader :top_right
attr_reader :bottom_left
attr_reader :bottom_right
def initialize(a, b)
@left = Line.new(a, b).from
@right = Line.new(a, b).to
@top_left = Point.new([left.x, right.x].min, [left.y, right.y].min)
@top_right = Point.new([left.x, right.x].max, [left.y, right.y].min)
@bottom_left = Point.new([left.x, right.x].min, [left.y, right.y].max)
@bottom_right = Point.new([left.x, right.x].max, [left.y, right.y].max)
end
def ==(other)
top_left == other.top_left &&
top_right == other.top_right &&
bottom_left == other.bottom_left &&
bottom_right == other.bottom_right
end
def eql?(other)
self == other
end
def hash
@top_left.hash ^ @top_right.hash ^ @bottom_left.hash ^ @bottom_right.hash
end
end
end

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

................................................................F....

Failures:

  1) Graphics shapes Rectangle comparison for equality returns a different hash if the rectangles differ
     Failure/Error: a.hash.should_not eq b.hash
       
       expected: value != 0
            got: 0
       
       (compared using ==)
     # /tmp/d20131223-4637-ifq80c/spec.rb:570: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.09542 seconds
69 examples, 1 failure

Failed examples:

rspec /tmp/d20131223-4637-ifq80c/spec.rb:566 # Graphics shapes Rectangle comparison for equality returns a different hash if the rectangles differ

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

Кристиан обнови решението на 22.12.2013 20:49 (преди почти 11 години)

+require 'set'
+
+module Graphics
+ module Renderers
+ module Ascii
+ end
+ module Html
+ end
+ end
+
+ class Canvas
+ HTML_TEMPLATE = "<!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\">
+@canvas@
+ </div>
+ </body>
+</html>"
+
+ attr_reader :width
+ attr_reader :height
+ def initialize(width, height)
+ @pixels = Set.new []
+ @width = width
+ @height = height
+ end
+
+ def set_pixel(x, y)
+ @pixels.add [x, y]
+ end
+
+ def pixel_at?(x, y)
+ @pixels.include? [x, y]
+ end
+
+ def draw(figure)
+ draw_point(figure) if figure.instance_of? Point
+ draw_line(figure) if figure.instance_of? Line
+ draw_rectangle(figure) if figure.instance_of? Rectangle
+ end
+
+ def draw_point(point)
+ set_pixel(point.x, point.y)
+ end
+
+ def draw_rectangle(rectangle)
+ draw_line(Line.new(rectangle.top_left, rectangle.top_right))
+ draw_line(Line.new(rectangle.top_left, rectangle.bottom_left))
+ draw_line(Line.new(rectangle.top_right, rectangle.bottom_right))
+ draw_line(Line.new(rectangle.bottom_left, rectangle.bottom_right))
+ end
+
+ def draw_line(line)
+ set_pixel(line.from.x, line.from.y)
+ bresenham(line)
+ end
+
+ def bresenham(line)
+ x, y, delta_x, delta_y, step_x, step_y, error = bresenham_initial_variables(line)
+ until (x == line.to.x && y == line.to.y)
+ x, y = 2 * error >= delta_y ? [x + step_x, y] : [x, y + step_y]
+ error = 2 * error >= delta_y ? error + delta_y : error + delta_x
+ set_pixel(x, y)
+ end
+ end
+
+ def bresenham_initial_variables(line)
+ delta_x = (line.to.x - line.from.x).abs
+ delta_y = -(line.to.y - line.from.y).abs
+ step_x = line.from.x < line.to.x ? 1 : -1
+ step_y = line.from.y < line.to.y ? 1 : -1
+ error = delta_x + delta_y
+ [line.from.x, line.from.y, delta_x, delta_y, step_x, step_y, error]
+ end
+
+ def render_as(renderer)
+ if renderer == Renderers::Ascii
+ render_with_symbols('@', '-', "\n")
+ elsif renderer == Renderers::Html
+ template = HTML_TEMPLATE
+ template.gsub("@canvas@", render_with_symbols("<b></b>", "<i></i>", "<br>\n"))
+ end
+ end
+
+ def render_with_symbols(filled, empty, line_end)
+ rows = 0.upto(width * height - 1).each_slice(width).map do |row|
+ row.map do |pixel|
+ symbol_for_pixel(pixel.remainder(width), pixel.div(width), filled, empty)
+ end
+ end
+ rows.map(&:join).join(line_end)
+ end
+
+ def symbol_for_pixel(x, y, filled, empty)
+ pixel_at?(x, y) ? filled : empty
+ end
+ end
+
+ class Point
+ attr_reader :x
+ attr_reader :y
+
+ def initialize(x, y)
+ @x = x
+ @y = y
+ end
+
+ def ==(other)
+ x == other.x && y == other.y
+ end
+
+ def eql?(other)
+ self == other
+ end
+
+ def hash
+ x.hash ^ y.hash
+ end
+
+ def left_compared_to?(other)
+ return true if x < other.x
+ return false if x > other.x
+ return y < other.y
+ end
+ end
+
+ class Line
+ attr_reader :from
+ attr_reader :to
+ def initialize(from, to)
+ from, to = to, from if to.left_compared_to? from
+ @from = from
+ @to = to
+ end
+
+ def ==(other)
+ (from == other.from) && (to == other.to)
+ end
+
+ def eql?(other)
+ self == other
+ end
+
+ def hash
+ @from.hash ^ @to.hash
+ end
+ end
+
+ class Rectangle
+ attr_reader :left
+ attr_reader :right
+ attr_reader :top_left
+ attr_reader :top_right
+ attr_reader :bottom_left
+ attr_reader :bottom_right
+
+ def initialize(a, b)
+ @left = Line.new(a, b).from
+ @right = Line.new(a, b).to
+ @top_left = Point.new([left.x, right.x].min, [left.y, right.y].min)
+ @top_right = Point.new([left.x, right.x].max, [left.y, right.y].min)
+ @bottom_left = Point.new([left.x, right.x].min, [left.y, right.y].max)
+ @bottom_right = Point.new([left.x, right.x].max, [left.y, right.y].max)
+ end
+
+ def ==(other)
+ top_left == other.top_left &&
+ top_right == other.top_right &&
+ bottom_left == other.bottom_left &&
+ bottom_right == other.bottom_right
+ end
+
+ def eql?(other)
+ self == other
+ end
+
+ def hash
+ @top_left.hash ^ @top_right.hash ^ @bottom_left.hash ^ @bottom_right.hash
+ end
+ end
+end

Кристиан обнови решението на 22.12.2013 21:42 (преди почти 11 години)

require 'set'
module Graphics
module Renderers
module Ascii
end
module Html
end
end
class Canvas
HTML_TEMPLATE = "<!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\">
@canvas@
</div>
</body>
</html>"
attr_reader :width
attr_reader :height
def initialize(width, height)
@pixels = Set.new []
@width = width
@height = height
end
def set_pixel(x, y)
@pixels.add [x, y]
end
def pixel_at?(x, y)
@pixels.include? [x, y]
end
def draw(figure)
- draw_point(figure) if figure.instance_of? Point
+ set_pixel(figure.x, figure.y) if figure.instance_of? Point
draw_line(figure) if figure.instance_of? Line
draw_rectangle(figure) if figure.instance_of? Rectangle
end
- def draw_point(point)
- set_pixel(point.x, point.y)
- end
-
def draw_rectangle(rectangle)
draw_line(Line.new(rectangle.top_left, rectangle.top_right))
draw_line(Line.new(rectangle.top_left, rectangle.bottom_left))
draw_line(Line.new(rectangle.top_right, rectangle.bottom_right))
draw_line(Line.new(rectangle.bottom_left, rectangle.bottom_right))
end
def draw_line(line)
set_pixel(line.from.x, line.from.y)
bresenham(line)
end
def bresenham(line)
x, y, delta_x, delta_y, step_x, step_y, error = bresenham_initial_variables(line)
until (x == line.to.x && y == line.to.y)
- x, y = 2 * error >= delta_y ? [x + step_x, y] : [x, y + step_y]
- error = 2 * error >= delta_y ? error + delta_y : error + delta_x
+ y, error_change_x = bresenham_x_check(y, 2 * error, step_y, delta_x)
+ x, error_change_y = bresenham_y_check(x, 2 * error, step_x, delta_y)
+ error += error_change_x + error_change_y
set_pixel(x, y)
end
end
+ def bresenham_x_check(y, error, step_y, delta_x)
+ error_change = 0
+ if error <= delta_x
+ y += step_y
+ error_change += delta_x
+ end
+ [y, error_change]
+ end
+
+ def bresenham_y_check(x, error, step_x, delta_y)
+ error_change = 0
+ if error >= delta_y
+ x += step_x
+ error_change += delta_y
+ end
+ [x, error_change]
+ end
+
def bresenham_initial_variables(line)
delta_x = (line.to.x - line.from.x).abs
delta_y = -(line.to.y - line.from.y).abs
step_x = line.from.x < line.to.x ? 1 : -1
step_y = line.from.y < line.to.y ? 1 : -1
error = delta_x + delta_y
[line.from.x, line.from.y, delta_x, delta_y, step_x, step_y, error]
end
def render_as(renderer)
if renderer == Renderers::Ascii
render_with_symbols('@', '-', "\n")
elsif renderer == Renderers::Html
template = HTML_TEMPLATE
template.gsub("@canvas@", render_with_symbols("<b></b>", "<i></i>", "<br>\n"))
end
end
def render_with_symbols(filled, empty, line_end)
+ symbol_for_pixel = lambda { |x, y| pixel_at?(x, y) ? filled : empty }
rows = 0.upto(width * height - 1).each_slice(width).map do |row|
row.map do |pixel|
- symbol_for_pixel(pixel.remainder(width), pixel.div(width), filled, empty)
+ symbol_for_pixel.call(pixel.remainder(width), pixel.div(width))
end
end
rows.map(&:join).join(line_end)
end
-
- def symbol_for_pixel(x, y, filled, empty)
- pixel_at?(x, y) ? filled : empty
- end
end
class Point
attr_reader :x
attr_reader :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
x == other.x && y == other.y
end
def eql?(other)
self == other
end
def hash
x.hash ^ y.hash
end
def left_compared_to?(other)
return true if x < other.x
return false if x > other.x
return y < other.y
end
end
class Line
attr_reader :from
attr_reader :to
def initialize(from, to)
from, to = to, from if to.left_compared_to? from
@from = from
@to = to
end
def ==(other)
(from == other.from) && (to == other.to)
end
def eql?(other)
self == other
end
def hash
@from.hash ^ @to.hash
end
end
class Rectangle
attr_reader :left
attr_reader :right
attr_reader :top_left
attr_reader :top_right
attr_reader :bottom_left
attr_reader :bottom_right
def initialize(a, b)
@left = Line.new(a, b).from
@right = Line.new(a, b).to
@top_left = Point.new([left.x, right.x].min, [left.y, right.y].min)
@top_right = Point.new([left.x, right.x].max, [left.y, right.y].min)
@bottom_left = Point.new([left.x, right.x].min, [left.y, right.y].max)
@bottom_right = Point.new([left.x, right.x].max, [left.y, right.y].max)
end
def ==(other)
top_left == other.top_left &&
top_right == other.top_right &&
bottom_left == other.bottom_left &&
bottom_right == other.bottom_right
end
def eql?(other)
self == other
end
def hash
@top_left.hash ^ @top_right.hash ^ @bottom_left.hash ^ @bottom_right.hash
end
end
+end
+
+module Graphics
+ canvas = Canvas.new 30, 30
+
+ # Door frame and window
+ canvas.draw Rectangle.new(Point.new(3, 3), Point.new(18, 12))
+ canvas.draw Rectangle.new(Point.new(1, 1), Point.new(20, 28))
+
+ # Door knob
+ canvas.draw Line.new(Point.new(4, 15), Point.new(7, 15))
+ canvas.draw Point.new(4, 16)
+
+ # Big "R"
+ canvas.draw Line.new(Point.new(8, 5), Point.new(8, 10))
+ canvas.draw Line.new(Point.new(9, 5), Point.new(12, 5))
+ canvas.draw Line.new(Point.new(9, 7), Point.new(12, 7))
+ canvas.draw Point.new(13, 6)
+ canvas.draw Line.new(Point.new(12, 8), Point.new(13, 10))
+
+ puts canvas.render_as(Renderers::Ascii)
end

Кристиан обнови решението на 22.12.2013 21:42 (преди почти 11 години)

require 'set'
module Graphics
module Renderers
module Ascii
end
module Html
end
end
class Canvas
HTML_TEMPLATE = "<!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\">
@canvas@
</div>
</body>
</html>"
attr_reader :width
attr_reader :height
def initialize(width, height)
@pixels = Set.new []
@width = width
@height = height
end
def set_pixel(x, y)
@pixels.add [x, y]
end
def pixel_at?(x, y)
@pixels.include? [x, y]
end
def draw(figure)
set_pixel(figure.x, figure.y) if figure.instance_of? Point
draw_line(figure) if figure.instance_of? Line
draw_rectangle(figure) if figure.instance_of? Rectangle
end
def draw_rectangle(rectangle)
draw_line(Line.new(rectangle.top_left, rectangle.top_right))
draw_line(Line.new(rectangle.top_left, rectangle.bottom_left))
draw_line(Line.new(rectangle.top_right, rectangle.bottom_right))
draw_line(Line.new(rectangle.bottom_left, rectangle.bottom_right))
end
def draw_line(line)
set_pixel(line.from.x, line.from.y)
bresenham(line)
end
def bresenham(line)
x, y, delta_x, delta_y, step_x, step_y, error = bresenham_initial_variables(line)
until (x == line.to.x && y == line.to.y)
y, error_change_x = bresenham_x_check(y, 2 * error, step_y, delta_x)
x, error_change_y = bresenham_y_check(x, 2 * error, step_x, delta_y)
error += error_change_x + error_change_y
set_pixel(x, y)
end
end
def bresenham_x_check(y, error, step_y, delta_x)
error_change = 0
if error <= delta_x
y += step_y
error_change += delta_x
end
[y, error_change]
end
def bresenham_y_check(x, error, step_x, delta_y)
error_change = 0
if error >= delta_y
x += step_x
error_change += delta_y
end
[x, error_change]
end
def bresenham_initial_variables(line)
delta_x = (line.to.x - line.from.x).abs
delta_y = -(line.to.y - line.from.y).abs
step_x = line.from.x < line.to.x ? 1 : -1
step_y = line.from.y < line.to.y ? 1 : -1
error = delta_x + delta_y
[line.from.x, line.from.y, delta_x, delta_y, step_x, step_y, error]
end
def render_as(renderer)
if renderer == Renderers::Ascii
render_with_symbols('@', '-', "\n")
elsif renderer == Renderers::Html
template = HTML_TEMPLATE
template.gsub("@canvas@", render_with_symbols("<b></b>", "<i></i>", "<br>\n"))
end
end
def render_with_symbols(filled, empty, line_end)
symbol_for_pixel = lambda { |x, y| pixel_at?(x, y) ? filled : empty }
rows = 0.upto(width * height - 1).each_slice(width).map do |row|
row.map do |pixel|
symbol_for_pixel.call(pixel.remainder(width), pixel.div(width))
end
end
rows.map(&:join).join(line_end)
end
end
class Point
attr_reader :x
attr_reader :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
x == other.x && y == other.y
end
def eql?(other)
self == other
end
def hash
x.hash ^ y.hash
end
def left_compared_to?(other)
return true if x < other.x
return false if x > other.x
return y < other.y
end
end
class Line
attr_reader :from
attr_reader :to
def initialize(from, to)
from, to = to, from if to.left_compared_to? from
@from = from
@to = to
end
def ==(other)
(from == other.from) && (to == other.to)
end
def eql?(other)
self == other
end
def hash
@from.hash ^ @to.hash
end
end
class Rectangle
attr_reader :left
attr_reader :right
attr_reader :top_left
attr_reader :top_right
attr_reader :bottom_left
attr_reader :bottom_right
def initialize(a, b)
@left = Line.new(a, b).from
@right = Line.new(a, b).to
@top_left = Point.new([left.x, right.x].min, [left.y, right.y].min)
@top_right = Point.new([left.x, right.x].max, [left.y, right.y].min)
@bottom_left = Point.new([left.x, right.x].min, [left.y, right.y].max)
@bottom_right = Point.new([left.x, right.x].max, [left.y, right.y].max)
end
def ==(other)
top_left == other.top_left &&
top_right == other.top_right &&
bottom_left == other.bottom_left &&
bottom_right == other.bottom_right
end
def eql?(other)
self == other
end
def hash
@top_left.hash ^ @top_right.hash ^ @bottom_left.hash ^ @bottom_right.hash
end
end
-end
-
-module Graphics
- canvas = Canvas.new 30, 30
-
- # Door frame and window
- canvas.draw Rectangle.new(Point.new(3, 3), Point.new(18, 12))
- canvas.draw Rectangle.new(Point.new(1, 1), Point.new(20, 28))
-
- # Door knob
- canvas.draw Line.new(Point.new(4, 15), Point.new(7, 15))
- canvas.draw Point.new(4, 16)
-
- # Big "R"
- canvas.draw Line.new(Point.new(8, 5), Point.new(8, 10))
- canvas.draw Line.new(Point.new(9, 5), Point.new(12, 5))
- canvas.draw Line.new(Point.new(9, 7), Point.new(12, 7))
- canvas.draw Point.new(13, 6)
- canvas.draw Line.new(Point.new(12, 8), Point.new(13, 10))
-
- puts canvas.render_as(Renderers::Ascii)
end

Кристиан обнови решението на 22.12.2013 21:45 (преди почти 11 години)

require 'set'
module Graphics
module Renderers
module Ascii
end
module Html
end
end
class Canvas
HTML_TEMPLATE = "<!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\">
@canvas@
</div>
</body>
</html>"
attr_reader :width
attr_reader :height
def initialize(width, height)
@pixels = Set.new []
- @width = width
+ @width = width
@height = height
end
def set_pixel(x, y)
@pixels.add [x, y]
end
def pixel_at?(x, y)
@pixels.include? [x, y]
end
def draw(figure)
set_pixel(figure.x, figure.y) if figure.instance_of? Point
draw_line(figure) if figure.instance_of? Line
draw_rectangle(figure) if figure.instance_of? Rectangle
end
def draw_rectangle(rectangle)
draw_line(Line.new(rectangle.top_left, rectangle.top_right))
draw_line(Line.new(rectangle.top_left, rectangle.bottom_left))
draw_line(Line.new(rectangle.top_right, rectangle.bottom_right))
draw_line(Line.new(rectangle.bottom_left, rectangle.bottom_right))
end
def draw_line(line)
set_pixel(line.from.x, line.from.y)
bresenham(line)
end
def bresenham(line)
x, y, delta_x, delta_y, step_x, step_y, error = bresenham_initial_variables(line)
until (x == line.to.x && y == line.to.y)
y, error_change_x = bresenham_x_check(y, 2 * error, step_y, delta_x)
x, error_change_y = bresenham_y_check(x, 2 * error, step_x, delta_y)
error += error_change_x + error_change_y
set_pixel(x, y)
end
end
def bresenham_x_check(y, error, step_y, delta_x)
error_change = 0
if error <= delta_x
y += step_y
error_change += delta_x
end
[y, error_change]
end
def bresenham_y_check(x, error, step_x, delta_y)
error_change = 0
if error >= delta_y
x += step_x
error_change += delta_y
end
[x, error_change]
end
def bresenham_initial_variables(line)
- delta_x = (line.to.x - line.from.x).abs
- delta_y = -(line.to.y - line.from.y).abs
- step_x = line.from.x < line.to.x ? 1 : -1
- step_y = line.from.y < line.to.y ? 1 : -1
- error = delta_x + delta_y
+ delta_x = (line.to.x - line.from.x).abs
+ delta_y = -(line.to.y - line.from.y).abs
+ step_x = line.from.x < line.to.x ? 1 : -1
+ step_y = line.from.y < line.to.y ? 1 : -1
+ error = delta_x + delta_y
[line.from.x, line.from.y, delta_x, delta_y, step_x, step_y, error]
end
def render_as(renderer)
if renderer == Renderers::Ascii
render_with_symbols('@', '-', "\n")
elsif renderer == Renderers::Html
template = HTML_TEMPLATE
template.gsub("@canvas@", render_with_symbols("<b></b>", "<i></i>", "<br>\n"))
end
end
def render_with_symbols(filled, empty, line_end)
symbol_for_pixel = lambda { |x, y| pixel_at?(x, y) ? filled : empty }
rows = 0.upto(width * height - 1).each_slice(width).map do |row|
row.map do |pixel|
symbol_for_pixel.call(pixel.remainder(width), pixel.div(width))
end
end
rows.map(&:join).join(line_end)
end
end
class Point
attr_reader :x
attr_reader :y
def initialize(x, y)
@x = x
@y = y
end
def ==(other)
- x == other.x && y == other.y
+ x == other.x &&
+ y == other.y
end
def eql?(other)
self == other
end
def hash
x.hash ^ y.hash
end
def left_compared_to?(other)
return true if x < other.x
return false if x > other.x
return y < other.y
end
end
class Line
attr_reader :from
attr_reader :to
def initialize(from, to)
from, to = to, from if to.left_compared_to? from
- @from = from
- @to = to
+ @from = from
+ @to = to
end
def ==(other)
- (from == other.from) && (to == other.to)
+ (from == other.from) &&
+ (to == other.to)
end
def eql?(other)
self == other
end
def hash
@from.hash ^ @to.hash
end
end
class Rectangle
attr_reader :left
attr_reader :right
attr_reader :top_left
attr_reader :top_right
attr_reader :bottom_left
attr_reader :bottom_right
def initialize(a, b)
- @left = Line.new(a, b).from
- @right = Line.new(a, b).to
- @top_left = Point.new([left.x, right.x].min, [left.y, right.y].min)
- @top_right = Point.new([left.x, right.x].max, [left.y, right.y].min)
- @bottom_left = Point.new([left.x, right.x].min, [left.y, right.y].max)
+ @left = Line.new(a, b).from
+ @right = Line.new(a, b).to
+ @top_left = Point.new([left.x, right.x].min, [left.y, right.y].min)
+ @top_right = Point.new([left.x, right.x].max, [left.y, right.y].min)
+ @bottom_left = Point.new([left.x, right.x].min, [left.y, right.y].max)
@bottom_right = Point.new([left.x, right.x].max, [left.y, right.y].max)
end
def ==(other)
- top_left == other.top_left &&
- top_right == other.top_right &&
- bottom_left == other.bottom_left &&
+ top_left == other.top_left &&
+ top_right == other.top_right &&
+ bottom_left == other.bottom_left &&
bottom_right == other.bottom_right
end
def eql?(other)
self == other
end
def hash
@top_left.hash ^ @top_right.hash ^ @bottom_left.hash ^ @bottom_right.hash
end
end
end