Йоан обнови решението на 24.11.2015 15:18 (преди около 9 години)
+module TurtleGraphics
+ class Turtle
+ DIRECTIONS = [:up, :right, :down, :left]
+
+ def initialize(rows = 0, columns = 0)
+ @matrix = create_matrix(rows, columns)
+ @row = 0
+ @column = 0
+ @rows = rows
+ @columns = columns
+ @direction = :right
+ @spawned = false
+ end
+
+ def draw(canvas = Canvas::Default.new, &block)
+ instance_eval(&block)
+
+ canvas.process(@matrix)
+ end
+
+ def move
+ spawn_at(0, 0) unless @spawned
+
+ case @direction
+ when :up then @row -= 1
+ when :right then @column += 1
+ when :down then @row += 1
+ when :left then @column -= 1
+ end
+
+ @row %= @rows
+ @column %= @columns
+
+ step_at(@row, @column)
+ end
+
+ def turn_left
+ change_direction(:to_left)
+ end
+
+ def turn_right
+ change_direction(:to_right)
+ end
+
+ def look(direction)
+ @direction = direction
+ end
+
+ def spawn_at(row, column)
+ @spawned = true
+
+ @row = row
+ @column = column
+
+ step_at(@row, @column)
+ end
+
+ private
+
+ def create_matrix(rows, columns)
+ Array.new(rows) { Array.new(columns, 0) }
+ end
+
+ def step_at(row, column)
+ @matrix[row][column] += 1
+ end
+
+ def change_direction(direction)
+ current_direction_index = DIRECTIONS.index(@direction)
+
+ if direction == :to_right
+ current_direction_index += 1
+ else
+ current_direction_index -= 1
+ end
+
+ current_direction_index %= DIRECTIONS.length
+
+ @direction = DIRECTIONS[current_direction_index]
+ end
+ end
+
+ module Canvas
+ class Base
+ def process(matrix)
+ matrix
+ end
+
+ private
+
+ def to_proportions(matrix)
+ max_item = matrix.flatten.max
+
+ matrix_proportions = matrix.map do |row|
+ row.map { |element| element / max_item.to_f }
+ end
+
+ matrix_proportions
+ end
+ end
+
+ class ASCII < Base
+ def initialize(symbols)
+ @lowest_symbol = symbols[0]
+ @low_symbol = symbols[1]
+ @high_symbol = symbols[2]
+ @highest_symbol = symbols[3]
+ end
+
+ def process(matrix)
+ proportions = to_proportions(matrix)
+
+ to_ascii(proportions)
+ end
+
+ private
+
+ def to_ascii(matrix)
+ symbols_matrix = matrix.map do |row|
+ row_symbols = row.map { |element| ascii_element element }
+ row_symbols.join
+ end
+
+ symbols_matrix.join("\n")
+ end
+
+ def ascii_element(percent)
+ percent = percent.round(2)
+
+ case
+ when percent == 0 then @lowest_symbol
+ when percent <= 0.34 then @low_symbol
+ when percent <= 0.67 then @high_symbol
+ when percent <= 1 then @highest_symbol
+ end
+ end
+ end
+
+ class HTML < Base
+ def initialize(pixel_size)
+ @pixel_size = pixel_size
+ end
+
+ def process(matrix)
+ proportions = to_proportions(matrix)
+
+ to_html(proportions)
+ end
+
+ private
+
+ def to_html(matrix)
+ "<!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>#{generate_table_html(matrix)}</table></body>
+ </html>"
+ end
+
+ def generate_table_html(matrix)
+ rows_html = matrix.map do |row|
+ "<tr>#{generate_table_data_html(row)}</tr>"
+ end
+
+ rows_html.join
+ end
+
+ def generate_table_data_html(proportions)
+ proportions_html = proportions.map do |proportion|
+ "<td style=\"opacity: #{format('%.2f', proportion)}\"></td>"
+ end
+
+ proportions_html.join
+ end
+ end
+
+ class Default < Base
+ end
+ end
+end
Изглежда доста добре :)
ASCII, обаче, може да приема произволен брой символи. Както си го направил в момента, не поддържаш брой, различен от четири.
Също, не съм сигурен, че правилното място за to_proportions
е в базовия клас. Не всеки наследник го интересува.