Цани обнови решението на 22.12.2013 22:14 (преди почти 11 години)
+module Graphics
+ class Canvas #ако исках да рисувам на пано щях да кажа на майка ми да ме научи
+ attr_reader :width, :height
+
+ def initialize (width, height)
+ @width = width
+ @height = height
+ @buffer = Array.new(height) { "0"*width }
+ end
+
+ def draw (figure)
+ set_all(figure.get_pixels)
+ end
+
+ def set_pixel (x, y)
+ @buffer[y][x] = "1"
+ end
+
+ def set_all (pixels)
+ pixels.each do |pixel|
+ set_pixel(pixel.x, pixel.y)
+ end
+ end
+
+ def pixel_at (x, y)
+ @buffer[x][y] == "1"
+ end
+
+ def render_as (renderer)
+ renderer.render(self)
+ end
+
+ def get_parsed_buffer (separator, empty, filled)
+ @buffer.join(separator).gsub("0",empty).gsub("1",filled)
+ end
+ end
+ module Renderers
+ class Ascii
+ def self.render (canvas)
+ canvas.get_parsed_buffer("\n","-","@")
+ end
+ end
+ class Html
+ @@top_html = '<!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">'
+ @@bottom_html ='</div>
+ </body>
+ </html>'
+
+ def self.render (canvas)
+ @@TOP_HTML + canvas.get_parsed_buffer("<br>","<i></i>","<b></b>") + @@BOTTOM_HTML
+ end
+ end
+ end
+ class Point
+ attr_reader :x, :y
+ def initialize (x, y)
+ @x = x
+ @y = y
+ end
+
+ def get_pixels
+ [self]
+ end
+
+ def hash
+ [x, y].hash
+ end
+
+ def distance other
+ @x - other.x + @y - other.y
+ end
+
+ def == other
+ hash == other.hash
+ end
+
+ alias_method :eql?, :==
+ end
+
+ class Line
+ attr_reader :from, :to
+ def initialize (a, b)
+ @from = (a.x < b.x || (a.x == b.x && a.y < b.y)) ? a : b
+ @to = @from.equal?(a) ? b : a
+ @top = (a.y < b.y || (a.y == b.y && a.x < b.x)) ? a : b
+ @bottom = @top.equal?(a) ? b : a
+ end
+
+ def get_pixels
+ return get_pixels_by_row if @to.x == @from.x
+ slope = (@to.y.to_f - @from.y)/(@to.x - @from.x)
+ return get_pixels_by_column if slope.abs < 1
+ return get_pixels_by_row
+ end
+
+ def get_pixels_by_row
+ slope = (@to.x.to_f - @from.x)/(@to.y - @from.y)
+ pixels = []
+ (@top.y..@bottom.y).each do |row|
+ pixels << Point.new((slope*(row - @from.y) + @from.x).round, row)
+ end
+ pixels
+ end
+
+ def get_pixels_by_column
+ slope = (@to.y.to_f - @from.y)/(@to.x - @from.x)
+ pixels = []
+ (@from.x..@to.x).each do |column|
+ pixels << Point.new(column, (slope*(column - @from.x) + @from.y).round)
+ end
+ pixels
+ end
+
+ def hash
+ @from.hash + @from.distance(@to)*@to.hash
+ end
+ end
+ class Rectangle
+ attr_reader :left, :right, :top_left, :top_right, :bottom_left, :bottom_right
+ def initialize (a, b)
+ @left = (a.x < b.x || (a.x == b.x && a.y < b.y)) ? a : b
+ @right = @left == a ? b : a
+ @top_left = Point.new(@left.x, @left.y < @right.y ? @left.y : @right.y)
+ @top_right = Point.new(@right.x, @left.y < @right.y ? @left.y : @right.y)
+ @bottom_left = Point.new(@left.x, @left.y >= @right.y ? @left.y : @right.y)
+ @bottom_right = Point.new(@right.x, @left.y >= @right.y ? @left.y : @right.y)
+ end
+
+ def hash
+ hash = @left.hash
+ hash += @left.distance(@right)*@right.hash
+ walls_hash = @top_left.distance(@bottom_left)*@bottom_left.hash
+ walls_hash *= @top_left.distance(@top_right)*@top_right.hash
+ hash += walls_hash
+ end
+
+ def get_pixels
+ pixels = []
+ #add_top pixels, ама това се събира в 90 символа
+ (@top_left.x..@top_right.x).each {|column| pixels << Point.new(column,@top_left.y)}
+ add_walls pixels #<3 макс 6 реда и макс 90 символа
+ add_bottom pixels
+ pixels
+ end
+
+ def add_walls pixels
+ (@top_left.y+1..@bottom_left.y-1).each do |row|
+ pixels<<Point.new(@left.x,row)<<Point.new(@right.x,row)
+ end
+ end
+
+ def add_bottom pixels
+ (@bottom_left.x..@bottom_right.x).each do |column|
+ pixels << Point.new(column,@bottom_left.y)
+ end
+ end
+
+ private :add_walls, :add_bottom
+ end
+end