我正在尝试使用红宝石中的深度优先搜索来生成简单的迷宫求解器,该算法可以正常工作并找到解决方案,我正在努力解决的问题是打印解决方案,更具体地说是从父对象属性访问父节点
我得到的路径输出是:
S
G
state: #<MazeLocation:0x000055999847fe50>, parent: [#<Node:0x000055999847ff68 @state=#<MazeLocation:0x0000559998490138 @row=1, @column=2>, @parent=[#<Node:0x00005599984902a0 @state=#<MazeLocation:0x00005599984904a8 @row=0, @column=2>, @parent=[#<Node:0x0000559998490610 @state=#<MazeLocation:0x0000559998490778 @row=0, @column=1>, @parent=[#<Node:0x0000559998490980 @state=#<MazeLocation:0x0000559998493ef0 @row=0, @column=0>, @parent=[]>]>]>]>]
Solution found
我要提取的是父级中的每个MazeLocation以追溯解决方案路径。
要重现的代码如下(抱歉,很长): 迷宫相关课程
require_relative 'search.rb'
module Cells
EMPTY = :" "
BLOCKED = :X
START = :S
GOAL = :G
PATH = :*
end
class MazeLocation
attr_reader :row
attr_reader :column
def initialize(row, column)
@row = row
@column = column
end
def ==(x)
@row == x.row && @column == x.column
end
def eql?(x)
@row == x.row && @column == x.column
end
# needed for set include? method
def hash
@row.hash
end
end
class Maze
attr_reader :start
def initialize(start, goal, rows = 10, columns = 10, sparseness = 0.1)
@rows = rows
@columns = columns
@start = start
@goal = goal
@grid = []
@rows.times do |row|
@grid << Array.new(@columns)
end
random_fill(sparseness)
@grid[start.row][start.column] = Cells::START
@grid[goal.row][goal.column] = Cells::GOAL
end
def to_s
output = ""
@grid.each do |row|
output += "" + row.join + "\n"
end
output
end
def mark(path)
path.each do |maze_location|
@grid[maze_location.row][maze_location.column] = Cells::PATH
end
@grid[@start.row][@start.column] = Cells::START
@grid[@goal.row][@goal.column] = Cells::GOAL
end
def goal_test(current_location)
current_location == @goal
end
def successors(current_location)
possible_moves = []
if current_location.row + 1 < @rows &&
@grid[current_location.row + 1][current_location.column] != Cells::BLOCKED
possible_moves << MazeLocation.new(current_location.row + 1, current_location.column)
end
if current_location.row - 1 >= 0 &&
@grid[current_location.row - 1][current_location.column] != Cells::BLOCKED
possible_moves << MazeLocation.new(current_location.row - 1, current_location.column)
end
if current_location.column + 1 < @columns &&
@grid[current_location.row][current_location.column + 1] != Cells::BLOCKED
possible_moves << MazeLocation.new(current_location.row, current_location.column + 1)
end
if current_location.column - 1 >= 0 &&
@grid[current_location.row][current_location.column - 1] != Cells::BLOCKED
possible_moves << MazeLocation.new(current_location.row, current_location.column - 1)
end
possible_moves
end
private
def random_fill(sparseness)
@grid.each_with_index do |column, row|
column.each_with_index do |cell, element|
if rand() < sparseness
@grid[row][element] = cell = Cells::BLOCKED
else
@grid[row][element] = cell = Cells::EMPTY
end
end
end
end
end
start = MazeLocation.new(0,0)
goal = MazeLocation.new(2,2)
maze = Maze.new(start, goal,3,3)
puts maze
solution = DSF.new(maze, start)
unless solution.solution_found
puts "No solution found using depth-first search!"
else
puts "Solution found"
maze.mark(solution.solution_path)
puts maze
end
搜索相关类别:
require 'set'
class Node
attr_reader :state
attr_reader :parent
attr_reader :cost
attr_reader :heuristic
def initialize(state, *parent)
@state = state
@parent = parent
end
def to_s
"state: #{@state}, parent: #{@parent}"
end
end
class DSF
attr_reader :solution_found
attr_reader :solution_path
def initialize(maze, inital)
# the object being searched
@maze = maze
# frontier to where we've yet to go
@frontier = []
@frontier.push(Node.new(inital))
@solution_found = false
@solution_path = []
# explored is where we have been
@explored = Set.new
search
end
def node_to_path(node)
puts node
path = []
path << node.state
path << node.parent
while node.parent.empty?
node = node.parent
path.append(node.state)
end
path.reverse
end
private
def search
while not @frontier.empty?
current_node = @frontier.pop
current_state = current_node.state
#goal check
if @maze.goal_test(current_state)
@solution_found = true
@solution_path = node_to_path(current_node)
end
@maze.successors(current_state).each do |child|
if @explored.include?(child)
next
end
@explored << child
@frontier.push(Node.new(child, current_node))
end
end
end
end
利益的功能就是这样:
DFS#node_to_path
def node_to_path(node)
puts node
path = []
path << node.state
path << node.parent
while node.parent.empty?
node = node.parent
path.append(node.state)
end
path.reverse
end
我确实考虑过将父节点作为object_id传递,但这似乎不正确。
答案 0 :(得分:0)
我弄清楚了并想与我分享-问题是我认为方法参数中的*运算符意味着它是可选的(我想这是某种方式),但我没有意识到它会变成将参数捕获到数组中。
我进行了以下修改:
到班级节点:
class Node
attr_reader :state
attr_reader :parent
def initialize(state, parent = nil)
@state = state
@parent = parent
end
def to_s
"state: #{@state}, parent: #{@parent}"
end
end
到DFS#node_to_path
def node_to_path(node)
path = []
path << node.state
while not node.parent.nil?
node = node.parent
path.append(node.state)
end
path.reverse
end
现在可以正常工作,并产生一个简单的深度优先搜索迷宫求解算法。