Иван обнови решението на 21.12.2013 23:11 (преди почти 11 години)
+module Graphics
+ module Renderers
+ class Html
+ def self.key
+ :html
+ end
+
+ def self.start
+ "<!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\">\n"
+ end
+
+ def self.end
+ " </div>
+ </body>
+ </html>"
+ end
+ end
+
+ class Ascii
+ def self.key
+ :ascii
+ end
+ end
+ end
+
+ class Canvas
+ attr_reader :width, :height
+
+ def initialize(width, height)
+ @width = width
+ @height = height
+ @world = Array.new(height).map { |height| height = Array.new(width) }
+ @rendered = ""
+ end
+
+ def set_pixel(x, y)
+ @world[y][x] = true
+ end
+
+ def pixel_at?(x, y)
+ @world[y][x]
+ end
+
+ def draw(object)
+ object.set_points
+ object.coordinates.each { |point| @world[point.last][point.first] = true }
+ end
+
+ def render_as(render)
+ if render.key == :ascii
+ render_as_ascii(render, "\n", "@", "-")
+ elsif render.key == :html
+ render_as_html(render, "<br>\n", "<b></b>", "<i></i>")
+ end
+ end
+
+ def render_as_ascii(render, new_line, point, empty)
+ @rendered = ""
+ render_line_as(new_line, point, empty)
+ @rendered
+ end
+
+ def render_as_html(render, new_line, point, empty)
+ @rendered = ""
+ render_line_as(new_line, point, empty)
+ render.start + @rendered + render.end
+ end
+
+ def render_line_as(new_line, point, empty)
+ @world.each do |line|
+ render_line_item_as(line, point, empty)
+ @rendered += new_line
+ end
+ end
+
+ def render_line_item_as(line, point, empty)
+ line.each { |item| replace(item, point, empty) }
+ end
+
+ def replace(item, point, empty)
+ item ? @rendered += point : @rendered += empty
+ end
+
+ end
+
+ class Point
+ attr_reader :x, :y, :coordinates
+
+ def initialize(x, y)
+ @x = x
+ @y = y
+ @coordinates = []
+ end
+
+ def set_points
+ @coordinates << [x, y]
+ end
+ end
+
+ class Line
+ attr_reader :from, :to, :coordinates
+
+ def initialize(first, second)
+ @coordinates = []
+ @from = vertical(first, second) ? upper(first, second) : left(first, second)
+ @to = @from == first ? second : first
+ end
+
+ def upper(first, second)
+ first.y <= second.y ? first : second
+ end
+
+ def left(first, second)
+ first.x <= second.x ? first : second
+ end
+
+ def vertical(first, second)
+ first.x - second.x == 0
+ end
+
+ def set_points
+ if vertical(from, to)
+ from.y.upto(to.y).each { |point| @coordinates << [from.x, point] }
+ else
+ from.x.upto(to.x).each { |point| @coordinates << [point, from.y] }
+ end
+ end
+
+ end
+
+ class Rectangle
+ attr_reader :left, :right, :coordinates
+
+ def initialize(first, second)
+ @left = vertical(first, second) ? upper(first, second) : left_point(first, second)
+ @right = @left == first ? second : first
+ @coordinates = []
+ @height = (right.y - left.y).abs
+ @width = (right.x - left.x).abs
+ end
+
+ def vertical(first, second)
+ first.x - second.x == 0
+ end
+
+ def upper(first, second)
+ first.y <= second.y ? first : second
+ end
+
+ def left_point(first, second)
+ first.x <= second.x ? first : second
+ end
+
+ def top_left
+ right.y - left.y < 0 ? Point.new(left.y - @height, right.y) : left
+ end
+
+ def top_right
+ @width == 0 ? top_left : Point.new(top_left.x + @width, top_left.y)
+ end
+
+ def bottom_left
+ right.y - left.y < 0 ? left : Point.new(left.x, left.y + @height)
+ end
+
+ def bottom_right
+ @width == 0 ? bottom_left : Point.new(bottom_left.x + @width, bottom_left.y)
+ end
+
+ def set_points
+ top_left.y.upto(bottom_left.y).each do |point|
+ @coordinates << [top_left.x, point]
+ @coordinates << [top_right.x, point]
+ end
+
+ top_left.x.upto(top_right.x).each do |point|
+ @coordinates << [point, top_left.y]
+ @coordinates << [point, bottom_left.y]
+ end
+ end
+ end
+end