From ce584d2ae3248090aba80e5988c0dca0f0bd723e Mon Sep 17 00:00:00 2001 From: David GAILLETON Date: Mon, 16 Mar 2026 15:22:18 +0100 Subject: [PATCH 1/7] fix(cell): add getter setter for value add(generators): base for kruskal maze generators --- README.md | 3 +++ src/amaz-lib/__init__.py | 5 +++++ src/{lib/class => amaz-lib/classes}/Cell.py | 6 ++++++ src/amaz-lib/generators/kruskal.py | 7 +++++++ 4 files changed, 21 insertions(+) create mode 100644 src/amaz-lib/__init__.py rename src/{lib/class => amaz-lib/classes}/Cell.py (91%) create mode 100644 src/amaz-lib/generators/kruskal.py diff --git a/README.md b/README.md index e69de29..e34f933 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,3 @@ +The Randomized Kruskal's Algorithm + +The Randomized Prim's Algorithm diff --git a/src/amaz-lib/__init__.py b/src/amaz-lib/__init__.py new file mode 100644 index 0000000..70704a3 --- /dev/null +++ b/src/amaz-lib/__init__.py @@ -0,0 +1,5 @@ +from .classes.Cell import Cell + +__version__ = "1.0.0" +__author__ = "nous" +__all__ = ["Cell"] diff --git a/src/lib/class/Cell.py b/src/amaz-lib/classes/Cell.py similarity index 91% rename from src/lib/class/Cell.py rename to src/amaz-lib/classes/Cell.py index 67d3ee6..d62639b 100644 --- a/src/lib/class/Cell.py +++ b/src/amaz-lib/classes/Cell.py @@ -7,6 +7,12 @@ class Cell(BaseModel): def __str__(self) -> str: return hex(self.value) + def set_value(self, value: int) -> None: + self.value = value + + def get_value(self) -> int: + return self.value + def set_north(self, is_wall: bool) -> None: if (is_wall and self.value | 14 == 15) or ( not is_wall and self.value | 14 != 15 diff --git a/src/amaz-lib/generators/kruskal.py b/src/amaz-lib/generators/kruskal.py new file mode 100644 index 0000000..35032de --- /dev/null +++ b/src/amaz-lib/generators/kruskal.py @@ -0,0 +1,7 @@ +from typing import Generator +import numpy as np +from .. import Cell + + +def kraskal(height: int, width: int) -> Generator[None, None, None]: + maze = np.array([[Cell(value=15) for _ in range(height)] * width]) From b44cffec2c4c7b842efc77afb544e1b52f140343 Mon Sep 17 00:00:00 2001 From: David GAILLETON Date: Mon, 16 Mar 2026 16:48:04 +0100 Subject: [PATCH 2/7] WIP: kruskal algorithm --- src/amaz-lib/__init__.py | 2 +- src/amaz-lib/classes/Maze.py | 15 +++++++++++++++ src/amaz-lib/generators/kruskal.py | 10 +++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 src/amaz-lib/classes/Maze.py diff --git a/src/amaz-lib/__init__.py b/src/amaz-lib/__init__.py index 70704a3..b47ab7d 100644 --- a/src/amaz-lib/__init__.py +++ b/src/amaz-lib/__init__.py @@ -1,5 +1,5 @@ from .classes.Cell import Cell __version__ = "1.0.0" -__author__ = "nous" +__author__ = "us" __all__ = ["Cell"] diff --git a/src/amaz-lib/classes/Maze.py b/src/amaz-lib/classes/Maze.py new file mode 100644 index 0000000..b6fcfbf --- /dev/null +++ b/src/amaz-lib/classes/Maze.py @@ -0,0 +1,15 @@ +from sys import stdout +import numpy as np +from pydantic import BaseModel + + +class Maze(BaseModel): + maze: np.ndarray + + def __str__(self) -> str: + res = "" + for _ in self.maze: + for cell in self.maze: + res += cell + res += "\n" + return res diff --git a/src/amaz-lib/generators/kruskal.py b/src/amaz-lib/generators/kruskal.py index 35032de..e1737e7 100644 --- a/src/amaz-lib/generators/kruskal.py +++ b/src/amaz-lib/generators/kruskal.py @@ -3,5 +3,13 @@ import numpy as np from .. import Cell -def kraskal(height: int, width: int) -> Generator[None, None, None]: +def kraskal( + height: int, width: int +) -> Generator[np.ndarray, None, np.ndarray]: maze = np.array([[Cell(value=15) for _ in range(height)] * width]) + cells_checked = np.array([[False for _ in range(height)] * width]) + excepted_end = np.array([[True for _ in range(height)] * width]) + + while cells_checked != excepted_end: + yield maze + return maze From 272ccefb5210cc3fc2fd3f0db4b3857b5c5eb57f Mon Sep 17 00:00:00 2001 From: David GAILLETON Date: Wed, 18 Mar 2026 11:30:55 +0100 Subject: [PATCH 3/7] new: kruskal generator --- __init__.py | 0 src/amaz-lib/generators/kruskal.py | 15 ---- src/{amaz-lib => amaz_lib}/__init__.py | 0 src/{amaz-lib => amaz_lib}/classes/Cell.py | 16 ++--- src/{amaz-lib => amaz_lib}/classes/Maze.py | 0 src/amaz_lib/generators/kruskal.py | 83 ++++++++++++++++++++++ 6 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 __init__.py delete mode 100644 src/amaz-lib/generators/kruskal.py rename src/{amaz-lib => amaz_lib}/__init__.py (100%) rename src/{amaz-lib => amaz_lib}/classes/Cell.py (75%) rename src/{amaz-lib => amaz_lib}/classes/Maze.py (100%) create mode 100644 src/amaz_lib/generators/kruskal.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/amaz-lib/generators/kruskal.py b/src/amaz-lib/generators/kruskal.py deleted file mode 100644 index e1737e7..0000000 --- a/src/amaz-lib/generators/kruskal.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Generator -import numpy as np -from .. import Cell - - -def kraskal( - height: int, width: int -) -> Generator[np.ndarray, None, np.ndarray]: - maze = np.array([[Cell(value=15) for _ in range(height)] * width]) - cells_checked = np.array([[False for _ in range(height)] * width]) - excepted_end = np.array([[True for _ in range(height)] * width]) - - while cells_checked != excepted_end: - yield maze - return maze diff --git a/src/amaz-lib/__init__.py b/src/amaz_lib/__init__.py similarity index 100% rename from src/amaz-lib/__init__.py rename to src/amaz_lib/__init__.py diff --git a/src/amaz-lib/classes/Cell.py b/src/amaz_lib/classes/Cell.py similarity index 75% rename from src/amaz-lib/classes/Cell.py rename to src/amaz_lib/classes/Cell.py index d62639b..83a6483 100644 --- a/src/amaz-lib/classes/Cell.py +++ b/src/amaz_lib/classes/Cell.py @@ -14,8 +14,8 @@ class Cell(BaseModel): return self.value def set_north(self, is_wall: bool) -> None: - if (is_wall and self.value | 14 == 15) or ( - not is_wall and self.value | 14 != 15 + if (not is_wall and self.value | 14 == 15) or ( + is_wall and self.value | 14 != 15 ): self.value = self.value ^ (1) @@ -23,8 +23,8 @@ class Cell(BaseModel): return self.value & 1 == 1 def set_est(self, is_wall: bool) -> None: - if (is_wall and self.value | 13 == 15) or ( - not is_wall and self.value | 13 != 15 + if (not is_wall and self.value | 13 == 15) or ( + is_wall and self.value | 13 != 15 ): self.value = self.value ^ (2) @@ -32,8 +32,8 @@ class Cell(BaseModel): return self.value & 2 == 2 def set_south(self, is_wall: bool) -> None: - if (is_wall and self.value | 11 == 15) or ( - not is_wall and self.value | 11 != 15 + if (not is_wall and self.value | 11 == 15) or ( + is_wall and self.value | 11 != 15 ): self.value = self.value ^ (4) @@ -41,8 +41,8 @@ class Cell(BaseModel): return self.value & 4 == 4 def set_west(self, is_wall: bool) -> None: - if (is_wall and self.value | 8 == 15) or ( - not is_wall and self.value | 8 != 15 + if (not is_wall and self.value | 8 == 15) or ( + is_wall and self.value | 8 != 15 ): self.value = self.value ^ (8) diff --git a/src/amaz-lib/classes/Maze.py b/src/amaz_lib/classes/Maze.py similarity index 100% rename from src/amaz-lib/classes/Maze.py rename to src/amaz_lib/classes/Maze.py diff --git a/src/amaz_lib/generators/kruskal.py b/src/amaz_lib/generators/kruskal.py new file mode 100644 index 0000000..2a62752 --- /dev/null +++ b/src/amaz_lib/generators/kruskal.py @@ -0,0 +1,83 @@ +from typing import Generator +import numpy as np +from ..classes.Cell import Cell +import math + + +def walls_to_maze( + walls: list[tuple[int, int]], + height: int, + width: int, +) -> np.ndarray: + maze: np.ndarray = np.array( + [[Cell(value=0) for _ in range(width)] for _ in range(height)] + ) + for wall in walls: + x, y = wall + match y - x: + case 1: + maze[math.trunc((x / width))][x % width].set_est(True) + maze[math.trunc((y / width))][y % width].set_west(True) + case 5: + maze[math.trunc((x / width))][x % width].set_south(True) + maze[math.trunc((y / width))][y % width].set_north(True) + return maze + + +def is_in_same_set(sets: list[list[int]], wall: tuple[int, int]) -> bool: + a, b = wall + for set in sets: + if a in set and b in set: + return True + if a in set or b in set: + return False + return False + + +def merge_sets(sets: list[list[int]], wall: tuple[int, int]) -> None: + a, b = wall + base_set = None + for set in sets: + if base_set is None and (a in set or b in set): + base_set = set + elif base_set and (a in set or b in set): + base_set += set + sets.remove(set) + + +def kraskal( + height: int, width: int +) -> Generator[np.ndarray, None, np.ndarray]: + sets = [[i] for i in range(height * width)] + walls = [] + for h in range(height): + for w in range(width - 1): + walls += [(w + (width * h), w + (width * h) + 1)] + for w in range(width): + for h in range(height - 1): + walls += [(w + (width * h), w + (width * h) + width)] + np.random.shuffle(walls) + + yield walls_to_maze(walls, height, width) + for wall in walls: + if not is_in_same_set(sets, wall): + merge_sets(sets, wall) + walls.remove(wall) + yield walls_to_maze(walls, height, width) + return walls_to_maze(walls, height, width) + + +def main(): + try: + for alg in kraskal(10, 10): + maze = alg + # print(maze) + # print() + print(maze) + + except GeneratorExit as maze: + print(maze) + + +if __name__ == "__main__": + main() From c8a13e9d5c5e348ee263e87536f60850cc623a5c Mon Sep 17 00:00:00 2001 From: David GAILLETON Date: Wed, 18 Mar 2026 12:14:10 +0100 Subject: [PATCH 4/7] add output to Maze class --- a_maze_ing.py | 13 ++++++++++++- output_validator.py | 25 +++++++++++++++++++++++++ src/amaz_lib/__init__.py | 4 +++- src/amaz_lib/classes/Cell.py | 2 +- src/amaz_lib/classes/Maze.py | 28 ++++++++++++++++++++-------- src/amaz_lib/generators/kruskal.py | 4 ++-- test.txt | 10 ++++++++++ 7 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 output_validator.py create mode 100644 test.txt diff --git a/a_maze_ing.py b/a_maze_ing.py index 08efe94..ad30819 100644 --- a/a_maze_ing.py +++ b/a_maze_ing.py @@ -1,5 +1,16 @@ +from numpy import ma +from src.amaz_lib import kruskal +from src.amaz_lib import Maze + + def main() -> None: - print("A-Maze-ing !!!") + try: + maze = Maze(maze=None) + for alg in kruskal(10, 10): + maze.set_maze(alg) + maze.export_maze("test.txt") + except Exception as err: + print(err) if __name__ == "__main__": diff --git a/output_validator.py b/output_validator.py new file mode 100644 index 0000000..dfc16eb --- /dev/null +++ b/output_validator.py @@ -0,0 +1,25 @@ +# This script does not check for errors or malformed files. +# It only validates that neighbooring cells sharing a wall have +# both the correct encoding. +# Usage: python3 output_validator.py output_maze.txt + +import sys + +if len(sys.argv) != 2: + print(f"Usage: python3 {sys.argv[0]} ") + sys.exit(1) + +g = [] +for line in open(sys.argv[1]): + if line.strip() == '': + break + g.append([int(c, 16) for c in line.strip(' \t\n\r')]) + +for r in range(len(g)): + for c in range(len(g[0])): + v = g[r][c] + if not all([(r < 1 or v & 1 == (g[r-1][c] >> 2) & 1), + (c >= len(g[0])-1 or (v >> 1) & 1 == (g[r][c+1] >> 3) & 1), + (r >= len(g)-1 or (v >> 2) & 1 == g[r+1][c] & 1), + (c < 1 or (v >> 3) & 1 == (g[r][c-1] >> 1) & 1)]): + print(f'Wrong encoding for ({c},{r})') diff --git a/src/amaz_lib/__init__.py b/src/amaz_lib/__init__.py index b47ab7d..03ae356 100644 --- a/src/amaz_lib/__init__.py +++ b/src/amaz_lib/__init__.py @@ -1,5 +1,7 @@ from .classes.Cell import Cell +from .classes.Maze import Maze +from .generators.kruskal import kruskal __version__ = "1.0.0" __author__ = "us" -__all__ = ["Cell"] +__all__ = ["Cell", "Maze", "kruskal"] diff --git a/src/amaz_lib/classes/Cell.py b/src/amaz_lib/classes/Cell.py index 83a6483..0dbde40 100644 --- a/src/amaz_lib/classes/Cell.py +++ b/src/amaz_lib/classes/Cell.py @@ -5,7 +5,7 @@ class Cell(BaseModel): value: int = Field(ge=0, le=15) def __str__(self) -> str: - return hex(self.value) + return hex(self.value).removeprefix("0x") def set_value(self, value: int) -> None: self.value = value diff --git a/src/amaz_lib/classes/Maze.py b/src/amaz_lib/classes/Maze.py index b6fcfbf..79b1faa 100644 --- a/src/amaz_lib/classes/Maze.py +++ b/src/amaz_lib/classes/Maze.py @@ -1,15 +1,27 @@ -from sys import stdout -import numpy as np -from pydantic import BaseModel +from dataclasses import dataclass +from .Cell import Cell -class Maze(BaseModel): - maze: np.ndarray +@dataclass +class Maze: + maze: list[list[Cell]] + + def get_maze(self) -> list[list[Cell]] | None: + return self.maze + + def set_maze(self, new_maze: list[list[Cell]]) -> None: + self.maze = new_maze def __str__(self) -> str: + if self.maze is None: + return "None" res = "" - for _ in self.maze: - for cell in self.maze: - res += cell + for line in self.maze: + for cell in line: + res += cell.__str__() res += "\n" return res + + def export_maze(self, file_name: str): + with open(file_name, "w") as file: + file.write(self.__str__()) diff --git a/src/amaz_lib/generators/kruskal.py b/src/amaz_lib/generators/kruskal.py index 2a62752..cf45c87 100644 --- a/src/amaz_lib/generators/kruskal.py +++ b/src/amaz_lib/generators/kruskal.py @@ -45,7 +45,7 @@ def merge_sets(sets: list[list[int]], wall: tuple[int, int]) -> None: sets.remove(set) -def kraskal( +def kruskal( height: int, width: int ) -> Generator[np.ndarray, None, np.ndarray]: sets = [[i] for i in range(height * width)] @@ -69,7 +69,7 @@ def kraskal( def main(): try: - for alg in kraskal(10, 10): + for alg in kruskal(10, 10): maze = alg # print(maze) # print() diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..217e942 --- /dev/null +++ b/test.txt @@ -0,0 +1,10 @@ +2a80002a80 +2a80282800 +282aaaa800 +2a82a802a8 +2802800280 +002aaaaa80 +2a80280280 +00282aa828 +002a82aaa8 +2aa8000028 From c14c0435754ae622d62b1bb1bfacdb3989de56d8 Mon Sep 17 00:00:00 2001 From: David GAILLETON Date: Wed, 18 Mar 2026 14:10:05 +0100 Subject: [PATCH 5/7] Rework and some fixes --- Makefile | 2 +- a_maze_ing.py | 7 +-- pyproject.toml | 4 -- src/amaz_lib/MazeGenerator.py | 90 ++++++++++++++++++++++++++++++ src/amaz_lib/__init__.py | 4 +- src/amaz_lib/classes/Cell.py | 2 +- src/amaz_lib/classes/Maze.py | 18 ++++-- src/amaz_lib/generators/kruskal.py | 83 --------------------------- test.txt | 33 +++++++---- 9 files changed, 134 insertions(+), 109 deletions(-) create mode 100644 src/amaz_lib/MazeGenerator.py delete mode 100644 src/amaz_lib/generators/kruskal.py diff --git a/Makefile b/Makefile index 6b7b186..877546f 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ clean: rm -rf __pycache__ .mypy_cache lint: - uv run flake8 . + uv run flake8 . --exclude=.venv uv run mypy . --warn-return-any --warn-unused-ignores --ignore-missing-imports --disallow-untyped-defs --check-untyped-defs lint-strict: diff --git a/a_maze_ing.py b/a_maze_ing.py index ad30819..f2e955f 100644 --- a/a_maze_ing.py +++ b/a_maze_ing.py @@ -1,12 +1,11 @@ -from numpy import ma -from src.amaz_lib import kruskal +from src.amaz_lib import MazeGenerator from src.amaz_lib import Maze def main() -> None: try: - maze = Maze(maze=None) - for alg in kruskal(10, 10): + maze = Maze(maze=None, start=(1, 1), end=(16, 15)) + for alg in MazeGenerator.Kruskal.kruskal(20, 20): maze.set_maze(alg) maze.export_maze("test.txt") except Exception as err: diff --git a/pyproject.toml b/pyproject.toml index ce9d7ed..9b6646b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,3 @@ dev = [ [tool.mypy] python_version = "3.10" -exclude = [ - ".venv", - "venv", -] diff --git a/src/amaz_lib/MazeGenerator.py b/src/amaz_lib/MazeGenerator.py new file mode 100644 index 0000000..63dcd0c --- /dev/null +++ b/src/amaz_lib/MazeGenerator.py @@ -0,0 +1,90 @@ +from typing import Generator +import numpy as np +from .classes.Cell import Cell +import math + + +class MazeGenerator: + class Kruskal: + @staticmethod + def walls_to_maze( + walls: list[tuple[int, int]], height: int, width: int + ) -> np.ndarray: + maze: np.ndarray = np.array( + [[Cell(value=0) for _ in range(width)] for _ in range(height)] + ) + for wall in walls: + x, y = wall + match y - x: + case 1: + maze[math.trunc((x / width))][x % width].set_est(True) + maze[math.trunc((y / width))][y % width].set_west(True) + case 5: + maze[math.trunc((x / width))][x % width].set_south( + True + ) + maze[math.trunc((y / width))][y % width].set_north( + True + ) + return maze + + @staticmethod + def is_in_same_set( + sets: list[list[int]], wall: tuple[int, int] + ) -> bool: + a, b = wall + for set in sets: + if a in set and b in set: + return True + if a in set or b in set: + return False + return False + + @staticmethod + def merge_sets(sets: list[list[int]], wall: tuple[int, int]) -> None: + a, b = wall + base_set = None + for set in sets: + if base_set is None and (a in set or b in set): + base_set = set + elif base_set and (a in set or b in set): + base_set += set + sets.remove(set) + + @classmethod + def kruskal( + cls, height: int, width: int + ) -> Generator[np.ndarray, None, np.ndarray]: + sets = [[i] for i in range(height * width)] + walls = [] + for h in range(height): + for w in range(width - 1): + walls += [(w + (width * h), w + (width * h) + 1)] + for w in range(width): + for h in range(height - 1): + walls += [(w + (width * h), w + (width * h) + width)] + np.random.shuffle(walls) + + yield cls.walls_to_maze(walls, height, width) + for wall in walls: + if not cls.is_in_same_set(sets, wall): + cls.merge_sets(sets, wall) + walls.remove(wall) + yield cls.walls_to_maze(walls, height, width) + return cls.walls_to_maze(walls, height, width) + + +def main(): + try: + for alg in MazeGenerator.Kruskal.kruskal(10, 10): + maze = alg + # print(maze) + # print() + print(maze) + + except GeneratorExit as maze: + print(maze) + + +if __name__ == "__main__": + main() diff --git a/src/amaz_lib/__init__.py b/src/amaz_lib/__init__.py index 03ae356..cf2963d 100644 --- a/src/amaz_lib/__init__.py +++ b/src/amaz_lib/__init__.py @@ -1,7 +1,7 @@ from .classes.Cell import Cell from .classes.Maze import Maze -from .generators.kruskal import kruskal +from .MazeGenerator import MazeGenerator __version__ = "1.0.0" __author__ = "us" -__all__ = ["Cell", "Maze", "kruskal"] +__all__ = ["Cell", "Maze", "MazeGenerator"] diff --git a/src/amaz_lib/classes/Cell.py b/src/amaz_lib/classes/Cell.py index 0dbde40..d6675bc 100644 --- a/src/amaz_lib/classes/Cell.py +++ b/src/amaz_lib/classes/Cell.py @@ -5,7 +5,7 @@ class Cell(BaseModel): value: int = Field(ge=0, le=15) def __str__(self) -> str: - return hex(self.value).removeprefix("0x") + return hex(self.value).removeprefix("0x").upper() def set_value(self, value: int) -> None: self.value = value diff --git a/src/amaz_lib/classes/Maze.py b/src/amaz_lib/classes/Maze.py index 79b1faa..bfc5ab5 100644 --- a/src/amaz_lib/classes/Maze.py +++ b/src/amaz_lib/classes/Maze.py @@ -1,15 +1,19 @@ from dataclasses import dataclass + +import numpy from .Cell import Cell @dataclass class Maze: - maze: list[list[Cell]] + maze: numpy.ndarray + start: tuple[int, int] + end: tuple[int, int] - def get_maze(self) -> list[list[Cell]] | None: + def get_maze(self) -> numpy.ndarray | None: return self.maze - def set_maze(self, new_maze: list[list[Cell]]) -> None: + def set_maze(self, new_maze: numpy.ndarray) -> None: self.maze = new_maze def __str__(self) -> str: @@ -20,8 +24,14 @@ class Maze: for cell in line: res += cell.__str__() res += "\n" + res += "\n" + res += f"{self.start[0]},{self.start[1]}\n" + res += f"{self.end[0]},{self.end[1]}\n" return res - def export_maze(self, file_name: str): + def export_maze(self, file_name: str) -> None: with open(file_name, "w") as file: file.write(self.__str__()) + + def solver(self) -> str: + pass diff --git a/src/amaz_lib/generators/kruskal.py b/src/amaz_lib/generators/kruskal.py deleted file mode 100644 index cf45c87..0000000 --- a/src/amaz_lib/generators/kruskal.py +++ /dev/null @@ -1,83 +0,0 @@ -from typing import Generator -import numpy as np -from ..classes.Cell import Cell -import math - - -def walls_to_maze( - walls: list[tuple[int, int]], - height: int, - width: int, -) -> np.ndarray: - maze: np.ndarray = np.array( - [[Cell(value=0) for _ in range(width)] for _ in range(height)] - ) - for wall in walls: - x, y = wall - match y - x: - case 1: - maze[math.trunc((x / width))][x % width].set_est(True) - maze[math.trunc((y / width))][y % width].set_west(True) - case 5: - maze[math.trunc((x / width))][x % width].set_south(True) - maze[math.trunc((y / width))][y % width].set_north(True) - return maze - - -def is_in_same_set(sets: list[list[int]], wall: tuple[int, int]) -> bool: - a, b = wall - for set in sets: - if a in set and b in set: - return True - if a in set or b in set: - return False - return False - - -def merge_sets(sets: list[list[int]], wall: tuple[int, int]) -> None: - a, b = wall - base_set = None - for set in sets: - if base_set is None and (a in set or b in set): - base_set = set - elif base_set and (a in set or b in set): - base_set += set - sets.remove(set) - - -def kruskal( - height: int, width: int -) -> Generator[np.ndarray, None, np.ndarray]: - sets = [[i] for i in range(height * width)] - walls = [] - for h in range(height): - for w in range(width - 1): - walls += [(w + (width * h), w + (width * h) + 1)] - for w in range(width): - for h in range(height - 1): - walls += [(w + (width * h), w + (width * h) + width)] - np.random.shuffle(walls) - - yield walls_to_maze(walls, height, width) - for wall in walls: - if not is_in_same_set(sets, wall): - merge_sets(sets, wall) - walls.remove(wall) - yield walls_to_maze(walls, height, width) - return walls_to_maze(walls, height, width) - - -def main(): - try: - for alg in kruskal(10, 10): - maze = alg - # print(maze) - # print() - print(maze) - - except GeneratorExit as maze: - print(maze) - - -if __name__ == "__main__": - main() diff --git a/test.txt b/test.txt index 217e942..3ea62f1 100644 --- a/test.txt +++ b/test.txt @@ -1,10 +1,23 @@ -2a80002a80 -2a80282800 -282aaaa800 -2a82a802a8 -2802800280 -002aaaaa80 -2a80280280 -00282aa828 -002a82aaa8 -2aa8000028 +2AAA802AAAA8282AAAA8 +000282A8280282A80028 +002A8280280028280000 +2AA82A82AA82A82AA800 +02A8002A8028002A8280 +282A8282AAA828002AA8 +0028282A8282A82A82A8 +2A8002AA80002A802A80 +002802802A8280028280 +0282AA82A82AA80282A8 +2802AAA8282AA8282AA8 +000002A8028282AAA828 +02AAA800002A82A80000 +2AAAA82A82AA800282A8 +282AA82A8282A82AA828 +00002AAA82828282AAA8 +02A82A80282802A80028 +282A8000280028002AA8 +02AA82A82A82AAAAAAA8 +2A80000002AAAAA80000 + +1,1 +16,15 From 84c4b63a6c4c9ed3c94711dccceb414b27518472 Mon Sep 17 00:00:00 2001 From: David GAILLETON Date: Thu, 19 Mar 2026 13:54:27 +0100 Subject: [PATCH 6/7] ascii print + fix maze generator kruskal --- a_maze_ing.py | 20 ++++++++++++------ src/amaz_lib/MazeGenerator.py | 12 ++++++++++- src/amaz_lib/classes/Maze.py | 23 ++++++++++++++++++++ test.txt | 40 +++++++++++++++++------------------ 4 files changed, 67 insertions(+), 28 deletions(-) diff --git a/a_maze_ing.py b/a_maze_ing.py index f2e955f..cfb67f2 100644 --- a/a_maze_ing.py +++ b/a_maze_ing.py @@ -1,15 +1,21 @@ +import os +from numpy import ma from src.amaz_lib import MazeGenerator from src.amaz_lib import Maze def main() -> None: - try: - maze = Maze(maze=None, start=(1, 1), end=(16, 15)) - for alg in MazeGenerator.Kruskal.kruskal(20, 20): - maze.set_maze(alg) - maze.export_maze("test.txt") - except Exception as err: - print(err) + # try: + maze = Maze(maze=None, start=(1, 1), end=(16, 15)) + for alg in MazeGenerator.Kruskal.kruskal(20, 20): + maze.set_maze(alg) + os.system("clear") + maze.ascii_print() + maze.export_maze("test.txt") + + +# except Exception as err: +# print(err) if __name__ == "__main__": diff --git a/src/amaz_lib/MazeGenerator.py b/src/amaz_lib/MazeGenerator.py index 63dcd0c..024b331 100644 --- a/src/amaz_lib/MazeGenerator.py +++ b/src/amaz_lib/MazeGenerator.py @@ -19,13 +19,23 @@ class MazeGenerator: case 1: maze[math.trunc((x / width))][x % width].set_est(True) maze[math.trunc((y / width))][y % width].set_west(True) - case 5: + case width: maze[math.trunc((x / width))][x % width].set_south( True ) maze[math.trunc((y / width))][y % width].set_north( True ) + for x in range(height): + for y in range(width): + if x == 0: + maze[x][y].set_north(True) + if x == height - 1: + maze[x][y].set_south(True) + if y == 0: + maze[x][y].set_est(True) + if y == width - 1: + maze[x][y].set_west(True) return maze @staticmethod diff --git a/src/amaz_lib/classes/Maze.py b/src/amaz_lib/classes/Maze.py index bfc5ab5..e5f3803 100644 --- a/src/amaz_lib/classes/Maze.py +++ b/src/amaz_lib/classes/Maze.py @@ -35,3 +35,26 @@ class Maze: def solver(self) -> str: pass + + def ascii_print(self) -> None: + for line in self.maze: + if line is self.maze[0]: + for cell in line: + print("_", end="") + if cell.get_north(): + print("__", end="") + else: + print(" ", end="") + print() + for cell in line: + if cell is line[0] and cell.get_west(): + print("|", end="") + if cell.get_south() is True: + print("__", end="") + else: + print(" ", end="") + if cell.get_est() is True: + print("|", end="") + else: + print("_", end="") + print() diff --git a/test.txt b/test.txt index 3ea62f1..4c9352e 100644 --- a/test.txt +++ b/test.txt @@ -1,23 +1,23 @@ -2AAA802AAAA8282AAAA8 -000282A8280282A80028 -002A8280280028280000 -2AA82A82AA82A82AA800 -02A8002A8028002A8280 -282A8282AAA828002AA8 -0028282A8282A82A82A8 -2A8002AA80002A802A80 -002802802A8280028280 -0282AA82A82AA80282A8 -2802AAA8282AA8282AA8 -000002A8028282AAA828 -02AAA800002A82A80000 -2AAAA82A82AA800282A8 -282AA82A8282A82AA828 -00002AAA82828282AAA8 -02A82A80282802A80028 -282A8000280028002AA8 -02AA82A82A82AAAAAAA8 -2A80000002AAAAA80000 +7D53BFD3D57951517D1D +3D12C3903BD03AD4178D +2BAEBEEEAA92EED547C9 +2287ED17AAAC5393FFF0 +6C6951292A87D2AEBD30 +37D43E8686E93AABAB8C +21516D2D47FEE8284049 +6C7857C3FB9116C696D8 +751453D6D2AAC57BE970 +3BA952D17EA83BD05470 +22AAD2907BAE86967B74 +2AA83C2EFC69696FBC35 +686EE96FD7D4783FAD21 +7ED17ED3D57D3EC52FA0 +7B943D16FB7BABD3AFC8 +7407C5297EB82EB84174 +392D53C6912EE9447E9D +62A952BBAAC13EFD7B89 +3AAC3EC6EABAAD557824 +66C7C7D7D6C6C7D556CD 1,1 16,15 From c6c7e6e47e8625d3d716e9d48d3e594676a634c1 Mon Sep 17 00:00:00 2001 From: David GAILLETON Date: Thu, 19 Mar 2026 14:59:18 +0100 Subject: [PATCH 7/7] Generator class rework --- src/amaz_lib/MazeGenerator.py | 150 +++++++++++++++++----------------- src/amaz_lib/classes/Maze.py | 1 + 2 files changed, 77 insertions(+), 74 deletions(-) diff --git a/src/amaz_lib/MazeGenerator.py b/src/amaz_lib/MazeGenerator.py index 024b331..a41536e 100644 --- a/src/amaz_lib/MazeGenerator.py +++ b/src/amaz_lib/MazeGenerator.py @@ -1,87 +1,89 @@ +from abc import ABC, abstractmethod from typing import Generator import numpy as np from .classes.Cell import Cell import math -class MazeGenerator: - class Kruskal: - @staticmethod - def walls_to_maze( - walls: list[tuple[int, int]], height: int, width: int - ) -> np.ndarray: - maze: np.ndarray = np.array( - [[Cell(value=0) for _ in range(width)] for _ in range(height)] - ) - for wall in walls: - x, y = wall - match y - x: - case 1: - maze[math.trunc((x / width))][x % width].set_est(True) - maze[math.trunc((y / width))][y % width].set_west(True) - case width: - maze[math.trunc((x / width))][x % width].set_south( - True - ) - maze[math.trunc((y / width))][y % width].set_north( - True - ) - for x in range(height): - for y in range(width): - if x == 0: - maze[x][y].set_north(True) - if x == height - 1: - maze[x][y].set_south(True) - if y == 0: - maze[x][y].set_est(True) - if y == width - 1: - maze[x][y].set_west(True) - return maze +class MazeGenerator(ABC): + @abstractmethod + @classmethod + def generator( + cls, height: int, width: int + ) -> Generator[np.ndarray, None, np.ndarray]: ... - @staticmethod - def is_in_same_set( - sets: list[list[int]], wall: tuple[int, int] - ) -> bool: - a, b = wall - for set in sets: - if a in set and b in set: - return True - if a in set or b in set: - return False - return False - @staticmethod - def merge_sets(sets: list[list[int]], wall: tuple[int, int]) -> None: - a, b = wall - base_set = None - for set in sets: - if base_set is None and (a in set or b in set): - base_set = set - elif base_set and (a in set or b in set): - base_set += set - sets.remove(set) +class Kruskal(MazeGenerator): + @staticmethod + def walls_to_maze( + walls: list[tuple[int, int]], height: int, width: int + ) -> np.ndarray: + maze: np.ndarray = np.array( + [[Cell(value=0) for _ in range(width)] for _ in range(height)] + ) + for wall in walls: + x, y = wall + match y - x: + case 1: + maze[math.trunc((x / width))][x % width].set_est(True) + maze[math.trunc((y / width))][y % width].set_west(True) + case width: + maze[math.trunc((x / width))][x % width].set_south(True) + maze[math.trunc((y / width))][y % width].set_north(True) + for x in range(height): + for y in range(width): + if x == 0: + maze[x][y].set_north(True) + if x == height - 1: + maze[x][y].set_south(True) + if y == 0: + maze[x][y].set_est(True) + if y == width - 1: + maze[x][y].set_west(True) + return maze - @classmethod - def kruskal( - cls, height: int, width: int - ) -> Generator[np.ndarray, None, np.ndarray]: - sets = [[i] for i in range(height * width)] - walls = [] - for h in range(height): - for w in range(width - 1): - walls += [(w + (width * h), w + (width * h) + 1)] - for w in range(width): - for h in range(height - 1): - walls += [(w + (width * h), w + (width * h) + width)] - np.random.shuffle(walls) + @staticmethod + def is_in_same_set(sets: list[list[int]], wall: tuple[int, int]) -> bool: + a, b = wall + for set in sets: + if a in set and b in set: + return True + if a in set or b in set: + return False + return False - yield cls.walls_to_maze(walls, height, width) - for wall in walls: - if not cls.is_in_same_set(sets, wall): - cls.merge_sets(sets, wall) - walls.remove(wall) - yield cls.walls_to_maze(walls, height, width) - return cls.walls_to_maze(walls, height, width) + @staticmethod + def merge_sets(sets: list[list[int]], wall: tuple[int, int]) -> None: + a, b = wall + base_set = None + for set in sets: + if base_set is None and (a in set or b in set): + base_set = set + elif base_set and (a in set or b in set): + base_set += set + sets.remove(set) + + @classmethod + def generator( + cls, height: int, width: int + ) -> Generator[np.ndarray, None, np.ndarray]: + sets = [[i] for i in range(height * width)] + walls = [] + for h in range(height): + for w in range(width - 1): + walls += [(w + (width * h), w + (width * h) + 1)] + for w in range(width): + for h in range(height - 1): + walls += [(w + (width * h), w + (width * h) + width)] + np.random.shuffle(walls) + + yield cls.walls_to_maze(walls, height, width) + for wall in walls: + if not cls.is_in_same_set(sets, wall): + cls.merge_sets(sets, wall) + walls.remove(wall) + yield cls.walls_to_maze(walls, height, width) + return cls.walls_to_maze(walls, height, width) def main(): diff --git a/src/amaz_lib/classes/Maze.py b/src/amaz_lib/classes/Maze.py index e5f3803..e47c51c 100644 --- a/src/amaz_lib/classes/Maze.py +++ b/src/amaz_lib/classes/Maze.py @@ -2,6 +2,7 @@ from dataclasses import dataclass import numpy from .Cell import Cell +from ..MazeGenerator import MazeGenerator @dataclass