Set up git
This commit is contained in:
commit
e41b857206
|
@ -0,0 +1 @@
|
|||
__pycache__
|
|
@ -0,0 +1,67 @@
|
|||
import pygame
|
||||
import maze
|
||||
import sys
|
||||
|
||||
# Initialize Pygame
|
||||
pygame.init()
|
||||
|
||||
# Constants
|
||||
CELL_SIZE = 10
|
||||
HIGHLIGHT_COLOR = (0, 0, 255) # Blue for highlighted cells
|
||||
WALL_COLOR = (0, 0, 0) # Black for walls
|
||||
PATH_COLOR = (255, 255, 255) # White for paths
|
||||
|
||||
class MazeVisualizer:
|
||||
|
||||
def __init__(self, maze: maze.Maze):
|
||||
self.maze = maze
|
||||
self.screen_width = maze.width * CELL_SIZE
|
||||
self.screen_height = maze.height * CELL_SIZE
|
||||
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
|
||||
pygame.display.set_caption("Maze Generator Visualization")
|
||||
|
||||
def draw_maze(self):
|
||||
self.screen.fill(PATH_COLOR)
|
||||
for y in range(self.maze.height):
|
||||
for x in range(self.maze.width):
|
||||
if not self.maze[x, y]: # Wall
|
||||
pygame.draw.rect(self.screen, WALL_COLOR,
|
||||
pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE))
|
||||
|
||||
# Highlight the current cell
|
||||
if self.maze.highlighted:
|
||||
hx, hy = self.maze.highlighted
|
||||
pygame.draw.rect(self.screen, HIGHLIGHT_COLOR,
|
||||
pygame.Rect(hx * CELL_SIZE, hy * CELL_SIZE, CELL_SIZE, CELL_SIZE))
|
||||
|
||||
def run(self):
|
||||
clock = pygame.time.Clock()
|
||||
running = True
|
||||
generation_complete = False
|
||||
|
||||
while running:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
if event.type == pygame.KEYUP:
|
||||
generation_complete = not generation_complete
|
||||
|
||||
# Only step through the algorithm if it's not finished
|
||||
if not generation_complete:
|
||||
generation_complete = not self.maze.step()
|
||||
|
||||
# Draw the maze regardless of generation state
|
||||
self.draw_maze()
|
||||
pygame.display.flip()
|
||||
clock.tick(10) # Adjust speed as needed
|
||||
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
|
||||
# my_maze = maze.RecursiveBacktracker(63)
|
||||
my_maze = maze.OriginShift(63)
|
||||
# for _ in range(512): my_maze.step()
|
||||
# for _ in range(2048): my_maze.step()
|
||||
for _ in range(16384): my_maze.step()
|
||||
visualizer = MazeVisualizer(my_maze)
|
||||
visualizer.run()
|
|
@ -0,0 +1,225 @@
|
|||
import abc, enum, random
|
||||
|
||||
|
||||
class Maze(abc.ABC):
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def width(self) -> int:
|
||||
pass
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def height(self) -> int:
|
||||
pass
|
||||
|
||||
@property
|
||||
def highlighted(self) -> tuple[int,int] | None:
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def __getitem__(self, index: tuple[int,int]) -> bool:
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def step(self) -> bool: # returns False when algorithm is done
|
||||
pass
|
||||
|
||||
def __str__(self) -> str:
|
||||
s = ""
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
s += ' ' if self[x,y] else 'x'
|
||||
s += '\n'
|
||||
return s
|
||||
|
||||
def __list__(self) -> list[list[bool]]:
|
||||
return [list([self[x,y] for x in range(self.width)]) for y in range(self.height)]
|
||||
|
||||
|
||||
class RecursiveBacktracker(Maze):
|
||||
|
||||
__cells: list[list[bool]]
|
||||
__stack: list[tuple[int,int]]
|
||||
|
||||
__width: int
|
||||
__height: int
|
||||
|
||||
def __init__(self, width: int, height: int | None = None):
|
||||
self.__width = width
|
||||
self.__height = height or width
|
||||
self.__cells = [list([False for _ in range(self.width)]) for _ in range(self.height)]
|
||||
self.__stack = [(
|
||||
(random.randint(0, ((self.width - 1) // 2) - 1) * 2) + 1,
|
||||
(random.randint(0, ((self.height - 1) // 2) - 1) * 2) + 1
|
||||
)]
|
||||
|
||||
self.__cells[self.highlighted[1]][self.highlighted[0]] = True # type: ignore
|
||||
|
||||
@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.__stack:
|
||||
return self.__stack[-1]
|
||||
|
||||
def __getitem__(self, index: tuple[int,int]) -> bool:
|
||||
return self.__cells[index[1]][index[0]]
|
||||
|
||||
def step(self) -> bool:
|
||||
if self.highlighted is not None:
|
||||
neighbors = self.__unvisited_neighbors(self.highlighted)
|
||||
if neighbors:
|
||||
cell = neighbors[random.randint(0,len(neighbors)-1)]
|
||||
x = (self.highlighted[0] + cell[0]) // 2
|
||||
y = (self.highlighted[1] + cell[1]) // 2
|
||||
self.__cells[y][x] = True
|
||||
self.__cells[cell[1]][cell[0]] = True
|
||||
self.__stack.append(cell)
|
||||
else: self.__stack.pop()
|
||||
return True
|
||||
else: return False
|
||||
|
||||
def __unvisited_neighbors(self, index: tuple[int,int]) -> list[tuple[int,int]]:
|
||||
neighbors: list[tuple[int,int]] = []
|
||||
x, y = index
|
||||
|
||||
if x - 2 > 0 and not self[(x - 2,y)]:
|
||||
neighbors.append((x - 2,y))
|
||||
if x + 2 < self.width - 1 and not self[(x + 2,y)]:
|
||||
neighbors.append((x + 2,y))
|
||||
if y - 2 > 0 and not self[(x,y - 2)]:
|
||||
neighbors.append((x,y - 2))
|
||||
if y + 2 < self.height - 1 and not self[(x,y + 2)]:
|
||||
neighbors.append((x,y + 2))
|
||||
|
||||
return neighbors
|
||||
|
||||
|
||||
class VectorEnum(enum.Enum):
|
||||
Zero = 0
|
||||
Up = 1
|
||||
Left = 2
|
||||
Down = 3
|
||||
Right = 4
|
||||
|
||||
|
||||
class OriginShift(Maze):
|
||||
|
||||
__cells: list[list[VectorEnum]]
|
||||
|
||||
__width: int
|
||||
__height: int
|
||||
|
||||
def __init__(self, width: int, height: int | None = None):
|
||||
self.__width = width
|
||||
self.__height = height or width
|
||||
|
||||
self.__cells = [list([self.__start(x,y) for x in range(self.vec_width)]) for y in range(self.vec_height)]
|
||||
|
||||
@property
|
||||
def width(self) -> int:
|
||||
return self.__width
|
||||
|
||||
@property
|
||||
def height(self) -> int:
|
||||
return self.__height
|
||||
|
||||
@property
|
||||
def highlighted(self) -> tuple[int,int] | None:
|
||||
for y, row in enumerate(self.__cells):
|
||||
for x, cell in enumerate(row):
|
||||
if cell == VectorEnum.Zero:
|
||||
return (self.__from_vec(x), self.__from_vec(y))
|
||||
|
||||
def __getitem__(self, index: tuple[int,int]) -> bool:
|
||||
x, y = index
|
||||
# print(index)
|
||||
# print(f"Loc: {((x - 1) / 2)}, {((y - 1) / 2)} - {self.__to_vec(x)}, {self.__to_vec(y)}")
|
||||
if x % 2 and y % 2: return True
|
||||
elif x % 2:
|
||||
# print(f"Down: {self.__to_vec(x)}, {self.__to_vec(y-1)}")
|
||||
if self.__to_vec(y-1) >= 0:
|
||||
# print(f"Down: {self.__cells[self.__to_vec(y-1)][self.__to_vec(x)]}")
|
||||
if self.__cells[self.__to_vec(y-1)][self.__to_vec(x)] == VectorEnum.Down:
|
||||
return True
|
||||
# print(f"Up: {self.__to_vec(x)}, {self.__to_vec(y+1)}")
|
||||
if self.__to_vec(y+1) < self.vec_height:
|
||||
# print(f"Up: {self.__cells[self.__to_vec(y+1)][self.__to_vec(x)]}")
|
||||
if self.__cells[self.__to_vec(y+1)][self.__to_vec(x)] == VectorEnum.Up:
|
||||
return True
|
||||
elif y % 2:
|
||||
# print(f"Left: {self.__to_vec(x-1)}, {self.__to_vec(y)}")
|
||||
if self.__to_vec(x-1) >= 0:
|
||||
# print(f"Left: {self.__cells[self.__to_vec(y)][self.__to_vec(x-1)]}")
|
||||
if self.__cells[self.__to_vec(y)][self.__to_vec(x-1)] == VectorEnum.Right:
|
||||
return True
|
||||
# print(f"Right: {self.__to_vec(x+1)}, {self.__to_vec(y)}")
|
||||
if self.__to_vec(x+1) < self.vec_width:
|
||||
# print(f"Right: {self.__cells[self.__to_vec(y)][self.__to_vec(x+1)]}")
|
||||
if self.__cells[self.__to_vec(y)][self.__to_vec(x+1)] == VectorEnum.Left:
|
||||
return True
|
||||
return False
|
||||
|
||||
def step(self) -> bool:
|
||||
# return True
|
||||
if self.highlighted is not None:
|
||||
x, y = self.__to_vec(self.highlighted[0]), self.__to_vec(self.highlighted[1])
|
||||
neighbors = self.__neighbors((x,y))
|
||||
if neighbors:
|
||||
cell = neighbors[random.randint(0,len(neighbors)-1)]
|
||||
# print((x,y))
|
||||
self.__cells[y][x] = self.__direction((x,y), cell)
|
||||
self.__cells[cell[1]][cell[0]] = VectorEnum.Zero
|
||||
return True
|
||||
else: return False
|
||||
|
||||
def __neighbors(self, index: tuple[int,int]) -> list[tuple[int,int]]:
|
||||
neighbors: list[tuple[int,int]] = []
|
||||
x, y = index
|
||||
|
||||
if x - 1 >= 0:
|
||||
neighbors.append((x - 1,y))
|
||||
if x + 1 < self.vec_width:
|
||||
neighbors.append((x + 1,y))
|
||||
if y - 1 >= 0:
|
||||
neighbors.append((x,y - 1))
|
||||
if y + 1 < self.vec_height:
|
||||
neighbors.append((x,y + 1))
|
||||
|
||||
return neighbors
|
||||
|
||||
def __direction(self, start: tuple[int,int], end: tuple[int,int]) -> VectorEnum:
|
||||
if start[0] - end[0] > 0: return VectorEnum.Left
|
||||
if start[0] - end[0] < 0: return VectorEnum.Right
|
||||
if start[1] - end[1] > 0: return VectorEnum.Up
|
||||
if start[1] - end[1] < 0: return VectorEnum.Down
|
||||
return VectorEnum.Zero
|
||||
|
||||
def __start(self, x: int, y: int) -> VectorEnum:
|
||||
# if x == 0 and y == 0: return VectorEnum.Zero
|
||||
# elif x == 0: return VectorEnum.Up
|
||||
# else: return VectorEnum.Left
|
||||
if x == self.vec_width - 1 and y == self.vec_height - 1: return VectorEnum.Zero
|
||||
elif x == self.vec_width - 1: return VectorEnum.Down
|
||||
else: return VectorEnum.Right
|
||||
|
||||
def __from_vec(self, i: int) -> int:
|
||||
return ((i * 2) + 1)
|
||||
|
||||
def __to_vec(self, i: int) -> int:
|
||||
return ((i - 1) // 2)
|
||||
|
||||
@property
|
||||
def vec_width(self) -> int:
|
||||
return self.__to_vec(self.width)
|
||||
|
||||
@property
|
||||
def vec_height(self) -> int:
|
||||
return self.__to_vec(self.height)
|
|
@ -0,0 +1,6 @@
|
|||
Start with a perfect maze
|
||||
Repeat the following steps:
|
||||
|
||||
Have the origin point to a random neighboring cell
|
||||
that neighboring cell becomes the new origin
|
||||
have the new origin point nowhere
|
|
@ -0,0 +1,15 @@
|
|||
Hunt and Kill
|
||||
Recursive Backtracker
|
||||
Prim's Algorithm
|
||||
Growing Tree
|
||||
Kruskal's Algorithm
|
||||
Eller's Algorithm
|
||||
Sidewinder
|
||||
Binary Tree
|
||||
Recursive Division
|
||||
Binary Division
|
||||
Garth Sorensen Method
|
||||
Wilson's Algorithm
|
||||
Aldous-Broder Algorithm
|
||||
Aldous-Broder-Wilson Hybrid
|
||||
Origin Shift
|
|
@ -0,0 +1,12 @@
|
|||
+ Recursive Backtracking
|
||||
+ Origin Shift
|
||||
- Binary Tree
|
||||
- Sidewinder
|
||||
- Binary Division
|
||||
- Recursive Division
|
||||
- Prim's Algorithm
|
||||
- Aldous-Broder Algorithm
|
||||
- Wilson's Algorithm
|
||||
- Aldous-Broder-Wilson Algorithm
|
||||
- Kruskal's Algorithm
|
||||
- Eller's Algorithm
|
Loading…
Reference in New Issue