-
Notifications
You must be signed in to change notification settings - Fork 1
/
maze.py
157 lines (118 loc) · 5.73 KB
/
maze.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
151
152
153
154
155
156
157
from wall import Wall
from passage import Passage
import random
import pandas as pd
import numpy as np
class Maze:
def __init__(self, width: int=7, height: int=7, seed: int=0, loops: int=0) -> None:
self.width = width + 1 if width % 2 == 0 else width
self.height = height + 1 if height % 2 == 0 else height
self.seed = seed
self.loops = loops
self.area = np.array([[Wall(x,y) for y in range(self.width)] for x in range(self.height)])
random.seed(self.seed)
self.spawn_x, self.spawn_y = (random.choice([i for i in range(1, self.height, 2)]),
random.choice([j for j in range(1, self.width, 2)]))
self.area[self.spawn_x, self.spawn_y] = Passage(self.spawn_x, self.spawn_y, self.area)
self.pivot_passages = [self.area[self.spawn_x, self.spawn_y]]
self.frontier_passages = set(self.area[self.spawn_x, self.spawn_y].connections)
self.passages = [Passage(self.spawn_x, self.spawn_y, self.area)]
self.generate()
self.start = self.random_starting_position()
self.end = self.random_end_position()
def random_starting_position(self):
"""
Generates a random start position for a the maze
"""
start = random.choice(self.passages)
self.area[(start.x, start.y)] = 3
self.passages.remove(start)
return (start.x, start.y)
def random_end_position(self):
"""
Generates a random end position for a the maze
"""
end = random.choice(self.passages)
self.area[(end.x, end.y)] = 2
self.passages.remove(end)
return (end.x, end.y)
def find(self, pivot_passages, target_passage):
"""
Finds any pivot passages that are connected to the target passage
Returns a random pivot passage that is connected to the target passage
"""
connected_passages = []
for passage in pivot_passages:
if target_passage in passage.connections:
connected_passages.append(passage)
return random.choice(connected_passages)
def linked_passage(self, passage_1, passage_2):
"""
Returns the average position between two passages
"""
# finds the position between the frontier passage and the pivot passage
average_position_x = int((passage_1.x + passage_2.x) / 2)
average_position_y = int((passage_1.y + passage_2.y) / 2)
return (average_position_x, average_position_y)
def generate(self) -> None:
"""
Generates a maze
"""
while len(self.frontier_passages) > 0:
random_pivot_passage = random.choice(sorted(list(self.frontier_passages), key=lambda passage: (passage.x, passage.y)))
connected_passage = self.find(self.pivot_passages, random_pivot_passage)
link_passage_x, link_passage_y = self.linked_passage(connected_passage, random_pivot_passage)
# Connects the Passages together
self.area[link_passage_x, link_passage_y] = Passage(link_passage_x, link_passage_y, self.area)
self.passages.append(self.area[link_passage_x, link_passage_y]) # adds the passage into passages list
connected_passage.connections.remove(random_pivot_passage)
self.frontier_passages.remove(random_pivot_passage)
#Sets the frontier coordinate to a passage
self.area[random_pivot_passage.x, random_pivot_passage.y] = Passage(random_pivot_passage.x, random_pivot_passage.y, self.area)
self.passages.append(self.area[random_pivot_passage.x, random_pivot_passage.y])
self.pivot_passages.append(self.area[random_pivot_passage.x, random_pivot_passage.y])
#updates the number of frontier positions left
self.frontier_passages.update(self.area[random_pivot_passage.x, random_pivot_passage.y].connections)
i = 0
while i < self.loops:
odd_passages = [passage for passage in self.passages if passage.x % 2 == 1 and passage.y % 2 == 1]
random_passage = random.choice(odd_passages)
for passage in random_passage.adjacent_passages:
link_passage = self.area[self.linked_passage(passage, random_passage)]
if isinstance(link_passage, Wall):
self.area[self.linked_passage(passage, random_passage)] = Passage(link_passage.x, link_passage.y, self.area)
i += 1
break
odd_passages.remove(random_passage)
# self.random_starting_position()
# self.random_end_position()
def convert_area(self, index):
"""
Converts the Wall and Passage Objects to 1s and 0s
"""
if isinstance(index, Wall):
index = 1
return index
elif isinstance(index, Passage):
index = 0
return index
else:
return index
def export_df(self):
"""
Takes in the Maze and exports it as a Pandas DataFrame
"""
csv = []
for row in self.area:
csv.append(list(map(self.convert_area, row)))
return pd.DataFrame(np.array(csv))
def __str__(self) -> str:
"""
Returns the maze in a string form
"""
maze_str = ""
for row in self.area:
for obj in row:
maze_str += obj.__str__() + " "
maze_str += "\n"
return maze_str