Set up git

This commit is contained in:
Kyler Olsen 2024-11-04 17:05:56 -07:00
commit e41b857206
7 changed files with 332 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__

67
main.py Normal file
View File

@ -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()

225
maze.py Normal file
View File

@ -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)

6
notes/Orgin Shift.txt Normal file
View File

@ -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

15
notes/algorithms.txt Normal file
View File

@ -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

12
notes/algs.txt Normal file
View File

@ -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

6
test.py Normal file
View File

@ -0,0 +1,6 @@
from maze import OriginShift
m = OriginShift(21)
print(m[1,1])
print(m[2,1])
print(m[1,2])