Skip to content

Instantly share code, notes, and snippets.

Created January 20, 2010 12:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/281801 to your computer and use it in GitHub Desktop.
Save anonymous/281801 to your computer and use it in GitHub Desktop.
require 'set'
class Labworker
def initialize(maze)
@maze = maze
@cheese_found = false
jerry = Mouse.new(maze, maze.startpoint.row, maze.startpoint.col)
jerry.observe(self)
@moving_mice = [jerry]
@step = 0
end
def solve_maze
until self.cheese_found? or self.no_mice_moved_on_last_tick
@step += 1
mice_that_moved_on_last_tick = @moving_mice.dup
@moving_mice = []
mice_that_moved_on_last_tick.each do |mouse|
mouse.clock_tick
end
end
end
def no_mice_moved_on_last_tick
@moving_mice.empty?
end
def cheese_found?
@cheese_found
end
# Mouse event handlers
def mouse_moved(mouse)
@moving_mice << mouse
end
def cheese_celebration_dance(mouse)
@cheese_found = true
@maze.solvable = true
@maze.steps = @step
end
def oh_no_been_here_before(mouse)
end
def oh_no_i_am_trapped(mouse)
end
end
class Mouse
attr_reader :row, :col
def initialize(maze,row,col)
@maze = maze
@row, @col = row, col
@observer = nil
@depressed = false
end
def observe(observer)
@observer = observer
end
def sniff_around
@maze[@row,@col].neighbour_cells.select {|c| c.walkable? && !c.has_pee?(self.my_smell) }
end
def sniff
if @maze[@row,@col].has_pee?(self.my_smell)
@depressed = true
@observer.oh_no_been_here_before(self) if @observer
end
@observer.cheese_celebration_dance(self) if @maze[@row,@col].endpoint? && @observer
end
def my_smell
@my_smell ||= self.object_id
end
def my_smell=(smell)
@my_smell = smell
end
protected :my_smell=
def pee
@maze[@row,@col].pee_on(self.my_smell)
end
def move(new_row, new_cell)
@row, @col = new_row, new_cell
@observer.mouse_moved(self) if @observer
end
def trapped?
if self.sniff_around.empty?
@depressed = true
@observer.oh_no_i_am_trapped(self) if @observer
return true
end
end
def breed
pup = self.dup
pup.my_smell = self.my_smell
pup
end
def breed_pups(count)
pups = []
count.times { pups << self.breed}
pups
end
def clock_tick
return if @depressed
self.pee
return if self.trapped?
cells = self.sniff_around
family = self.breed_pups(cells.length-1)
family.unshift(self)
family.zip(cells).each do |mouse,cell|
mouse.move(cell.row, cell.col)
mouse.sniff
end
end
end
class Maze
attr_writer :solvable
attr_accessor :steps
def initialize(maze_str)
@steps = 0
@cells = {}
maze_str.each_line.with_index do |line, row|
line.chomp.each_char.with_index do |ch, col|
r,c = row+1,col+1
fact_method = case ch
when 'A' then :create_startpoint
when 'B' then :create_endpoint
when '#' then :create_wall
when ' ' then :create_empty_cell
end
@cells[[r,c]] = Cell.send(fact_method,self,r,c)
end
end
Labworker.new(self).solve_maze
end
def startpoint
@cells.values.find {|c| c.startpoint? }
end
def endpoint
@cells.values.find {|c| c.endpoint? }
end
def [](row,col)
@cells[[row,col]]
end
def neighbour_cells(cell)
row,col = cell.row, cell.col
[@cells[[row-1,col]], @cells[[row,col+1]], @cells[[row+1,col]], @cells[[row,col-1]]].compact
end
def solvable?
@solvable ||= false
end
end
class Cell
attr_reader :row, :col
def self.create_startpoint(maze,row,col)
Cell.new(maze,row,col,false,true)
end
def self.create_endpoint(maze,row,col)
Cell.new(maze,row,col,false,false,true)
end
def self.create_wall(maze,row,col)
Cell.new(maze,row,col)
end
def self.create_empty_cell(maze,row,col)
Cell.new(maze,row,col,false)
end
def initialize(maze,row,col,wall=true,startpoint=false,endpoint=false)
@maze = maze
@row, @col = row, col
@startpoint = startpoint
@endpoint = endpoint
@wall = wall
@pee_smells = Set.new
end
def startpoint?
@startpoint
end
def endpoint?
@endpoint
end
def walkable?
not @wall
end
def neighbour_cells
@maze.neighbour_cells(self)
end
def pee_on(pee_smell)
@pee_smells << pee_smell
end
def has_pee?(pee_smell)
@pee_smells.include?(pee_smell)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment