Skip to content

Instantly share code, notes, and snippets.

@ryandgoldenberg1
Last active September 29, 2015 17:34
Show Gist options
  • Save ryandgoldenberg1/291642c802a676cf3089 to your computer and use it in GitHub Desktop.
Save ryandgoldenberg1/291642c802a676cf3089 to your computer and use it in GitHub Desktop.
2D Maze Pathfinder
class Maze
attr_accessor :data, :workqueue, :seen, :start, :finish, :solution
def initialize(filename)
@data = read_data(filename)
@start = find_letter("S")
@finish = find_letter("E")
@workqueue = [ Node.new(start, [start]) ]
@seen = [start]
@solution = nil
end
def read_data(filename)
File.readlines(filename).map(&:chomp).map { |row| row.split('') }
end
def show(board = data)
puts board.map(&:join).join("\n")
end
def show_solution
return unless solution
path = solution.path.select { |n| n != finish && n != start }
dup_board = data.map {|row| row.map { |el| el.dup } }
path.each do |p|
dup_board[p.row][p.col] = "X"
end
show(dup_board)
end
def find_letter(letter)
(0...data.length).each do |row|
(0...data[row].length).each do |col|
if data[row][col] == letter
return Point.new([row, col])
end
end
end
nil
end
def seen?(point)
seen.any? { |p| p == point }
end
def finish?(node)
node.point == finish
end
def [](point)
data[point.row][point.col]
end
def in_workqueue?(point)
workqueue.any? { |n| n.point == point }
end
def do_work
node = @workqueue.shift
if finish?(node)
@solution = node
return true
end
@seen << node.point
neighbors = node.neighbor_nodes(data)
neighbors.reject! { |n| seen?(n.point) || self[n.point] == "*" || in_workqueue?(n.point) }
@workqueue += neighbors
end
def solve
while !solution
do_work
end
solution
end
end
class Node
attr_accessor :point, :path
def initialize(point, path)
@point = point
@path = path
end
def neighbor_nodes(data)
[point.left, point.right, point.up, point.down].select do |p|
p.inbounds?(data)
end.map do |p|
build_neighbor(p)
end
end
def build_neighbor(point)
new_path = path + [point]
Node.new(point, new_path)
end
end
class Point
attr_accessor :row, :col
def initialize(arr)
@row = arr[0]
@col = arr[1]
end
def ==(other)
self.row == other.row && self.col == other.col
end
def left
Point.new([row, col - 1])
end
def up
Point.new([row - 1, col])
end
def right
Point.new([row, col + 1])
end
def down
Point.new([row + 1, col])
end
def inbounds?(map)
row >= 0 && row < map.length &&
col >= 0 && col < map[row].length
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment