Владимир обнови решението на 01.12.2015 18:30 (преди около 9 години)
+module TurtleGraphics
+
+ module Canvas
+
+ class Base
+
+ attr_accessor :width, :height
+
+ def initialize(width, height)
+ @width, @height = width, height
+ reset
+ end
+
+ def reset
+ @matrix = Array.new(@height) { Array.new(@width, 0) }
+ end
+
+ def result
+ @matrix
+ end
+
+ def visit(row, column)
+ @matrix[row][column] += 1
+ end
+
+ def max_visits
+ @max_int ||= @matrix.map do |row|
+ row.max
+ end.max
+ end
+ end
+
+ class ASCII < Base
+
+ def initialize(chars)
+ @symbols = chars
+ super(0, 0)
+ end
+
+ def get_symbol(intensity)
+ step = 1.0 / (@symbols.size - 1)
+ index, initial_intensity = 0, 0
+ while intensity > initial_intensity
+ index += 1
+ initial_intensity += step
+ end
+ @symbols[index]
+ end
+
+ def result
+ @matrix.map do |row|
+ row.map do |cell_visits|
+ get_symbol(cell_visits.to_f / max_visits)
+ end.join
+ end.join("\n")
+ end
+ end
+
+ class HTML < Base
+
+ BASE = <<-eos
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Turtle graphics</title>
+
+ <style>
+ table {
+ border-spacing: 0;
+ }
+
+ tr {
+ padding: 0;
+ }
+
+ td {
+ width: #width#px;
+ height: #height#px;
+
+ background-color: black;
+ padding: 0;
+ }
+ </style>
+</head>
+<body>
+ <table>
+ #table#
+ </table>
+</body>
+</html>
+eos
+
+ def initialize(cell_width)
+ @cell_width = cell_width
+ super(0, 0)
+ end
+
+ def result
+ base = BASE.gsub(/#height#|#width#/, @cell_width.to_s)
+ table = ''
+ @matrix.each do |row|
+ table += "<tr>"
+ row.each do |cell_visits|
+ table += "<td style=\"opacity: #{cell_visits.to_f / max_visits}\"></td>"
+ end
+ table += "</tr>"
+ end
+ base.gsub('#table#', table.chomp)
+ end
+ end
+ end
+
+ class Turtle
+
+ ORIENTATIONS = %i(right down left up)
+
+ def initialize(width, height)
+ @width, @height = width, height
+ @canvas = Canvas::Base.new(width, height)
+ spawn_at(0, 0)
+ end
+
+ def move
+ case ORIENTATIONS[@orientation]
+ when :right
+ @column += 1
+ when :down
+ @row += 1
+ when :left
+ @column -= 1
+ when :up
+ @row -= 1
+ end
+ fix_position
+ end
+
+ def fix_position
+ if @column == @canvas.width
+ @column = 0
+ elsif @column < 0
+ @column = @canvas.width - 1
+ end
+ if @row == @canvas.height
+ @row = 0
+ elsif @row < 0
+ @row = @canvas.height - 1
+ end
+ visit
+ end
+
+ def turn_right
+ @orientation += 1
+ @orientation = 0 if @orientation > 3
+ end
+
+ def turn_left
+ @orientation -= 1
+ @orientation = 3 if @orientation < 0
+ end
+
+ def spawn_at(row = 0, column = 0)
+ @canvas.reset
+ @row, @column = row, column
+ @orientation = 0
+ visit
+ end
+
+ def visit
+ @canvas.visit(@row, @column)
+ end
+
+ def look(orientation)
+ raise 'Invalid orientations' unless ORIENTATIONS.include? orientation
+ @orientation = ORIENTATIONS.index(orientation)
+ end
+
+ def draw(canvas = nil, &block)
+ if canvas
+ @canvas = canvas
+ @canvas.width, @canvas.height = @width, @height
+ spawn_at(0, 0)
+ end
+ instance_eval(&block)
+ @canvas.result
+ end
+ end
+end