Looks like you're going about it the right way, but you need to define the __eq__
and __ne__
methods in the Node class; otherwise node in prev
will always return False
because Python doesn't know how to compare node
to the items in the list. Check out the Python data model documentation for more on how comparisons work on user-defined types.
I grabbed your code and added a couple of (very naive) methods to do the equality checking, and it no longer appears to be hanging. It's also worth noting that your classes ought to be inheriting from the base object
(see below). These are the changes I made (in context):
class Board(object):
def __init__(self, matrix, whitepos=None):
self.matrix = matrix
self.whitepos = whitepos
if not whitepos:
for y in xrange(3):
for x in xrange(3):
if board[y][x] == 0:
self.whitepos = (x, y)
def __eq__(self, o):
# Note that comparing whitepos is not strictly necessary; but I left
# it in as a safety measure in case the board state gets corrupted.
# If speed becomes an issue, take it out.
return (self.matrix, self.whitepos) == (o.matrix, o.whitepos)
class Node(object):
def __init__(self, board, parent):
self.state = board
self.parent = parent
if not parent:
self.g = 0
else:
self.g = parent.g + 1
self.h = heuristic(board)
def test_goal(self):
return is_final_state(self.state)
def expand(self):
children = []
b = self.state
x, y = get_whitepos(b)
if x > 0:
children.append(Node(move(b, x, y, -1, 0), self))
if x < 2:
children.append(Node(move(b, x, y, +1, 0), self))
if y > 0:
children.append(Node(move(b, x, y, 0, -1), self))
if y < 2:
children.append(Node(move(b, x, y, 0, +1), self))
return children
def __eq__(self, o):
# Note that you don't have to compare parents, since your goal
# is to eliminate ANY nodes with the same position.
return self.state == o.state
class Solution(object):
def __init__(self, node, mem_needed, steps):
self.node = node
self.mem_needed = mem_needed
self.iterations = steps
def inc(self, other):
self.node = other.node
self.mem_needed = max(self.mem_needed, other.mem_needed)
self.iterations += other.iterations
#...
print_solution("bl", bl_search(board))
# I commented out all but the first search to avoid cluttering up the output.
With these changes, the code does produce a solution (I'll leave it up to you to verify that it's correct, but here's my output).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
* bl
moves: 20
[[1, 2, 3], [8, 0, 4], [7, 6, 5]]
[[1, 2, 3], [8, 6, 4], [7, 0, 5]]
[[1, 2, 3], [8, 6, 4], [0, 7, 5]]
[[1, 2, 3], [0, 6, 4], [8, 7, 5]]
[[1, 2, 3], [6, 0, 4], [8, 7, 5]]
[[1, 0, 3], [6, 2, 4], [8, 7, 5]]
[[0, 1, 3], [6, 2, 4], [8, 7, 5]]
[[6, 1, 3], [0, 2, 4], [8, 7, 5]]
[[6, 1, 3], [2, 0, 4], [8, 7, 5]]
[[6, 1, 3], [2, 7, 4], [8, 0, 5]]
[[6, 1, 3], [2, 7, 4], [8, 5, 0]]
[[6, 1, 3], [2, 7, 0], [8, 5, 4]]
[[6, 1, 0], [2, 7, 3], [8, 5, 4]]
[[6, 0, 1], [2, 7, 3], [8, 5, 4]]
[[6, 7, 1], [2, 0, 3], [8, 5, 4]]
[[6, 7, 1], [2, 5, 3], [8, 0, 4]]
[[6, 7, 1], [2, 5, 3], [8, 4, 0]]
[[6, 7, 1], [2, 5, 0], [8, 4, 3]]
[[6, 7, 0], [2, 5, 1], [8, 4, 3]]
[[6, 0, 7], [2, 5, 1], [8, 4, 3]]
[[6, 5, 7], [2, 0, 1], [8, 4, 3]]
nodes needed: 44282
iterations: 59930
Hope this helps!