2 Commits

Author SHA1 Message Date
da7e c8a13e9d5c add output to Maze class 2026-03-18 12:14:10 +01:00
da7e 272ccefb52 new: kruskal generator 2026-03-18 11:30:55 +01:00
11 changed files with 173 additions and 45 deletions
View File
+12 -1
View File
@@ -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__":
+25
View File
@@ -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]} <output_file>")
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})')
-5
View File
@@ -1,5 +0,0 @@
from .classes.Cell import Cell
__version__ = "1.0.0"
__author__ = "us"
__all__ = ["Cell"]
-15
View File
@@ -1,15 +0,0 @@
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
-15
View File
@@ -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
+7
View File
@@ -0,0 +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", "Maze", "kruskal"]
@@ -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
@@ -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)
+27
View File
@@ -0,0 +1,27 @@
from dataclasses import dataclass
from .Cell import Cell
@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 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__())
+83
View File
@@ -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 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()
+10
View File
@@ -0,0 +1,10 @@
2a80002a80
2a80282800
282aaaa800
2a82a802a8
2802800280
002aaaaa80
2a80280280
00282aa828
002a82aaa8
2aa8000028