1

I am trying to create a BFS solution to the 8 puzzle problem in python. However after I 'get()' a node from the queue and find the puzzle state inside that node it seems the puzzle object has turned into a list object without the method 'getMoves()'. I am wondering why it is not still a Puzzle object?

import collections
import queue

class Node:

    def __init__(self, Puzzle, last=None):
        self.puzzle = Puzzle
        self.last = last

    def getPuzzle(self):
        return self.puzzle

    def getLast(self):
        return self.last

class Puzzle:

    def __init__(self, startState, goalState):
        self.state = startState
        self.goal = goalState

    def getState():
        return self.state

    def getMoves(self):

        currentState = self.state

        possibleNewStates = []

        zeroPos = currentState.index(0)

        if zeroPos == 0:
            possibleNewStates.append(move(0,1))
            possibleNewStates.append(move(0,3))
        elif zeroPos == 1:
            possibleNewStates.append(move(1,0))
            possibleNewStates.append(move(1,2))
            possibleNewStates.append(move(1,4))
        elif zeroPos == 2:
            possibleNewStates.append(move(2,1))
            possibleNewStates.append(move(2,5))
        elif zeroPos == 3:
            possibleNewStates.append(move(3,0))
            possibleNewStates.append(move(3,4))
            possibleNewStates.append(move(3,6))
        elif zeroPos == 4:
            possibleNewStates.append(self.move(4,1))
            possibleNewStates.append(self.move(4,3))
            possibleNewStates.append(self.move(4,5))
            possibleNewStates.append(self.move(4,7))
        elif zeroPos == 5:
            possibleNewStates.append(move(5,2))
            possibleNewStates.append(move(5,4))
            possibleNewStates.append(move(5,8))
        elif zeroPos == 6:
            possibleNewStates.append(move(6,3))
            possibleNewStates.append(move(6,7))
        elif zeroPos == 7:
            possibleNewStates.append(move(7,4))
            possibleNewStates.append(move(7,6))
            possibleNewStates.append(move(7,8))
        else:
            possibleNewStates.append(move(8,5))
            possibleNewStates.append(move(8,7))

        return possibleNewStates

    def move(self, current, to):

        changeState = self.state

        save = changeState[to]
        changeState[to] = changeState[current]
        changeState[current] = save

        return changeState

    def printPuzzle(self):

        copyState = self.state
        print(copyState)
        '''
        for i in range(9):
            if i == 2 or i == 5:
                print((str)(copyState[i]))
            else:
                print((str)(copyState[i])+" ", end="")
            print()
        '''

    def isSolved(self):
        return self.state == self.goal

class Solver:

    def __init__(self, Puzzle):
        self.puzzle = Puzzle

    def solveBFS(self):
        puzzle = self.puzzle
        startNode = Node(puzzle)
        myQueue = queue.Queue(0)
        myQueue.put(startNode)
        myPuzzle = startNode.getPuzzle()
        print(myPuzzle.isSolved())
        while myQueue:
            currentNode = myQueue.get()
            currentPuzzle = currentNode.puzzle

            if currentPuzzle == [0,1,2,3,4,5,6,7,8]:
                return currentNode

            nextMoves = currentPuzzle.getMoves() # << ERROR HERE
            for state in nextMoves:
                nextNode = Node(state, currentNode)
                myQueue.put(nextNode)

    startingState = [7,2,4,5,0,6,8,3,1]
    goalState = [0,1,2,3,4,5,6,7,8]
    myPuzzle = Puzzle(startingState, goalState)
    mySolver = Solver(myPuzzle)
    goalNode = mySolver.solveBFS()
    goalPuzzle = goalNode.getPuzzle()
    goalPuzzle.printPuzzle()
4
  • Could you cut this down to a minimal reproducible example? The process of doing so will likely help you to solve the problem yourself. Commented Oct 6, 2015 at 14:28
  • Where is the move() function defined? In Puzzle.getMoves(), most code refers to a move() function, and some lines refer to the self.moves() method. It is that function that probably returns a list. Commented Oct 6, 2015 at 14:29
  • What does currentNode.puzzle return? It seems you expext both a list and a Puzzle in the lines that follow. Also, don't use a class name as a variable/parameter name. Commented Oct 6, 2015 at 14:30
  • Thank you all for the feedback! Very timely and very helpful. To jonrsharpe: I will try this, thank you To Martijn Pieters: The move() function is not defined, each instance should be replaced with self.move() To tobias_k: I was just trying different ways to get the Puzzle object stored in the current Node and I was confused as to why the if statement didn't receive a compiling error. Commented Oct 7, 2015 at 16:47

2 Answers 2

2

That's because in some cases, state must be a list when you create a new node:

nextMoves = currentPuzzle.getMoves()
for state in nextMoves:
    nextNode = Node(state, currentNode)

Here state must've been a list returned from the Puzzle.getMoves() list:

def getMoves(self):
    # ...

    possibleNewStates = []

    # append various objects to possibleNewStates.

    return possibleNewStates

In getMoves() you use two callables to produces new states:

possibleNewStates.append(move(0,1))

and

possibleNewStates.append(self.move(4,1))

Puzzle.move() produces a list; you do some swapping on self.state which you set to a list:

def move(self, current, to):
    changeState = self.state

    save = changeState[to]
    changeState[to] = changeState[current]
    changeState[current] = save

    return changeState

Note that this mutates self.state in-place; you did not create a copy of the value here.

self.state was set from the first argument to Puzzle(), which was a list:

startingState = [7,2,4,5,0,6,8,3,1]
goalState = [0,1,2,3,4,5,6,7,8]
myPuzzle = Puzzle(startingState, goalState)

so self.move() returns a list, not a Puzzle() instance.

You didn't share the definition of the move() global function; if this also produces a list then that's another cause of your Node.puzzle values becoming lists.

You probably want to correct all move() calls to use self.move(), and for self.move() to return a new Puzzle() instance. You'll need to create a copy of self.state list here too:

def move(self, current, to):
    changeState = self.state[:]  # create a copy    
    changeState[to], changeState[current] = changeState[current], changeState[to]
    return Puzzle(changeState, self.goal)
Sign up to request clarification or add additional context in comments.

Comments

0

All move() in getMoves() should be changed to self.move(). Otherwise you are working with an unbound Puzzle.

1 Comment

No, move is an un-specified global function. It is not the unbound Puzzle.move method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.