-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path8-puzzle-solution-using-a-star.py
118 lines (92 loc) · 3.56 KB
/
8-puzzle-solution-using-a-star.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
# in the name of allah
blank_symbol = '*'
GOAL = [[1, 2, 3], [4, 5, 6], [7, 8, blank_symbol]]
def find_position(state, value):
for i in range(3):
for j in range(3):
if state[i][j] == value:
return Position(j, i)
def get_heuristic_value(state):
def get_manhattan_distance(value):
current_position = find_position(state, value)
goal_position = find_position(GOAL, value)
return abs(goal_position.width - current_position.width) + abs(goal_position.height - current_position.height)
heuristic_value = 0
for i in range(3):
for j in range(3):
if state[i][j] != blank_symbol:
heuristic_value += get_manhattan_distance(state[i][j])
return heuristic_value
class Position:
def __init__(self, width, height):
self.width = width
self.height = height
# states that exists in frontier
class LeafStatus:
# g : distance from root (initial state)
# h : heuristic value for this state
def __init__(self, state, g, parent):
self.state = state
self.g = g
self.h = get_heuristic_value(state)
self.f = g + self.h
self.parent = parent
def goal_test(state):
return state == GOAL
# expand leaf if frontier and update frontier
def expand(leaf: LeafStatus):
frontier.remove(leaf)
explored.append(leaf.state)
for arrow in ['right', 'left', 'top', 'bottom']:
if can_move(leaf.state, arrow):
# because in python Parameters are passed by reference, so we keep a copy of state
copy_state = [[x for x in y] for y in leaf.state]
move(copy_state, arrow)
if copy_state not in explored:
new_leaf = LeafStatus(copy_state, leaf.g + 1, leaf)
frontier.append(new_leaf)
def find_blank(state):
return find_position(state, blank_symbol)
def can_move(state, direction):
position = find_blank(state)
if direction == 'right':
return position.width != 2
elif direction == 'left':
return position.width != 0
elif direction == 'top':
return position.height != 0
elif direction == 'bottom':
return position.height != 2
def move(state, direction):
if can_move(state, direction):
b_width = find_blank(state).width
b_height = find_blank(state).height
if direction == 'right':
state[b_height][b_width] = state[b_height][b_width + 1]
state[b_height][b_width + 1] = blank_symbol
elif direction == 'left':
state[b_height][b_width] = state[b_height][b_width - 1]
state[b_height][b_width - 1] = blank_symbol
elif direction == 'top':
state[b_height][b_width] = state[b_height - 1][b_width]
state[b_height - 1][b_width] = blank_symbol
elif direction == 'bottom':
state[b_height][b_width] = state[b_height + 1][b_width]
state[b_height + 1][b_width] = blank_symbol
initial_state = [[4, 6, 5], [7, 1, 8], [3, blank_symbol, 2]]
frontier = [LeafStatus(initial_state, 0, None)]
selected_leaf = frontier[0]
explored = []
while not goal_test(selected_leaf.state):
for leaf in frontier:
selected_leaf = frontier[0]
if leaf.f < selected_leaf.f:
selected_leaf = leaf
expand(selected_leaf)
print(selected_leaf.state)
a=selected_leaf
while a.parent!=None:
for i in range(3):
print(a.parent.state[i])
print('\n\n')
a=a.parent