Мирослав обнови решението на 02.12.2015 00:34 (преди около 9 години)
+class TurtleGraphics
+
+ class Turtle
+
+ attr_accessor :field
+
+ def initialize(rows, cols)
+ nullify_field(rows, cols)
+ spawn_at(0, 0)
+ @max_cell = 1
+ end
+
+ def nullify_field(rows, cols)
+ @field = Array.new(rows) { Array.new(cols, 0) }
+ end
+
+ def draw(canvas = nil, &block)
+ instance_eval(&block)
+ if canvas.instance_of? TurtleGraphics::Canvas::ASCII then
+ FieldConverter.convert_to_ascii(@field, canvas.symbols, @max_cell)
+ elsif canvas.instance_of? TurtleGraphics::Canvas::HTML then
+ FieldConverter.convert_to_html(@field, canvas.size, @max_cell)
+ else
+ @field
+ end
+ end
+
+ def move()
+ @max_cell = @object.move(@field, @max_cell)
+ end
+
+ def turn_left()
+ @object.turn_left()
+ end
+
+ def turn_right()
+ @object.turn_right()
+ end
+
+ def spawn_at(row, column)
+ nullify_field(@field[0].size, @field.size)
+ @object = MovingObject.new(@field, row, column)
+ end
+
+ def look(orientation)
+ @object.orientation = orientation
+ end
+ end
+
+ class Canvas
+
+ class ASCII
+
+ attr_accessor :symbols
+
+ def initialize(symbols)
+ @symbols = symbols
+ end
+ end
+
+ class HTML
+
+ attr_accessor :size
+
+ def initialize(size)
+ @size = size
+ end
+ end
+ end
+end
+
+class FieldConverter
+ def self.convert_to_ascii(field, symbols, max_cell)
+ string = ""
+ self.traverse(field) { |element|
+ string += self.convert_ascii(element, symbols, max_cell)
+ }
+ string.strip! || string
+ end
+
+ def self.convert_ascii(element, symbols, max_cell)
+ if element == "\n" || element == "" then return element end
+ intensity = Rational(element, max_cell)
+ symbols[ (intensity * (symbols.size - 1)).to_i ]
+ end
+
+ def self.traverse(field)
+ field.each { |row|
+ yield ""
+ row.each { |element|
+ yield element
+ }
+ yield "\n"
+ }
+ end
+
+ def self.convert_to_html(field, size, max_cell)
+ html = "<!DOCTYPE html>\n<html>\n<head>\n\t<title>Turtle graphics</title>\
+ \n\t<style>\n\ttable {\n\t\tborder-spacing: 0;\n\t}\n\ttr {\n\t\t\
+ padding: 0;\n\t}\n\ttd {\n\t\twidth: #{size}px;\n\t\theight: #{size}px;\
+ \n\t\tbackground-color: black;\n\t\tpadding: 0;\n\t}\n\t</style>\n\
+ </head>\n<body>\n<table>\n"
+ self.traverse(field) { |element|
+ html += self.convert_html(element, max_cell)
+ }
+ html += "</table>\n</body>\n</html>"
+ end
+
+ def self.convert_html(element, max_cell)
+ if element == "" then return "\t<tr>\n" end
+ if element == "\n" then return "\t</tr>\n" end
+ opacity = Rational(element, max_cell)
+ "\t\t<td style=\"opacity: #{format('%.2f', opacity)}\"></td>\n"
+ end
+end
+
+class MovingObject
+
+ ORIENTATION_MAP = { right: [0, 1], left: [0, -1], up: [-1, 0], down: [1, 0] }
+ SIDES = [ :up, :right, :down, :left ]
+
+ attr_accessor :orientation
+ attr_accessor :x, :y
+
+ def initialize(field, start_x = 0, start_y = 0, orientation = :right)
+ @x = start_x
+ @y = start_y
+ @orientation = orientation
+ field[@y][@x] = 1
+ end
+
+ def move(field, max_cell)
+ update_position([@y, @x].zip(ORIENTATION_MAP[@orientation]).map { |x, y|
+ x + y
+ })
+
+ @x = field[0].size - 1 if @x < 0
+ @x = 0 if @x == field[0].size
+ @y = field.size - 1 if @y < 0
+ @y = 0 if @y == field.size
+
+ field[@y][@x] += 1
+ if field[@y][@x] > max_cell then
+ max_cell = field[@y][@x]
+ else
+ max_cell
+ end
+ end
+
+ def turn_left()
+ index = get_orientation_index(@orientation) - 1
+ index = SIDES.size - 1 if index < 0
+ @orientation = SIDES[index]
+ end
+
+ def turn_right()
+ index = get_orientation_index(@orientation) + 1
+ index = 0 if index == SIDES.size
+ @orientation = SIDES[index]
+ end
+
+ private
+
+ def get_orientation_index(orientation)
+ SIDES.find_index(orientation)
+ end
+
+ def update_position(new_position)
+ @x = new_position[1]
+ @y = new_position[0]
+ end
+end