-
Notifications
You must be signed in to change notification settings - Fork 1
/
block_state.py
125 lines (88 loc) · 4.48 KB
/
block_state.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
# check if cube1 is on table
def is_on_table(cube1):
return cube1[1] == -1
# The Class that Represents the state of Cubes
class BlockState(object):
def __init__(self, config, n, objects, parent=None, action="Initial", cost=0, f=0, ):
self.n = n
self.cost = cost # int g cost
self.parent = parent # BlockState
self.action = action # string
self.config = config
'''config is a tuple of tuples :
Tuples in config will be : -1 if cube is clear or index of cube over it
AND -1 if cube is on table or index of cube under it .
eg. : (-1,3) this cube is clear and has the cube with index 3 under it'''
self.children = [] # list
self.f = f # f cost
self.objects = objects # a string array which indicates in which place in config is every cube
def expand(self):
index_of_cube1 = 0
for cube1 in self.config:
# if cube1 is clear and free to move
if cube1[0] == -1:
# if cube1 is not on table move cube1 on table and create a child(new configuration of cubes)
if not is_on_table(cube1):
new_config = list(map(list, self.config))
# update config
new_config[cube1[1]][0] = -1
new_config[index_of_cube1][1] = -1
if not self.is_same_with_predecessor(new_config):
action = 'Move(' + self.objects[index_of_cube1] + ',' + self.objects[cube1[1]] + ',table)'
# create child
child = BlockState(tuple(map(tuple, new_config)), self.n, self.objects, parent=self,
action=action,
cost=self.cost + 1)
# update child
self.children.append(child)
# find others free cubes and save their indexes
clear_cubes_indexes = self.find_others_free_cubes(index_of_cube1)
# if there are free cubes move cube1 over other free cube and create a child(new configuration of cubes)
for index_of_cube2 in clear_cubes_indexes:
new_config = list(map(list, self.config))
# update config
new_config[index_of_cube2][0] = index_of_cube1
new_config[index_of_cube1][1] = index_of_cube2
if not is_on_table(cube1):
new_config[cube1[1]][0] = -1
if not self.is_same_with_predecessor(new_config):
if is_on_table(cube1):
action = 'Move(' + self.objects[index_of_cube1] + ',' + 'table' + ',' + self.objects[
index_of_cube2] + ')'
else:
action = 'Move(' + self.objects[index_of_cube1] + ',' + self.objects[cube1[1]] \
+ ',' + self.objects[index_of_cube2] + ')'
# create child
child = BlockState(tuple(map(tuple, new_config)), self.n, self.objects, parent=self,
action=action,
cost=self.cost + 1)
# append on children's list
self.children.append(child)
index_of_cube1 += 1
# find and return indexes of free cubes except cube1's index
def find_others_free_cubes(self, index_of_cube1):
clear_cubes_indexes = []
index_of_cube2 = 0
for cube2 in self.config:
if cube2[0] == -1 and index_of_cube2 != index_of_cube1:
clear_cubes_indexes.append(index_of_cube2)
index_of_cube2 += 1
return clear_cubes_indexes
def is_same_with_predecessor(self, new_config):
state = self
if state.parent is not None:
if list(map(list, state.parent.config)) == new_config:
return True
return False
def __eq__(self, other):
if type(other) is str:
return False
return self.config == tuple(map(tuple, other.config))
def __lt__(self, other):
if type(other) is str:
return False
return self.config < tuple(map(tuple, other.config))
def __gt__(self, other):
if type(other) is str:
return False
return self.config > tuple(map(tuple, other.config))