Created
January 20, 2010 12:11
-
-
Save anonymous/281801 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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