Изтрит обнови решението на 29.11.2015 21:56 (преди около 9 години)
+module TurtleGraphics
+ class TurtleGraphics::Turtle
+
+ ORIENTATIONS = [:left, :up, :right, :down]
+ DIRS = {left: [-1, 0], up: [0, -1], right: [1, 0], down: [0, 1]}
+
+ def initialize(rows, columns)
+ @rows = rows
+ @columns = columns
+
+ self.look(:right)
+ end
+
+ def draw(custom_canvas = nil, &f)
+ @canvas = Array.new(@rows) { Array.new(@columns, 0) }
+
+ self.instance_eval(&f) if block_given?
+
+ if custom_canvas
+ custom_canvas.convert(@canvas)
+ else
+ @canvas
+ end
+ end
+
+ def move
+ if @position == nil
+ self.spawn_at(0, 0)
+ mark_position
+ end
+
+ dir = DIRS[@orientation]
+ new_x, new_y = @position[0] + dir[0], @position[1] + dir[1]
+ @position = [new_x % @columns, new_y % @rows]
+ mark_position
+ end
+
+ def mark_position
+ @canvas[@position[1]][@position[0]] += 1
+ end
+
+ def spawn_at(row, column)
+ @position = [row, column]
+ end
+
+ def turn_left
+ turn(-1)
+ end
+
+ def turn_right
+ turn(1)
+ end
+
+ def turn(direction)
+ look(ORIENTATIONS[(ORIENTATIONS.index(@orientation) + direction) % 4])
+ end
+
+ def look(orientation)
+ @orientation = orientation
+ end
+ end
+end
+
+module TurtleGraphics::Canvas
+ class TurtleGraphics::Canvas::ASCII
+ def initialize(symbols)
+ @symbols = symbols
+ @step = 1.0 / (@symbols.length - 1)
+ end
+
+ def convert(canvas)
+ max = canvas.map { |row| row.max }.max
+ result = ""
+
+ canvas.map do |row|
+ a = row.map do |pixel|
+ intensity = pixel.to_f / max
+ @symbols[(intensity / @step).ceil]
+ end
+
+ result << a.join(" ") << "\n"
+ end
+
+ result
+ end
+ end
+
+ class TurtleGraphics::Canvas::HTML
+
+ TEMPLATE_HTML =
+'<!DOCTYPE html>
+<html>
+<head>
+ <title>Turtle graphics</title>
+
+ <style>
+ table {
+ border-spacing: 0;
+ }
+
+ tr {
+ padding: 0;
+ }
+
+ td {
+ width: %dpx;
+ height: %dpx;
+
+ background-color: black;
+ padding: 0;
+ }
+ </style>
+</head>
+<body>
+ <table>
+%s </table>
+</body>
+</html>'
+
+ TEMPLATE_TD = " <td style=\"opacity: %s\"></td>\n"
+
+ def initialize(size)
+ @size = size
+ end
+
+ def convert(canvas)
+
+ max = canvas.map { |row| row.max }.max
+ result = ""
+ canvas.map do |row|
+ result << " <tr>\n"
+ row.map do |pixel|
+ intensity = pixel.to_f / max
+ result << TEMPLATE_TD % [format('%.2f', intensity)]
+ end
+ result << " </tr>\n"
+ end
+
+ TEMPLATE_HTML % [@size, @size, result]
+ end
+ end
+end
Здравей :)
Малко стилови коментари:
- Паралелното присвояване не се използва толкова често на практика. Няма ползи от него в този му вид
new_x, new_y = @position[0] + dir[0], @position[1] + dir[1]
. Много по-чисто би било на два отделни реда. - В
TEMPLATE_TD
и другите низове няма нужда да слагаш нови редове и празни места - няма да ги взимаме под внимание. - Правиш едно излишно форматиране в
convert
. Първо форматираш число като%.2f
, после резултата го форматираш като низ. Защо не сложиш директно%.2f
вTEMPLATE_TD
? - Конкатенирането на низове, особено in-place не е добра практика в Ruby. Опитай да направиш нещата без
<<
. - Използвай heredoc за многоредови низове. Така случайна кавичка в самото съдържание няма да затвори низа.