Skip to content

Instantly share code, notes, and snippets.

@madebydna
Created August 11, 2011 13:35
Show Gist options
  • Save madebydna/1139662 to your computer and use it in GitHub Desktop.
Save madebydna/1139662 to your computer and use it in GitHub Desktop.
Turtle solution example (#puzzlenode)
module Logo
module Parser
def self.unroll_repeats(str)
str.gsub(/REPEAT (\d+) \[\s*(.*)\s*\]/) { |x|
$1.to_i.times.map { $2.strip }.join(" ")
}
end
def self.parse(source)
unroll_repeats(source).scan(/(RT|LT|FD|BK)\s+(\d+)/m)
.map { |c, v| [c, v.to_i] }
end
end
module Compass
DIRECTIONS = { 0 => :north,
45 => :north_east,
90 => :east,
135 => :south_east,
180 => :south,
225 => :south_west,
270 => :west,
315 => :north_west }
WEIGHTING = { :north => [ 0, 1],
:north_east => [ 1, 1],
:east => [ 1, 0],
:south_east => [ 1, -1],
:south => [ 0, -1],
:south_west => [-1, -1],
:west => [-1, 0],
:north_west => [-1, 1] }
end
class Canvas
include Enumerable
attr_reader :size, :data
def initialize(size)
@size = size
@data = size.times.map { Array.new(size, false) }
end
def each
data.each { |row| yield row }
end
def center_point
center_x = (size-1)/2
[center_x, center_x]
end
def draw_line(point_a, point_b)
points = self.class.points_between(point_a, point_b)
points.each do |point|
x, y = point
data[y][x] = true
end
end
def self.points_between(point_a, point_b)
return [point_a] if point_a == point_b
x1, y1 = point_a
x2, y2 = point_b
case
when y1 == y2
values_between(x1,x2).map { |x| [x, y1] }
when x1 == x2
values_between(y1,y2).map { |y| [x1, y] }
else
values_between(x1, x2).zip(values_between(y1, y2))
end
end
def self.values_between(a, b)
a < b ? a.upto(b) : a.downto(b)
end
end
class Interpreter
def initialize(canvas)
@canvas = canvas
@drawing_angle = 0
@drawing_position = @canvas.center_point
end
attr_reader :drawing_position
def drawing_direction
Compass::DIRECTIONS[@drawing_angle]
end
def move_drawing_position_forward(value)
original_position = Marshal.load(Marshal.dump(drawing_position))
xw, yw = Compass::WEIGHTING[drawing_direction]
drawing_position[0] += value*xw
drawing_position[1] += value*yw
@canvas.draw_line(original_position, drawing_position)
end
def move_drawing_position_back(value)
original_position = Marshal.load(Marshal.dump(drawing_position))
xw, yw = Compass::WEIGHTING[drawing_direction]
drawing_position[0] -= value*xw
drawing_position[1] -= value*yw
@canvas.draw_line(original_position, drawing_position)
end
def apply(command)
action, value = command
case action
when "FD"
move_drawing_position_forward(value)
when "BK"
move_drawing_position_back(value)
when "RT"
@drawing_angle = (@drawing_angle + value) % 360
when "LT"
@drawing_angle = (360 + @drawing_angle - value) % 360
end
end
def run(commands)
commands.each {|command| apply(command) }
end
end
module Presenter
def self.draw(matrix)
matrix.map do |row|
row.map {|x| x ? "X" : "."}.join(" ")
end.join("\n")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment