7 Commits

Author SHA1 Message Date
Maoake Teriierooiterai 4055a8a7a2 finish to print the 42 2026-03-25 13:58:35 +01:00
Maoake TERIIEROOITERAI a39f348b1e set up the function draw ft 2026-03-24 22:11:54 +01:00
Maoake TERIIEROOITERAI 03c4d206d6 starting the branch parsing need to get a good start on this 2026-03-24 21:21:46 +01:00
Maoake TERIIEROOITERAI 8eb46f601f fixing the DFS and modify the main 2026-03-24 20:47:13 +01:00
da7e 991cdead51 Merge branch 'main' of github.com:maoakeEnterprise/amazing 2026-03-24 16:12:19 +01:00
da7e 6730ebcdb5 It's aliiiive! 2026-03-24 16:10:57 +01:00
da7e a79d4e5c3b algorithm edited but nothing better 2026-03-24 15:33:50 +01:00
4 changed files with 141 additions and 107 deletions
+4 -2
View File
@@ -7,11 +7,13 @@ import src.amaz_lib as g
def main(maze_gen: MazeGenerator) -> None: def main(maze_gen: MazeGenerator) -> None:
# try: # try:
maze = Maze(maze=None) maze = Maze(maze=None)
gen = maze_gen.generator(100, 100) for alg in maze_gen.generator(10, 10):
for alg in gen:
maze.set_maze(alg) maze.set_maze(alg)
os.system("clear") os.system("clear")
maze.ascii_print() maze.ascii_print()
# solver = AStar((1, 1), (14, 18))
# print(solver.solve(maze))
# except Exception as err: # except Exception as err:
# print(err) # print(err)
+3 -4
View File
@@ -26,15 +26,14 @@ class Maze:
return res return res
def ascii_print(self) -> None: def ascii_print(self) -> None:
for line in self.maze: for cell in self.maze[0]:
if line is self.maze[0]:
for cell in line:
print("_", end="") print("_", end="")
if cell.get_north(): if cell.get_north():
print("__", end="") print("__", end="")
else: else:
print(" ", end="") print(" ", end="")
print() print("_")
for line in self.maze:
for cell in line: for cell in line:
if cell is line[0] and cell.get_west(): if cell is line[0] and cell.get_west():
print("|", end="") print("|", end="")
+109 -63
View File
@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Generator from typing import Generator, Set
import numpy as np import numpy as np
from .Cell import Cell from .Cell import Cell
import math import math
@@ -8,14 +8,46 @@ import math
class MazeGenerator(ABC): class MazeGenerator(ABC):
@abstractmethod @abstractmethod
def generator( def generator(
self, height: int, width: int self, height: int, width: int, seed: int = None
) -> Generator[np.ndarray, None, np.ndarray]: ... ) -> Generator[np.ndarray, None, np.ndarray]: ...
@staticmethod
def get_cell_ft(width: int, height: int) -> set:
forty_two = set()
y, x = (int(height / 2), int(width / 2))
forty_two.add((y, x - 1))
forty_two.add((y, x - 2))
forty_two.add((y, x - 3))
forty_two.add((y - 1, x - 3))
forty_two.add((y - 2, x - 3))
forty_two.add((y + 1, x - 1))
forty_two.add((y + 2, x - 1))
forty_two.add((y, x + 1))
forty_two.add((y, x + 2))
forty_two.add((y, x + 3))
forty_two.add((y - 1, x + 3))
forty_two.add((y - 2, x + 3))
forty_two.add((y - 2, x + 2))
forty_two.add((y - 2, x + 1))
forty_two.add((y + 1, x + 1))
forty_two.add((y + 2, x + 1))
forty_two.add((y + 2, x + 2))
forty_two.add((y + 2, x + 3))
return forty_two
class Kruskal(MazeGenerator): class Kruskal(MazeGenerator):
class Set:
def __init__(self, cells: list[int]) -> None:
self.cells: list[int] = cells
class Sets:
def __init__(self, sets: list[Set]) -> None:
self.sets = sets
@staticmethod @staticmethod
def walls_to_maze( def walls_to_maze(
walls: list[tuple[int, int]], height: int, width: int walls: np.ndarray, height: int, width: int
) -> np.ndarray: ) -> np.ndarray:
maze: np.ndarray = np.array( maze: np.ndarray = np.array(
[[Cell(value=0) for _ in range(width)] for _ in range(height)] [[Cell(value=0) for _ in range(width)] for _ in range(height)]
@@ -36,94 +68,115 @@ class Kruskal(MazeGenerator):
if x == height - 1: if x == height - 1:
maze[x][y].set_south(True) maze[x][y].set_south(True)
if y == 0: if y == 0:
maze[x][y].set_est(True)
if y == width - 1:
maze[x][y].set_west(True) maze[x][y].set_west(True)
if y == width - 1:
maze[x][y].set_est(True)
return maze return maze
@staticmethod @staticmethod
def is_in_same_set(sets: list[list[int]], wall: tuple[int, int]) -> bool: def is_in_same_set(sets: Sets, wall: tuple[int, int]) -> bool:
a, b = wall a, b = wall
for set in sets: for set in sets.sets:
if a in set and b in set: if a in set.cells and b in set.cells:
return True return True
if a in set or b in set: elif a in set.cells or b in set.cells:
return False return False
return False return False
@staticmethod @staticmethod
def merge_sets(sets: list[list[int]], wall: tuple[int, int]) -> None: def merge_sets(sets: Sets, wall: tuple[int, int]) -> None:
a, b = wall a, b = wall
base_set = None base_set = None
for set in sets: for i in range(len(sets.sets)):
if base_set is None and (a in set or b in set): if base_set is None and (
base_set = set a in sets.sets[i].cells or b in sets.sets[i].cells
elif base_set and (a in set or b in set): ):
base_set += set base_set = sets.sets[i]
sets.remove(set) elif base_set and (
a in sets.sets[i].cells or b in sets.sets[i].cells
):
base_set.cells += sets.sets[i].cells
sets.sets.pop(i)
return
raise Exception("two sets not found")
def generator( def generator(
self, height: int, width: int self, height: int, width: int, seed: int = None
) -> Generator[np.ndarray, None, np.ndarray]: ) -> Generator[np.ndarray, None, np.ndarray]:
sets = [[i] for i in range(height * width)] if seed is not None:
np.random.seed(seed)
sets = self.Sets([self.Set([i]) for i in range(height * width)])
walls = [] walls = []
for h in range(height): for h in range(height):
for w in range(width - 1): for w in range(width - 1):
walls += [(w + (width * h), w + (width * h) + 1)] walls += [(w + (width * h), w + (width * h) + 1)]
for w in range(width):
for h in range(height - 1): for h in range(height - 1):
walls += [(w + (width * h), w + (width * h) + width)] for w in range(width):
walls += [(w + (width * h), w + (width * (h + 1)))]
print(walls)
np.random.shuffle(walls) np.random.shuffle(walls)
yield self.walls_to_maze(walls, height, width) yield self.walls_to_maze(walls, height, width)
while len(sets.sets) > 1:
for wall in walls: for wall in walls:
if not self.is_in_same_set(sets, wall): if not self.is_in_same_set(sets, wall):
self.merge_sets(sets, wall) self.merge_sets(sets, wall)
walls.remove(wall) walls.remove(wall)
yield self.walls_to_maze(walls, height, width) yield self.walls_to_maze(walls, height, width)
if len(sets.sets) == 1:
break
print(f"nb sets: {len(sets.sets)}")
return self.walls_to_maze(walls, height, width) return self.walls_to_maze(walls, height, width)
class DepthFirstSearch(MazeGenerator): class DepthFirstSearch(MazeGenerator):
def generator(self, width: int, height: int def generator(
self, height: int, width: int, seed: int = None
) -> Generator[np.ndarray, None, np.ndarray]: ) -> Generator[np.ndarray, None, np.ndarray]:
maze = DepthFirstSearch.init_maze(width, height) if seed is not None:
np.random.seed(seed)
maze = self.init_maze(width, height)
forty_two = self.get_cell_ft(width, height)
visited = np.zeros((height, width), dtype=bool) visited = np.zeros((height, width), dtype=bool)
visited = self.lock_cell_ft(visited, forty_two)
path = list() path = list()
w_h = (width, height) w_h = (width, height)
coord = (0, 0) coord = (0, 0)
x, y = coord x, y = coord
first = True first_iteration = True
while path or first_iteration:
first_iteration = False
while path or first:
first = False
visited[y, x] = True visited[y, x] = True
path = DepthFirstSearch.add_cell_visited(coord, path) path = self.add_cell_visited(coord, path)
random_c = DepthFirstSearch.random_cells(visited, coord, w_h)
if len(random_c) == 0: random_c = self.random_cells(visited, coord, w_h)
path = DepthFirstSearch.back_on_step(path, w_h, visited)
if path: if not random_c:
coord = path[-1] path = self.back_on_step(path, w_h, visited)
random_c = DepthFirstSearch.random_cells(visited, coord, w_h)
x, y = coord
if not path: if not path:
break break
coord = path[-1]
wall = DepthFirstSearch.next_step(random_c) random_c = self.random_cells(visited, coord, w_h)
maze[y][x] = DepthFirstSearch.broken_wall(maze[y][x], wall)
coord = DepthFirstSearch.next_cell(x, y, wall)
wall_r = DepthFirstSearch.reverse_path(wall)
x, y = coord x, y = coord
maze[y][x] = DepthFirstSearch.broken_wall(maze[y][x], wall_r)
wall = self.next_step(random_c)
maze[y][x] = self.broken_wall(maze[y][x], wall)
coord = self.next_cell(x, y, wall)
wall_r = self.reverse_path(wall)
x, y = coord
maze[y][x] = self.broken_wall(maze[y][x], wall_r)
yield maze yield maze
return maze return maze
@staticmethod @staticmethod
def init_maze(width: int, height: int) -> np.ndarray: def init_maze(width: int, height: int) -> np.ndarray:
maze = np.array([[Cell(value=15) for _ in range(width)] maze = np.array(
for _ in range(height)]) [[Cell(value=15) for _ in range(width)] for _ in range(height)]
)
return maze return maze
@staticmethod @staticmethod
@@ -168,34 +221,27 @@ class DepthFirstSearch(MazeGenerator):
@staticmethod @staticmethod
def next_cell(x: int, y: int, next: str) -> tuple: def next_cell(x: int, y: int, next: str) -> tuple:
next_step = { next_step = {"N": (0, -1), "S": (0, 1), "W": (-1, 0), "E": (1, 0)}
"N": (0, -1),
"S": (0, 1),
"W": (-1, 0),
"E": (1, 0)
}
add_x, add_y = next_step[next] add_x, add_y = next_step[next]
return (x + add_x, y + add_y) return (x + add_x, y + add_y)
@staticmethod @staticmethod
def reverse_path(next: str) -> str: def reverse_path(direction: str) -> str:
reverse = { return {"N": "S", "S": "N", "W": "E", "E": "W"}[direction]
"N": "S",
"S": "N",
"W": "E",
"E": "W"
}
return reverse[next]
@staticmethod @staticmethod
def back_on_step(path: list, w_h: tuple, visited: np.array) -> list: def back_on_step(path: list, w_h: tuple, visited: np.array) -> list:
while path:
last = path[-1] last = path[-1]
r_cells = DepthFirstSearch.random_cells(visited, last, w_h) if DepthFirstSearch.random_cells(visited, last, w_h):
while len(path) > 0:
path.pop()
if path:
last = path[-1]
r_cells = DepthFirstSearch.random_cells(visited, last, w_h)
if r_cells:
break break
path.pop()
return path return path
@staticmethod
def lock_cell_ft(visited: np.ndarray, forty_two: set[tuple[int]]
) -> np.ndarray:
tab = [cell for cell in forty_two]
for cell in tab:
visited[cell] = True
return visited
+14 -27
View File
@@ -53,25 +53,25 @@ class AStar(MazeSolver):
print(actual) print(actual)
path = { path = {
"N": ( "N": (
self.f((actual[0], actual[1] - 1)) self.f((actual[1] - 1, actual[0]))
if not maze[actual[0]][actual[1]].get_north() and actual[1] > 0 if not maze[actual[1]][actual[0]].get_north() and actual[0] > 0
else None else None
), ),
"E": ( "E": (
self.f((actual[0] + 1, actual[1])) self.f((actual[1], actual[0] + 1))
if not maze[actual[0]][actual[1]].get_est() if not maze[actual[1]][actual[0]].get_est()
and actual[0] < len(maze) - 1 and actual[1] < len(maze) - 1
else None else None
), ),
"S": ( "S": (
self.f((actual[0], actual[1] + 1)) self.f((actual[1] + 1, actual[0]))
if not maze[actual[0]][actual[1]].get_south() if not maze[actual[1]][actual[0]].get_south()
and actual[1] < len(maze[0]) - 1 and actual[0] < len(maze) - 1
else None else None
), ),
"W": ( "W": (
self.f((actual[0] - 1, actual[1])) self.f((actual[1], actual[0] - 1))
if not maze[actual[0]][actual[1]].get_west() and actual[0] > 0 if not maze[actual[1]][actual[0]].get_west() and actual[1] > 0
else None else None
), ),
} }
@@ -107,23 +107,10 @@ class AStar(MazeSolver):
case _: case _:
return actual return actual
def get_path( def get_path(self, maze: np.ndarray) -> str | None:
self, actual: tuple[int, int], maze: np.ndarray, pre: str | None actual = self.start
) -> str | None: path = ""
if actual == self.end:
return ""
paths = self.best_path(maze, actual)
for path in paths:
if paths[path] is None:
continue
if path != pre:
temp = self.get_path(
self.get_next_pos(path, actual),
maze,
self.get_opposit(path),
)
if not temp is None:
return path + temp
return None return None
def solve(self, maze: Maze) -> str: def solve(self, maze: Maze) -> str: