-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgame_manager.py
More file actions
148 lines (120 loc) · 4.8 KB
/
game_manager.py
File metadata and controls
148 lines (120 loc) · 4.8 KB
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
from map import Map
from FileIO import FileIO
from constants import Consts
from screen_manager import Display
from state import State
from node import Node
from heap_hashtable import MinHeap
import time
class GameManager:
map: Map
init_state: State
display: Display
def __init__(self):
self.map, self.init_state = self.parse_map()
# After parsing map it's time to start pygame
self.display = Display(self.map)
def start_search(self, search_type: str) -> (list[State], int, int):
"""Chooses a search between all and returns its result list.
:param search_type Search algorithm type
:returns The result of search"""
result = self.__getattribute__(search_type + "_search")()
# Putting path to goal in list
if search_type in ["bd_bfs", "reverse_bfs"]:
return result
else:
result_list = GameManager.extract_path_list(result)
result_list.pop()
result_list.reverse()
return result_list, result.depth, result.path_cost
def display_states(self, states_list: list[State]) -> None:
"""Gets a list of states and displays it into display object.
:param states_list List of states to show"""
if len(states_list) <= 0:
print("There is no way")
return
self.display.update(self.init_state) # Starting display
self.display.begin_display()
for state in states_list:
time.sleep(Consts.STEP_TIME)
self.display.update(state)
def a_star_search(self) -> Node:
"""Performs an A* search from initial state to goal state.
:returns The node containing the goal state."""
def euclid_distance(point1: tuple[int, int], point2: tuple[int, int]) -> float:
"""Finds euclid distance between two points."""
return ((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2) ** 0.5
def manhattan_distance(point1: tuple[int, int], point2: tuple[int, int]) -> int:
"""Finds manhattan distance between to points."""
d1 = point1[0] - point2[0]
d2 = point1[1] - point2[1]
if d1 < 0:
d1 *= -1
if d2 < 0:
d2 *= -1
return d1 + d2
def heuristic(state: State) -> int:
"""The heuristic function which evaluates steps from a state to goal.
:param state The state to evaluate."""
sum_of_distances = 0
for point in self.map.points:
d = manhattan_distance(point, state.person)
sum_of_distances += d
return sum_of_distances
Node.heuristic = heuristic # Setting all nodes heuristic functions
heap = MinHeap() # Beginning of a star search
visited = set()
root_node = Node(self.init_state)
heap.add(root_node)
while not heap.is_empty():
node = heap.pop()
# Checking goal state
if State.is_goal(node.state, self.map.points):
return node
if node.state not in visited:
visited.add(node.state)
else:
continue
# A* search
actions = State.successor(node.state, self.map)
for child in node.expand(actions):
heap.add(child)
@staticmethod
def parse_map() -> (Map, State):
"""Uses map file to create a map object in the game.
:returns The map object and the initial state"""
map_array = FileIO.read_line_by_line(Consts.MAP_FILE)
sizes = map_array.pop(0)
h, w = int(sizes[0]), int(sizes[1])
map_object = Map(h, w)
# Variables to read from map
points = []
person = (0, 0)
for j, row in enumerate(map_array):
for i, col in enumerate(row):
if len(col) > 1: # If there is an object in map
if col[1] == "p":
points.append((j, i))
elif col[1] == "r":
person = (j, i)
row[i] = col[0]
map_object.append_row(row) # Append row to map
map_object.set_points(points)
return map_object, State(person)
@staticmethod
def extract_path_list(node: Node) -> list[State]:
result_list = []
watchdog = 0
while node is not None:
watchdog += 1
if watchdog > 1000:
raise Exception("Watchdog limit exceeded")
result_list.append(node.state)
node = node.parent
return result_list
@staticmethod
def state_in_list_of_nodes(state: State, nodes_list: list[Node]) -> bool:
for node in nodes_list:
if node.state == state:
return True
return False