This is an 8 puzzle and uses bfs and dfs to solve find the solution and prints out the path to the goal. I am having trouble poping and appending the children so that it can find the solution. My error is that it will only print out the two options and does not branch out from the possible solution. The terminal is still going despite not printing out anything.
Here is my code and on the bottom is a test case.
import copy
#This is the only file you need to work on. You do NOT need to modify other files
# Below are the functions you need to implement. For the first project, you only need to finish implementing bfs() and dfs()
#here you need to implement the Breadth First Search Method
def bfs(puzzle):
list = []
#initialization
state = copy.deepcopy(puzzle)
goal = [0,1,2,3,4,5,6,7,8]
possible_move = [[1,3],[0,2,4],[1,5],[0,4,6],[1,3,5,7],[2,4,8],[3,7],[4,6,8],[5,7]]
#appending the first state
queue = []
queue = [Node(state)]
for node in queue[:]:
print('the state of this game position is:\n ' str(node.state))
loop = True
notFound = True
l = 0
while loop:
for node in queue:
#blank index in each state
blank = node.state.index(8)
print('the index of the blank is ' str(blank))
#The possible position
possible_pos = possible_move[blank]
print('possible pos ' str(possible_pos))
if state != goal:
for i in possible_pos:
possible_sw = copy.deepcopy(node.state)
print('index swap = ' str(i))
temp = possible_sw[i]
possible_sw[i] = 8
possible_sw[blank] = temp
print('the child nodes is ' str(possible_sw))
node.insertChild(possible_sw)
if possible_sw == goal:
print('end')
notFound = False
loop = False
#check each child and find the goal state
for node in queue[:]:
for child_state in node.children:
if child_state == [0,1,2,3,4,5,6,7,8]:
final_state = child_state
print('the final state is ' str(final_state.state))
queue.pop(0)
#find the parent path
while node.parent and loop is False:
sol_path = final_state.state
list.append(sol_path.index(8))
if final_state.parent is not None:
final_state = final_state.parent
else:
parent = False
list.reverse()
list.pop(0)
print('moves list ' str(list))
return list
#here you need to implement the Depth First Search Method
def dfs(puzzle):
list = []
return list
#This will be for next project
def astar(puzzle):
list = []
return list
def swap(list, pos1, pos2):
list[pos1],list[pos2] = list[pos2], list[pos1]
return list
class Node:
def __init__(self,state,parent = None):
self.parent = parent
self.state = state
self.children = []
def insertChild(self, child_state):
self.children.append(Node(child_state,self))
#test cases
# p =[0, 1, 2, 3, 4, 5, 8, 6, 7]
p = [0, 1, 2, 3, 4, 5, 6, 8, 7]
#p = [0, 1, 2, 3, 8, 4, 6, 7, 5]
#p =[0, 4, 1, 3, 8, 2, 6, 7, 5]
bfs(p)
print(" ")
#dfs(p)
CodePudding user response:
There are several issues with your attempt:
The queue never receives more entries;
queue.append
is never called. On the other hand, the inner loop overqueue[:]
empties the queue withpop
, removing its only element. And from that moment on the queue remains empty.The
Node
constructor is called only once, so there will never be more than one node, and the testnode.parent
will always be false, making the lastwhile
loop useless, and the moveslist (if any) will never be printedIf the end is not found in the first iteration -- meaning the initial position is not one move away from the goal -- the outer loop will get into an infinite loop: on its second iteration the queue is empty, so there is nothing to do, and the
loop
name will never become True.if state != goal
makes little sense as thestate
name never changes in the loop. If anything, this should referencenode.state
, notstate
.The
list.pop(0)
at the very end unnecessarily removes a move. The loop condition already checks if the node has a parent -- so skipping the root state -- so then you'll miss two states.The code does not check whether the initial position is maybe the goal position, and so it will not return an empty move list as solution when this is the case.
Some other remarks:
swap
is never called.- The code has several names which serve no purpose, like
l
,notFound
. - It uses
list
which is a native name in Python -- choose a different name. - The
children
attribute of theNode
instances is not useful. Although you iterate it to find the final state, the logic for identifying whether the goal was reached, is already present elsewhere in the code... it doesn't needchildren
. deepcopy
is not needed: the lists you use are not "deep". You can simply copy them by applying thelist
(native) function, or slicing them with[:]
.- Assigning twice to
queue
in sequence (in the initialisation) makes the first assignment useless. Just have the second assignment. - The loop in the initialisation part should not be a loop. At that moment you know the queue has only one entry, so iterating it is overkill. You can just output the initial state using
puzzle
. But maybe you wanted to output the state in the loop... - There is no need for
temp
to perform a swap. First of all, Python can do tuple assignment, but also: a move is not really a swap of two unknown values: you know that one of the two is the empty cell (8), so you can safely overwrite that cell with the other cell's value, and then set the other cell's value to 8 -- notemp
is needed.
Here is your code corrected with the above remarks:
class Node:
def __init__(self,state,parent = None):
self.parent = parent
self.state = state
def bfs(puzzle):
solution = []
#initialization
goal = [0,1,2,3,4,5,6,7,8]
possible_move = [[1,3],[0,2,4],[1,5],[0,4,6],[1,3,5,7],[2,4,8],[3,7],[4,6,8],[5,7]]
node = Node(puzzle)
queue = [node]
while True:
node = queue.pop(0)
print('the state of this game position is:\n ' str(node.state))
if node.state == goal:
break
blank = node.state.index(8)
print('the index of the blank is ' str(blank))
possible_pos = possible_move[blank]
print('possible pos ' str(possible_pos))
for i in possible_pos:
possible_sw = node.state[:]
print('index swap = ' str(i))
possible_sw[blank] = possible_sw[i]
possible_sw[i] = 8
print('the child node is ' str(possible_sw))
queue.append(Node(possible_sw, node))
while node.parent:
solution.append(node.state.index(8))
node = node.parent
solution.reverse()
print('moves list ' str(solution))
return solution