-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathnode.py
150 lines (120 loc) · 4.17 KB
/
node.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#Author: nhny at hcmut.edu.vn
#Course: AI 2016
#Lab 3
# DFS, BFS, Hill Climbing, A-Star with heuristics manhattan distance and hamming distance.
import heapq
class Node(object):
"""
Represent state of board in 8 puzzle problem.
"""
n = 0
def __init__(self, board, prev_state = None):
assert len(board) == 9
self.board = board[:];
self.prev = prev_state
self.step = 0
Node.n += 1
if self.prev:
self.step = self.prev.step + 1
def __eq__(self, other):
"""Check wether two state is equal."""
return self.board == other.board
def __hash__(self):
"""Return hash code of object.
Used for comparing elements in set
"""
h = [0, 0, 0]
h[0] = self.board[0] << 6 | self.board[1] << 3 | self.board[2]
h[1] = self.board[3] << 6 | self.board[4] << 3 | self.board[5]
h[2] = self.board[6] << 6 | self.board[7] << 3 | self.board[8]
h_val = 0
for h_i in h:
h_val = h_val * 31 + h_i
return h_val
def __str__(self):
string_list = [str(i) for i in self.board]
sub_list = (string_list[:3], string_list[3:6], string_list[6:])
return "\n".join([" ".join(l) for l in sub_list])
def manhattan_distance(self):
"""Return Manhattan distance of state."""
#TODO: return Manhattan distance
distance = 0
goal = [1,2,3,4,5,6,7,8,0]
for i in range(1,9):
xs, ys = self.__i2pos(self.board.index(i))
xg, yg = self.__i2pos(goal.index(i))
distance += abs(xs-xg) + abs(ys-yg)
return distance
def manhattan_score(self):
"""Return Manhattan score of state."""
#TODO: return Manhattan score of state
return 0
def hamming_distance(self):
"""Return Hamming distance of state."""
#TODO: return Hamming distance
distance = 0
goal = [1,2,3,4,5,6,7,8,0]
for i in range(9):
if goal[i] != self.board[i]: distance += 1
return distance
def hamming_score(self):
"""Return Hamming distance score of state."""
#TODO return Hamming score of state
return 0
def next(self):
"""Return next states from this state."""
next_moves = []
i = self.board.index(0)
next_moves = (self.move_up(i), self.move_down(i), self.move_left(i), self.move_right(i))
return [s for s in next_moves if s]
def move_right(self, i):
x, y = self.__i2pos(i)
if y < 2:
right_state = Node(self.board, self)
right = self.__pos2i(x, y+1)
right_state.__swap(i, right)
return right_state
def move_left(self, i):
x, y = self.__i2pos(i)
if y > 0:
left_state = Node(self.board, self)
left = self.__pos2i(x, y - 1)
left_state.__swap(i, left)
return left_state
def move_up(self, i):
x, y = self.__i2pos(i)
if x > 0:
up_state = Node(self.board, self)
up = self.__pos2i(x - 1, y)
up_state.__swap(i, up)
return up_state
def move_down(self, i):
x, y = self.__i2pos(i)
if x < 2:
down_state = Node(self.board, self)
down = self.__pos2i(x + 1, y)
down_state.__swap(i, down)
return down_state
def __swap(self, i, j):
self.board[j], self.board[i] = self.board[i], self.board[j]
def __i2pos(self, index):
return (int(index / 3), index % 3)
def __pos2i(self, x, y):
return x * 3 + y
class PriorityQueue:
def __init__(self):
self.heap = []
self.count = 0
def push(self, item, priority):
# FIXME: restored old behaviour to check against old results better
# FIXED: restored to stable behaviour
entry = (priority, self.count, item)
# entry = (priority, item)
heapq.heappush(self.heap, entry)
self.count += 1
def pop(self):
(_, _, item) = heapq.heappop(self.heap)
# (_, item) = heapq.heappop(self.heap)
return item
def isEmpty(self):
return len(self.heap) == 0