Иван обнови решението на 02.12.2015 15:53 (преди около 9 години)
+class TurtleGraphics
+ class Turtle
+ attr_accessor :canvas
+ def initialize(rows, cols)
+ rows = 1 if rows < 0
+ cols = 1 if cols < 0
+
+ @rows = rows
+ @cols = cols
+
+ @canvas = Array.new(@rows) { Array.new(@cols, 0) }
+ @orientation = :right
+ @position = [0, 0] # row, col
+ @canvas[0][0] = 1
+
+ @orientations = [:left, :up, :right, :down]
+ end
+
+ def draw(graphic = nil, &block)
+ instance = TurtleGraphics::Turtle.new(@rows, @cols)
+ instance.instance_eval &block
+ @canvas = instance.canvas
+
+ if graphic.kind_of? Canvas::ASCII
+ return graphic.get_ascii(@canvas)
+ end
+
+ if graphic.kind_of? Canvas::HTML
+ return graphic.to_html(@canvas)
+ end
+
+ @canvas
+ end
+
+ def move
+ case @orientation
+ when :left then @position[1] -= 1
+ when :up then @position[0] -= 1
+ when :right then @position[1] += 1
+ when :down then @position[0] += 1
+ end
+
+ check_position
+ @canvas[@position[0]][@position[1]] += 1
+ end
+
+ def turn_left
+ if @orientation == :left
+ @orientation = :down
+ else
+ look(@orientations[@orientations.index(@orientation) - 1])
+ end
+ end
+
+ def turn_right
+ if @orientation == :down
+ @orientation = :left
+ else
+ look(@orientations[@orientations.index(@orientation) + 1])
+ end
+ end
+
+ def spawn_at(row, column)
+ row = @rows % row
+ column = @cols % column
+ @position = [row, column]
+ @canvas[@position[0]][@position[1]] += 1
+ end
+
+ def look(orientation)
+ @orientation = orientation if @orientations.include? orientation
+ end
+
+ def check_position
+ @position[0] = 0 if @position[0] >= @rows
+ @position[1] = 0 if @position[1] >= @cols
+ @position[0] = @rows - 1 if @position[0] < 0
+ @position[1] = @cols - 1 if @position[1] < 0
+ end
+ end
+
+ class Canvas
+
+ class ASCII
+ attr_accessor :symbols
+
+ def initialize(symbols)
+ @symbols = symbols
+ end
+
+ def get_ascii(canvas)
+ ascii_string = ""
+
+ densities = (0..(symbols.length - 1)).map do |e|
+ e / ((symbols.length - 1) * 1.0)
+ end
+
+ flat_canvas = canvas.flatten
+
+ (0..(flat_canvas.length - 1)).each do |i|
+ current = flat_canvas[i] / ((symbols.length - 1) * 1.0)
+
+ ascii_string << symbols[0] if current == 0
+ ascii_string << next_char(current, densities)
+ ascii_string << "\n" if i % canvas[0].length == 1
+ end
+
+ ascii_string
+ end
+
+ def next_char(current, densities)
+ (0..(densities.length - 2)).each do |j|
+ if current > densities[j] && current <= densities[j + 1]
+ return symbols[j + 1]
+ end
+ end
+
+ ""
+ end
+ end
+
+ class HTML
+ attr_accessor :pixel_size
+
+ def initialize(pixel_size)
+ @pixel_size = pixel_size
+ end
+
+ def get_table(canvas)
+ table = ""
+ duplicate = canvas.dup
+
+ interval = 1.0 / canvas.map { |e| e.max }.max
+
+ duplicate = duplicate.map do |row|
+ row.map { |element| format('%.2f', element * interval) }
+ end
+
+ duplicate.each do |row|
+ table << "<tr>"
+ row.each { |element| table << "<td style=\"opacity: #{element}\"></td>" }
+ table << "</tr>"
+ end
+
+ table
+ end
+
+ def to_html(canvas)
+ html = "<!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>
+ #{get_table(canvas)}
+ </table>
+</body>
+</html>
+"
+ end
+ end
+
+ end
+end