Милена обнови решението на 29.11.2015 15:14 (преди около 9 години)
+module TurtleGraphics
+ class Turtle
+ ORIENTATIONS = {up: 0, down: 180, right: 90, left:270}
+
+ attr_reader :position, :steps
+
+ def initialize(rows, cols)
+ @rows = rows
+ @cols = cols
+ @orientation = 90
+ @position = {}
+ @steps = []
+ end
+
+ def move
+ spawn_at(0, 0) unless @position.length > 0
+ @position[:row] = (@position[:row] + 1) % @rows if @orientation == 180
+ @position[:row] = (@position[:row] - 1) % @rows if @orientation == 0
+ @position[:col] = (@position[:col] + 1) % @rows if @orientation == 90
+ @position[:col] = (@position[:col] - 1) % @rows if @orientation == 270
+ @steps << @position.dup
+ end
+
+ def turn_right
+ @orientation = (@orientation + 90) % 360
+ end
+
+ def turn_left
+ @orientation = (@orientation - 90) % 360
+ end
+
+ def spawn_at(row, col)
+ new_row, new_col = row % @rows, col % @cols
+ @position = {row: new_row , col: new_col}
+ @steps << @position.dup
+ end
+
+ def look(orientation)
+ @orientation = ORIENTATIONS[orientation]
+ end
+
+ def draw(canvas = nil)
+ self.instance_eval(&Proc.new) if block_given?
+ grid = Array.new(@rows) { Array.new(@cols){0} }
+ @steps.each { |p| grid[p[:row]][p[:col]] += 1}
+ return grid if canvas == nil
+ canvas.render(grid)
+ end
+ end
+
+ module Canvas
+ class ASCII
+ def initialize(symbols)
+ @symbols = symbols
+ @range_step = 1.to_f / (@symbols.length - 1)
+ end
+
+ def render(grid)
+ max_visits, output = grid.max_by { |array| array.max }.max, ''
+ grid.each do |row|
+ output += render_line(row, max_visits)
+ end
+ output.chomp("\n")
+ end
+
+ private
+
+ def render_line(row, max_visits)
+ output = ''
+ row.each_with_index do |value, index|
+ symbol_index = ((value.to_f / max_visits) / @range_step).ceil
+ output += @symbols[symbol_index]
+ end
+ output + "\n"
+ end
+ end
+
+ class HTML
+ LAYOUT = "<!DOCTYPE html>
+ <html>
+ <head>
+ <title>Turtle graphics</title>
+
+ <style>
+ table {
+ border-spacing: 0;
+ }
+
+ tr {
+ padding: 0;
+ }
+
+ td {
+ width: %spx;
+ height: %spx;
+
+ background-color: black;
+ padding: 0;
+ }
+ </style>
+ </head>
+ <body>
+ %s
+ </body>
+ </html>"
+ def initialize(pixel_size)
+ @pixel_size = pixel_size
+ end
+
+ def render(grid)
+ max_visits, table = grid.max_by { |array| array.max }.max, '<table>'
+ grid.each do |row|
+ table += render_line(row, max_visits)
+ end
+ table += '</table>'
+ LAYOUT % [@pixel_size, @pixel_size, table]
+ end
+
+ private
+
+ def render_line(row, max_visits)
+ output = '<tr>'
+ row.each do |value|
+ opacity = format('%.2f', value.to_f / max_visits)
+ output += "<td style='opacity: #{opacity}'></td>"
+ end
+
+ output += '</tr>'
+ end
+ end
+ end
+end
Здравей :)
Ето малко коментари:
- Интересно представяне с градуси :) В
move
има доста повторение. Защо не го замениш сcase
? - Защо пазиш стъпките отделно от матрицата и я обновяваш само накрая? Можеш да обновяваш директно нея.
- Паралелното присвояване не се използва толкова често на практика. Няма ползи от него в този му вид
new_row, new_col = row % @rows, col % @cols
. Много по-чисто би било на два отделни реда. - Конкатенирането на низове, особено in-place не е добра практика в Ruby. Опитай да го направиш без
+=
на низове. - Харесва ми, че си изнесла HTML-а в константа :)
- Не-whitespace символите в HTML-а трябва да са същите като използваните в условието. HTML кода, който създаваш в момента ще работи в браузър, но не е както в условието и ще ти се счупят тестовете.