Пепа обнови решението на 02.12.2015 02:50 (преди около 9 години)
+require 'ostruct'
+
+module TurtleGraphics
+ class Turtle
+ attr_accessor :canvas, :head
+
+ def initialize(rows, columns)
+ @canvas = Canvas::Canvas.new(rows, columns)
+ @head = OpenStruct.new(x: 0, y: 0)
+ @direction = OpenStruct.new(front: :right, left: :up)
+
+ spawn_at(0, 0)
+ end
+
+ def turn_right
+ left = @direction.front
+ @direction.front = opposite_direction(@direction.left)
+ @direction.left = left
+ end
+
+ def turn_left
+ left = opposite_direction(@direction.front)
+ @direction.front = @direction.left
+ @direction.left = left
+ end
+
+ def move
+ case @direction.front
+ when :right
+ @head.x = inside(:row, @head.x + 1) ? @head.x + 1 : 0
+ when :left
+ @head.x = inside(:row, @head.x - 1) ? @head.x - 1 : @canvas.columns - 1
+ when :up
+ @head.y = inside(:column, @head.y - 1) ? @head.y - 1 : @canvas.rows - 1
+ when :down
+ @head.y = inside(:column, @head.y + 1) ? @head.y + 1 : 0
+ end
+
+ @canvas.step(@head)
+ end
+
+ def inside(part, number)
+ if part == :row
+ number < @canvas.columns
+ else
+ number < @canvas.rows
+ end
+ end
+
+ def spawn_at(row, column)
+ @canvas.canvas[0][0] = 0
+ @head.x = column
+ @head.y = row
+ @canvas.canvas[row][column] += 1
+ look(:right)
+ end
+
+ def look(orientation)
+ if @direction.front == opposite_direction(orientation)
+ 2.times { turn_left }
+ elsif @direction.left == orientation
+ turn_left
+ elsif @direction.left == opposite_direction(orientation)
+ turn_right
+ end
+ end
+
+ def draw(painter = self, &block)
+ self.instance_eval(&block)
+
+ if painter.kind_of?(Canvas::ASCII)
+ painter.set_max_steps(@canvas.max_steps)
+ painter.draw(self.canvas.canvas)
+ elsif painter.kind_of?(Canvas::HTML)
+ else
+ self.canvas.canvas
+ end
+ end
+
+ private
+
+ def opposite_direction(direction)
+ return case direction
+ when :right then :left
+ when :left then :right
+ when :up then :down
+ when :down then :up
+ end
+ end
+ end
+
+ module Canvas
+
+ class Canvas
+ attr_accessor :canvas, :max_steps, :rows, :columns
+
+ def initialize(rows, columns)
+ @rows = rows
+ @columns = columns
+ @canvas = Array.new(rows) {Array.new(columns) {0}}
+ @max_steps = 0
+ end
+
+ def step(position)
+ @canvas[position.y][position.x] += 1
+ if @canvas[position.y][position.x] > @max_steps
+ @max_steps = @canvas[position.y][position.x]
+ end
+ end
+ end
+
+ class ASCII
+
+ def initialize(symbols)
+ @symbols = symbols
+ @interval_length = 1.0 / (@symbols.length - 1).to_f
+ end
+
+ def set_max_steps(max_steps)
+ @max_steps = max_steps.to_f
+ end
+
+ def get_intensity(start, final, number, depth)
+ intensity = number.to_f / @max_steps
+
+ if intensity.between?(start, final) or final <= 0
+ return @symbols[depth]
+ else
+ get_intensity(final, final - @interval_length, number, depth += 1)
+ end
+ end
+
+ def draw(canvas)
+ result = ''
+ canvas.each do |row|
+ row.each do |column|
+ result << get_intensity(1, 1 - @interval_length, column, 0)
+ end
+ result << "\n"
+ end
+ result
+ end
+ end
+
+ class HTML
+ def initialize(pixel_size)
+ @pixel_size = pixel_size
+ end
+
+ def set_max_steps(max_steps)
+ @max_steps = max_steps.to_f
+ end
+
+ def intensity(number)
+ number.to_f / @max_steps
+ end
+
+ def draw(canvas)
+ header = header2
+
+ canvas.each do |row|
+ header << '<tr>'
+ row.each do |column|
+ header << "<td style='opacity: #{format('%.2f',
+ intensity(column))}'></td>"
+ end
+ header << '</tr>'
+ end
+
+ header << "</table></body></html>"
+ return header.gsub(/\s+/, '')
+ end
+
+ def header2
+ "<!DOCTYPE html>
+ <html>
+ <head>
+ <title>Turtle graphics</title>
+
+ <style>
+ table {
+ border-spacing: 0;
+ }
+
+ tr {
+ padding: 0;
+ }
+
+ td {
+ width: #{@pixel_size}px;
+ height: #{@pixel_size}px;
+
+ background-color: black;
+ padding: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <table>"
+ end
+ end
+ end
+end