Implemented Aldous-Broder-Wilson Algorithm
This commit is contained in:
parent
afec3c04de
commit
aa3b405188
160
maze.py
160
maze.py
|
@ -1013,3 +1013,163 @@ class AldousBroder(VectorMaze):
|
||||||
if start[1] > end[1]: return VectorEnum.Down
|
if start[1] > end[1]: return VectorEnum.Down
|
||||||
if start[1] < end[1]: return VectorEnum.Up
|
if start[1] < end[1]: return VectorEnum.Up
|
||||||
return VectorEnum.Zero
|
return VectorEnum.Zero
|
||||||
|
|
||||||
|
|
||||||
|
class AldousBroderWilson(VectorMaze):
|
||||||
|
|
||||||
|
__cells: list[list[VectorEnum]]
|
||||||
|
|
||||||
|
__width: int
|
||||||
|
__height: int
|
||||||
|
|
||||||
|
__path: dict[tuple[int,int], VectorEnum]
|
||||||
|
__start: tuple[int,int] | None
|
||||||
|
|
||||||
|
__current: tuple[int,int]
|
||||||
|
__remaining: int
|
||||||
|
|
||||||
|
__switch: float
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
width: int,
|
||||||
|
height: int | None = None,
|
||||||
|
*, switch: float = 0.5
|
||||||
|
):
|
||||||
|
self.__width = width
|
||||||
|
self.__height = height or width
|
||||||
|
|
||||||
|
self.__cells = [
|
||||||
|
list([VectorEnum.Null for _ in range(self.width)])
|
||||||
|
for _ in range(self.height)]
|
||||||
|
|
||||||
|
x, y = random.randint(0,self.width-1), random.randint(0,self.height-1)
|
||||||
|
self.__cells[y][x] = VectorEnum.Zero
|
||||||
|
|
||||||
|
self.__start = None
|
||||||
|
self.__path = {}
|
||||||
|
|
||||||
|
self.__current = (x,y)
|
||||||
|
self.__remaining = self.width * self.height - 1
|
||||||
|
|
||||||
|
self.__switch = switch
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self) -> int:
|
||||||
|
return self.__width
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self) -> int:
|
||||||
|
return self.__height
|
||||||
|
|
||||||
|
@property
|
||||||
|
def highlighted(self) -> tuple[int,int] | None:
|
||||||
|
if self.__start is not None:
|
||||||
|
for key, value in self.__path.items():
|
||||||
|
if value == VectorEnum.Zero:
|
||||||
|
return key
|
||||||
|
elif self.__remaining > 0: return self.__current
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __getitem__(self, index: tuple[int,int]) -> VectorEnum:
|
||||||
|
x, y = index
|
||||||
|
return self.__cells[y][x]
|
||||||
|
|
||||||
|
def secondary(self, index: tuple[int,int]) -> VectorEnum:
|
||||||
|
if self.__start is not None:
|
||||||
|
if index in self.__path.keys():
|
||||||
|
cell: tuple[int,int] = self.__start
|
||||||
|
while self.__path.get(cell, VectorEnum.Zero) != VectorEnum.Zero:
|
||||||
|
if cell == index: return self.__path[cell]
|
||||||
|
cell = self.__next(cell, self.__path[cell])
|
||||||
|
return VectorEnum.Null
|
||||||
|
|
||||||
|
def step(self) -> bool:
|
||||||
|
if self.highlighted is not None and self.__start is not None:
|
||||||
|
highlighted = self.highlighted
|
||||||
|
neighbors = self._neighbors(highlighted)
|
||||||
|
cell = neighbors[random.randint(0, len(neighbors)-1)]
|
||||||
|
self.__path[highlighted] = self.__direction_wilson(
|
||||||
|
highlighted, cell)
|
||||||
|
if self.__cells[cell[1]][cell[0]] == VectorEnum.Null:
|
||||||
|
self.__path[cell] = VectorEnum.Zero
|
||||||
|
self.__optimize_path()
|
||||||
|
else:
|
||||||
|
cell: tuple[int,int] = self.__start
|
||||||
|
while self.__path.get(cell, VectorEnum.Zero) != VectorEnum.Zero:
|
||||||
|
self.__cells[cell[1]][cell[0]] = self.__path[cell]
|
||||||
|
cell = self.__next(cell, self.__path[cell])
|
||||||
|
self.__remaining -= len(self.__path)
|
||||||
|
self.__start = self.__new_start()
|
||||||
|
if self.__start is not None:
|
||||||
|
self.__path = {self.__start: VectorEnum.Zero}
|
||||||
|
else:
|
||||||
|
self.__path = {}
|
||||||
|
return True
|
||||||
|
elif self.highlighted is not None:
|
||||||
|
neighbors = self._neighbors(self.highlighted)
|
||||||
|
cell = neighbors[random.randint(0,len(neighbors)-1)]
|
||||||
|
if self.__cells[cell[1]][cell[0]] == VectorEnum.Null:
|
||||||
|
self.__cells[cell[1]][cell[0]] = self.__direction_aldous_broder(
|
||||||
|
self.highlighted, cell)
|
||||||
|
self.__remaining -= 1
|
||||||
|
self.__current = cell
|
||||||
|
if self.__remaining / (self.width * self.height) < self.__switch:
|
||||||
|
self.__start = self.__new_start()
|
||||||
|
if self.__start is not None:
|
||||||
|
self.__path = {self.__start: VectorEnum.Zero}
|
||||||
|
return True
|
||||||
|
else: return False
|
||||||
|
|
||||||
|
def __optimize_path(self):
|
||||||
|
if self.__start is not None:
|
||||||
|
purge = set(self.__path.keys())
|
||||||
|
cell: tuple[int,int] = self.__start
|
||||||
|
purge.remove(cell)
|
||||||
|
while self.__path.get(cell, VectorEnum.Zero) != VectorEnum.Zero:
|
||||||
|
cell = self.__next(cell, self.__path[cell])
|
||||||
|
purge.remove(cell)
|
||||||
|
for cell in purge:
|
||||||
|
del self.__path[cell]
|
||||||
|
|
||||||
|
def __new_start(self) -> tuple[int, int] | None:
|
||||||
|
empty = []
|
||||||
|
for x in range(self.width):
|
||||||
|
for y in range(self.height):
|
||||||
|
if self.__cells[y][x] == VectorEnum.Null:
|
||||||
|
empty.append((x,y))
|
||||||
|
if empty: return empty[random.randint(0,len(empty)-1)]
|
||||||
|
else: return None
|
||||||
|
|
||||||
|
def __direction_wilson(
|
||||||
|
self,
|
||||||
|
start: tuple[int,int],
|
||||||
|
end: tuple[int,int],
|
||||||
|
) -> VectorEnum:
|
||||||
|
if start[0] > end[0]: return VectorEnum.Left
|
||||||
|
if start[0] < end[0]: return VectorEnum.Right
|
||||||
|
if start[1] > end[1]: return VectorEnum.Up
|
||||||
|
if start[1] < end[1]: return VectorEnum.Down
|
||||||
|
return VectorEnum.Zero
|
||||||
|
|
||||||
|
def __direction_aldous_broder(
|
||||||
|
self,
|
||||||
|
start: tuple[int,int],
|
||||||
|
end: tuple[int,int],
|
||||||
|
) -> VectorEnum:
|
||||||
|
if start[0] > end[0]: return VectorEnum.Right
|
||||||
|
if start[0] < end[0]: return VectorEnum.Left
|
||||||
|
if start[1] > end[1]: return VectorEnum.Down
|
||||||
|
if start[1] < end[1]: return VectorEnum.Up
|
||||||
|
return VectorEnum.Zero
|
||||||
|
|
||||||
|
def __next(
|
||||||
|
self,
|
||||||
|
index: tuple[int,int],
|
||||||
|
direction: VectorEnum,
|
||||||
|
) -> tuple[int,int]:
|
||||||
|
if direction == VectorEnum.Up: return index[0], index[1]-1
|
||||||
|
elif direction == VectorEnum.Down: return index[0], index[1]+1
|
||||||
|
elif direction == VectorEnum.Left: return index[0]-1, index[1]
|
||||||
|
elif direction == VectorEnum.Right: return index[0]+1, index[1]
|
||||||
|
else: return index[0], index[1]
|
||||||
|
|
|
@ -7,6 +7,6 @@
|
||||||
+ Prim's Algorithm
|
+ Prim's Algorithm
|
||||||
+ Wilson's Algorithm
|
+ Wilson's Algorithm
|
||||||
+ Aldous-Broder Algorithm
|
+ Aldous-Broder Algorithm
|
||||||
- Aldous-Broder-Wilson Algorithm
|
+ Aldous-Broder-Wilson Algorithm
|
||||||
- Kruskal's Algorithm
|
- Kruskal's Algorithm
|
||||||
- Eller's Algorithm
|
- Eller's Algorithm
|
||||||
|
|
|
@ -124,7 +124,8 @@ VEC_MAZE_SIZE = (MAZE_SIZE + 1) // 2
|
||||||
# my_maze = maze.RecursiveDivision(MAZE_SIZE, binary=True)
|
# my_maze = maze.RecursiveDivision(MAZE_SIZE, binary=True)
|
||||||
# my_maze = maze.VectorWrapper(maze.Prim(VEC_MAZE_SIZE))
|
# my_maze = maze.VectorWrapper(maze.Prim(VEC_MAZE_SIZE))
|
||||||
# my_maze = maze.VectorWrapper(maze.Wilson(VEC_MAZE_SIZE))
|
# my_maze = maze.VectorWrapper(maze.Wilson(VEC_MAZE_SIZE))
|
||||||
my_maze = maze.VectorWrapper(maze.AldousBroder(VEC_MAZE_SIZE))
|
# my_maze = maze.VectorWrapper(maze.AldousBroder(VEC_MAZE_SIZE))
|
||||||
|
my_maze = maze.VectorWrapper(maze.AldousBroderWilson(VEC_MAZE_SIZE))
|
||||||
|
|
||||||
# for _ in range(512): my_maze.step()
|
# for _ in range(512): my_maze.step()
|
||||||
# for _ in range(2048): my_maze.step()
|
# for _ in range(2048): my_maze.step()
|
||||||
|
|
Loading…
Reference in New Issue