Reversed maze cell boolean values and clean up

This commit is contained in:
Kyler Olsen 2024-11-09 23:50:24 -07:00
parent f79b8bdb3e
commit e583199976
3 changed files with 174 additions and 81 deletions

10
game.py
View File

@ -65,7 +65,7 @@ def draw_map(
for y in range(world_map.height):
for x in range(world_map.width):
if not world_map[x, y]:
if world_map[x, y]:
pygame.draw.rect(screen, pygame.Color(255,255,255), pygame.Rect(
(pygame.Vector2(x, y)) +
(pygame.Vector2(screen.size) // 2), (1, 1)))
@ -96,7 +96,8 @@ def draw_game(
pygame.draw.line(
screen,
pygame.Color(192,192,192) if side else pygame.Color(255,255,255),
pygame.Color(192,192,192) if side else
pygame.Color(255,255,255),
(x, draw_start),
(x, draw_end),
)
@ -108,7 +109,8 @@ def ray(
max_dis_squared: int = 10_000,
debug: bool = False
) -> tuple[float, int | None]:
delta = pygame.Vector2(1/max(abs(ray_dir.x),1e-3),1/max(abs(ray_dir.y),1e-3))
delta = pygame.Vector2(
1/max(abs(ray_dir.x),1e-3),1/max(abs(ray_dir.y),1e-3))
map_pos = pygame.Vector2(int(ray_pos.x),int(ray_pos.y))
step = pygame.Vector2(0,0)
side_dis = pygame.Vector2(0,0)
@ -145,7 +147,7 @@ def ray(
map_pos.y >= 0 and
map_pos.x < world_map.width and
map_pos.y < world_map.height and
world_map[int(map_pos.x),int(map_pos.y)]
not world_map[int(map_pos.x),int(map_pos.y)]
): break
if (

195
maze.py
View File

@ -31,7 +31,7 @@ class Maze(abc.ABC):
return False
def secondary(self, index: tuple[int,int]) -> bool:
return False
return True
def __str__(self) -> str:
s = ""
@ -42,7 +42,8 @@ class Maze(abc.ABC):
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)]
return [list(
[self[x,y] for x in range(self.width)]) for y in range(self.height)]
def _neighbors(self, index: tuple[int,int]) -> list[tuple[int,int]]:
neighbors: list[tuple[int,int]] = []
@ -95,7 +96,8 @@ class VectorMaze(Maze):
return VectorEnum.Null
def __list__(self) -> list[list[VectorEnum]]:
return [list([self[x,y] for x in range(self.width)]) for y in range(self.height)]
return [list(
[self[x,y] for x in range(self.width)]) for y in range(self.height)]
def _neighbors(self, index: tuple[int,int]) -> list[tuple[int,int]]:
neighbors: list[tuple[int,int]] = []
@ -131,7 +133,10 @@ class VectorWrapper(Maze):
@property
def highlighted(self) -> tuple[int,int] | None:
if self.__maze.highlighted is not None:
return self.__from_vec(self.__maze.highlighted[0]), self.__from_vec(self.__maze.highlighted[1])
return (
self.__from_vec(self.__maze.highlighted[0]),
self.__from_vec(self.__maze.highlighted[1])
)
else: return None
def __getitem__(self, index: tuple[int,int]) -> bool:
@ -144,22 +149,26 @@ class VectorWrapper(Maze):
x, y = index
if x % 2 and y % 2:
if key((self.__to_vec(x), self.__to_vec(y))) != VectorEnum.Null:
return True
return False
elif x % 2:
if self.__to_vec(y-1) >= 0:
if key((self.__to_vec(x), self.__to_vec(y-1))) == VectorEnum.Down:
return True
if key((self.__to_vec(x), self.__to_vec(y-1))) == \
VectorEnum.Down:
return False
if self.__to_vec(y+1) < self.__maze.height:
if key((self.__to_vec(x), self.__to_vec(y+1))) == VectorEnum.Up:
return True
if key((self.__to_vec(x), self.__to_vec(y+1))) == \
VectorEnum.Up:
return False
elif y % 2:
if self.__to_vec(x-1) >= 0:
if key((self.__to_vec(x-1), self.__to_vec(y))) == VectorEnum.Right:
return True
if key((self.__to_vec(x-1), self.__to_vec(y))) == \
VectorEnum.Right:
return False
if self.__to_vec(x+1) < self.__maze.width:
if key((self.__to_vec(x+1), self.__to_vec(y))) == VectorEnum.Left:
return True
return False
if key((self.__to_vec(x+1), self.__to_vec(y))) == \
VectorEnum.Left:
return False
return True
def step(self) -> bool: return self.__maze.step()
@ -217,13 +226,14 @@ class RecursiveBacktracker(Maze):
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.__cells = [
list([True 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
self.__cells[self.__stack[-1][1]][self.__stack[-1][0]] = False
@property
def width(self) -> int:
@ -248,15 +258,18 @@ class RecursiveBacktracker(Maze):
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.__cells[y][x] = False
self.__cells[cell[1]][cell[0]] = False
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]]:
return [(x,y) for x,y in self._neighbors(index) if not self[x,y]]
def __unvisited_neighbors(
self,
index: tuple[int,int],
) -> list[tuple[int,int]]:
return [(x,y) for x,y in self._neighbors(index) if self[x,y]]
class OriginShift(VectorMaze):
@ -270,7 +283,9 @@ class OriginShift(VectorMaze):
self.__width = width
self.__height = height or width
self.__cells = [list([self.__start(x,y) for x in range(self.width)]) for y in range(self.height)]
self.__cells = [
list([self.__start(x,y) for x in range(self.width)])
for y in range(self.height)]
@property
def width(self) -> int:
@ -306,13 +321,21 @@ class OriginShift(VectorMaze):
def clone(cls, other: VectorMaze | list[list[VectorEnum]]) -> "OriginShift":
if isinstance(other, VectorMaze):
self = cls(other.width, other.height)
self.__cells = [list([other[x,y] for x in range(other.width)]) for y in range(other.height)]
self.__cells = [
list([other[x,y] for x in range(other.width)])
for y in range(other.height)]
else:
self = cls(len(other[0]), len(other))
self.__cells = [list([other[y][x] for x in range(len(other[0]))]) for y in range(len(other))]
self.__cells = [
list([other[y][x] for x in range(len(other[0]))])
for y in range(len(other))]
return self
def __direction(self, start: tuple[int,int], end: tuple[int,int]) -> VectorEnum:
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
@ -337,7 +360,12 @@ class BinaryTree(VectorMaze):
__x: int
__y: int
def __init__(self, width: int, height: int | None = None, *, bias: int | None = None ):
def __init__(
self,
width: int,
height: int | None = None,
*, bias: int | None = None,
):
self.__width = width
self.__height = height or width
@ -346,7 +374,9 @@ class BinaryTree(VectorMaze):
self.__x = 0
self.__y = 0
self.__cells = [list([VectorEnum.Null for x in range(self.width)]) for y in range(self.height)]
self.__cells = [
list([VectorEnum.Null for _ in range(self.width)])
for _ in range(self.height)]
@property
def width(self) -> int:
@ -370,7 +400,8 @@ class BinaryTree(VectorMaze):
neighbors = self._neighbors(self.highlighted)
if neighbors:
cell = neighbors[random.randint(0,len(neighbors)-1)]
self.__cells[self.__y][self.__x] = self.__direction(self.highlighted, cell)
self.__cells[self.__y][self.__x] = self.__direction(
self.highlighted, cell)
else:
self.__cells[self.__y][self.__x] = VectorEnum.Zero
self.__x += 1
@ -380,7 +411,11 @@ class BinaryTree(VectorMaze):
return True
else: return False
def __direction(self, start: tuple[int,int], end: tuple[int,int]) -> VectorEnum:
def __direction(
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
@ -393,12 +428,14 @@ class BinaryTree(VectorMaze):
if x - 1 >= 0 and (self.__bias & VectorEnum.Left) == VectorEnum.Left:
neighbors.append((x - 1,y))
if x + 1 < self.width and (self.__bias & VectorEnum.Right) == VectorEnum.Right:
neighbors.append((x + 1,y))
if x + 1 < self.width and (self.__bias & VectorEnum.Right) == \
VectorEnum.Right:
neighbors.append((x + 1,y))
if y - 1 >= 0 and (self.__bias & VectorEnum.Up) == VectorEnum.Up:
neighbors.append((x,y - 1))
if y + 1 < self.height and (self.__bias & VectorEnum.Down) == VectorEnum.Down:
neighbors.append((x,y + 1))
if y + 1 < self.height and (self.__bias & VectorEnum.Down) == \
VectorEnum.Down:
neighbors.append((x,y + 1))
return neighbors
@ -424,7 +461,8 @@ class Sidewinder(Maze):
):
self.__width = width
self.__height = height or width
self.__cells = [list([False for _ in range(self.width)]) for _ in range(self.height)]
self.__cells = [
list([True for _ in range(self.width)]) for _ in range(self.height)]
self.__start = start
self.__run_param = run_param
@ -439,7 +477,7 @@ class Sidewinder(Maze):
else:
self.__run = []
self.__cells[self.highlighted[1]][self.highlighted[0]] = True # type: ignore
self.__cells[self.__run[-1][1]][self.__run[-1][0]] = False
@property
def width(self) -> int:
@ -463,13 +501,15 @@ class Sidewinder(Maze):
if hx - 2 >= 0 and self.__start == VectorEnum.Down:
cell = (hx - 2, hy)
carve = hy + 2 >= self.height or random.random() > self.__run_param
carve = (
hy + 2 >= self.height or random.random() > self.__run_param)
elif hx + 2 < self.width and self.__start == VectorEnum.Up:
cell = (hx + 2, hy)
carve = hy - 2 < 0 or random.random() > self.__run_param
elif hy - 2 >= 0 and self.__start == VectorEnum.Right:
cell = (hx, hy - 2)
carve = hx + 2 >= self.width or random.random() > self.__run_param
carve = (
hx + 2 >= self.width or random.random() > self.__run_param)
elif hy + 2 < self.height and self.__start == VectorEnum.Left:
cell = (hx, hy + 2)
carve = hx - 2 < 0 or random.random() > self.__run_param
@ -480,8 +520,8 @@ class Sidewinder(Maze):
if cell is not None and carve:
x = (hx + cell[0]) // 2
y = (hy + cell[1]) // 2
self.__cells[y][x] = True
self.__cells[cell[1]][cell[0]] = True
self.__cells[y][x] = False
self.__cells[cell[1]][cell[0]] = False
self.__run.append(cell)
else:
hx, hy = self.highlighted
@ -492,55 +532,55 @@ class Sidewinder(Maze):
if hx - 2 >= 0:
x, y = (hx - 2, hy)
self.__run.append((x,y))
self.__cells[y][x] = True
self.__cells[y][x] = False
else:
if hy - 2 >= 0:
x, y = (self.width - 2, hy - 2)
self.__run.append((x,y))
self.__cells[y][x] = True
self.__cells[y][x] = False
if sy + 2 < self.height: cell = (sx, sy + 2)
else: cell = None
elif self.__start == VectorEnum.Up:
if hx + 2 < self.width:
x, y = (hx + 2, hy)
self.__run.append((x,y))
self.__cells[y][x] = True
self.__cells[y][x] = False
else:
if hy + 2 < self.height:
x, y = (1, hy + 2)
self.__run.append((x,y))
self.__cells[y][x] = True
self.__cells[y][x] = False
if sy - 2 >= 0: cell = (sx, sy - 2)
else: cell = None
elif self.__start == VectorEnum.Right:
if hy - 2 >= 0:
x, y = (hx, hy - 2)
self.__run.append((x,y))
self.__cells[y][x] = True
self.__cells[y][x] = False
else:
if hx - 2 >= 0:
x, y = (hx - 2, self.height - 2)
self.__run.append((x,y))
self.__cells[y][x] = True
self.__cells[y][x] = False
if sx + 2 < self.height: cell = (sx + 2, sy)
else: cell = None
elif self.__start == VectorEnum.Left:
if hy + 2 < self.height:
x, y = (hx, hy + 2)
self.__run.append((x,y))
self.__cells[y][x] = True
self.__cells[y][x] = False
else:
if hx + 2 < self.width:
x, y = (hx + 2, 1)
self.__run.append((x,y))
self.__cells[y][x] = True
self.__cells[y][x] = False
if sx - 2 >= 0: cell = (sx - 2, sy)
else: cell = None
if cell is not None:
x = (sx + cell[0]) // 2
y = (sy + cell[1]) // 2
self.__cells[y][x] = True
self.__cells[y][x] = False
return True
else: return False
@ -553,7 +593,14 @@ class _Window:
__y_start: int
__y_stop: int
def __init__(self, maze: "RecursiveDivision", x_start: int, x_stop: int, y_start: int, y_stop: int):
def __init__(
self,
maze: "RecursiveDivision",
x_start: int,
x_stop: int,
y_start: int,
y_stop: int,
):
self.__maze = maze
self.__x_start = x_start
self.__x_stop = x_stop
@ -633,7 +680,7 @@ class RecursiveDivision(Maze):
self.__uniform = uniform
self.__depth_first = depth_first
self.__cells = [
list([(0 < x < self.width-1 and 0 < y < self.height-1)
list([(not (0 < x < self.width-1 and 0 < y < self.height-1))
for x in range(self.width)]) for y in range(self.height)]
self.__stack = [
((True if self.__uniform else None),
@ -656,14 +703,14 @@ class RecursiveDivision(Maze):
if self.__split[0]:
axis, y, window = self.__split
x = (random.randint(0, (window.width - 1) // 2) * 2)
self.__cells[window.y(y)][window.x(x)] = True
self.__cells[window.y(y)][window.x(x)] = False
a, b = [
((not axis if self.__uniform else None), w)
for w in window.horizontal_bisect(y)]
else:
axis, x, window = self.__split
y = (random.randint(0, (window.height - 1) // 2) * 2)
self.__cells[window.y(y)][window.x(x)] = True
self.__cells[window.y(y)][window.x(x)] = False
a, b = [
((not axis if self.__uniform else None), w)
for w in window.vertical_bisect(x)]
@ -678,13 +725,13 @@ class RecursiveDivision(Maze):
if self.__binary: y = (((window.height - 3) // 4) * 2) + 1
else: y = (random.randint(0, (window.height - 3) // 2) * 2) + 1
for x in range(window.width):
self.__cells[window.y(y)][window.x(x)] = False
self.__cells[window.y(y)][window.x(x)] = True
self.__split = axis, y, window
else:
if self.__binary: x = (((window.width - 3) // 4) * 2) + 1
else: x = (random.randint(0, (window.width - 3) // 2) * 2) + 1
for y in range(window.height):
self.__cells[window.y(y)][window.x(x)] = False
self.__cells[window.y(y)][window.x(x)] = True
self.__split = axis, x, window
return True
else: return False
@ -699,11 +746,13 @@ class Prim(VectorMaze):
__frontier: set[tuple[int,int]]
def __init__(self, width: int, height: int | None = None, *, bias: int | None = None ):
def __init__(self, width: int, height: int | None = None):
self.__width = width
self.__height = height or width
self.__cells = [list([VectorEnum.Null for _ in range(self.width)]) for _ in range(self.height)]
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)
@ -725,25 +774,35 @@ class Prim(VectorMaze):
def step(self) -> bool:
if self.__frontier:
cell_a = list(self.__frontier)[random.randint(0,len(self.__frontier)-1)]
cell_a = list(
self.__frontier)[random.randint(0,len(self.__frontier)-1)]
self.__frontier.remove(cell_a)
neighbors = self._neighbors(cell_a, True)
cell_b = neighbors.pop(random.randint(0,len(neighbors)-1))
self.__cells[cell_a[1]][cell_a[0]] = self.__direction(cell_a, cell_b)
self.__cells[cell_a[1]][cell_a[0]] = self.__direction(
cell_a, cell_b)
self.__frontier.update(self._neighbors(cell_a, False))
return True
else: return False
def __direction(self, start: tuple[int,int], end: tuple[int,int]) -> VectorEnum:
def __direction(
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 _neighbors(self, index: tuple[int,int], inside=False) -> list[tuple[int,int]]:
def _neighbors(
self,
index: tuple[int,int],
inside=False,
) -> list[tuple[int,int]]:
neighbors: list[tuple[int,int]] = []
x, y = index
@ -779,11 +838,13 @@ class Wilson(VectorMaze):
__path: dict[tuple[int,int], VectorEnum]
__start: tuple[int,int] | None
def __init__(self, width: int, height: int | None = None, *, bias: int | None = None ):
def __init__(self, width: int, height: int | None = None):
self.__width = width
self.__height = height or width
self.__cells = [list([VectorEnum.Null for _ in range(self.width)]) for _ in range(self.height)]
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
@ -865,14 +926,22 @@ class Wilson(VectorMaze):
if empty: return empty[random.randint(0,len(empty)-1)]
else: return None
def __direction(self, start: tuple[int,int], end: tuple[int,int]) -> VectorEnum:
def __direction(
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 __next(self, index: tuple[int,int], direction: VectorEnum) -> tuple[int,int]:
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]

View File

@ -19,24 +19,41 @@ class MazeVisualizer:
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))
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]:
pygame.draw.rect(self.screen, WALL_COLOR,
pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE))
if self.maze.secondary((x, y)):
pygame.draw.rect(self.screen, SECONDARY_COLOR,
pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE))
if self.maze[x, y]:
pygame.draw.rect(
self.screen,
WALL_COLOR,
pygame.Rect(
x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
)
if not self.maze.secondary((x, y)):
pygame.draw.rect(
self.screen,
SECONDARY_COLOR,
pygame.Rect(
x * CELL_SIZE,
y * CELL_SIZE,
CELL_SIZE,
CELL_SIZE
)
)
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))
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()
@ -52,7 +69,8 @@ class MazeVisualizer:
generation_complete = not generation_complete
if event.key == pygame.K_o:
if isinstance(self.maze, maze.VectorWrapper):
self.maze = maze.VectorWrapper(maze.OriginShift.clone(self.maze.maze))
self.maze = maze.VectorWrapper(
maze.OriginShift.clone(self.maze.maze))
if event.key == pygame.K_s:
if generation_complete: self.maze.step()
if event.key == pygame.K_h:
@ -87,10 +105,14 @@ VEC_MAZE_SIZE = (MAZE_SIZE + 1) // 2
# my_maze = maze.RecursiveBacktracker(MAZE_SIZE)
# my_maze = maze.VectorWrapper(maze.OriginShift(VEC_MAZE_SIZE))
# my_maze = maze.VectorWrapper(maze.BinaryTree(VEC_MAZE_SIZE, bias=maze.VectorEnum.Up | maze.VectorEnum.Left))
# my_maze = maze.VectorWrapper(maze.BinaryTree(VEC_MAZE_SIZE, bias=maze.VectorEnum.Up | maze.VectorEnum.Right))
# my_maze = maze.VectorWrapper(maze.BinaryTree(VEC_MAZE_SIZE, bias=maze.VectorEnum.Down | maze.VectorEnum.Left))
# my_maze = maze.VectorWrapper(maze.BinaryTree(VEC_MAZE_SIZE, bias=maze.VectorEnum.Down | maze.VectorEnum.Right))
# my_maze = maze.VectorWrapper(maze.BinaryTree(
# VEC_MAZE_SIZE, bias=maze.VectorEnum.Up | maze.VectorEnum.Left))
# my_maze = maze.VectorWrapper(maze.BinaryTree(
# VEC_MAZE_SIZE, bias=maze.VectorEnum.Up | maze.VectorEnum.Right))
# my_maze = maze.VectorWrapper(maze.BinaryTree(
# VEC_MAZE_SIZE, bias=maze.VectorEnum.Down | maze.VectorEnum.Left))
# my_maze = maze.VectorWrapper(maze.BinaryTree(
# VEC_MAZE_SIZE, bias=maze.VectorEnum.Down | maze.VectorEnum.Right))
# my_maze = maze.Sidewinder(MAZE_SIZE, run_param=0.2)
# my_maze = maze.Sidewinder(MAZE_SIZE, run_param=0.5)
# my_maze = maze.Sidewinder(MAZE_SIZE, run_param=0.8)