29 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
Maoake Teriierooiterai c478400640 fix the cell pydantic cause the program was too long 2026-03-24 15:34:43 +01:00
da7e a79d4e5c3b algorithm edited but nothing better 2026-03-24 15:33:50 +01:00
Maoake Teriierooiterai 993bcce857 add generator to my maze generator DFS 2026-03-24 15:22:20 +01:00
Maoake Teriierooiterai a85e342a0a fix conflict 2026-03-24 14:31:49 +01:00
Maoake Teriierooiterai 4d151664ab finish the generator DFS 2026-03-24 14:28:10 +01:00
da7e 8dc00e238a Merge branch 'main' of github.com:maoakeEnterprise/amazing 2026-03-24 13:37:30 +01:00
da7e 0f19d24736 base but not working astar solver 2026-03-24 13:30:32 +01:00
Maoake Teriierooiterai 8b4ef7afce finish the maze generator 2026-03-24 11:10:16 +01:00
Maoake Teriierooiterai 030c6142ba need to fix my infinite while so i make a checkpoint if i need to restore it 2026-03-24 09:34:53 +01:00
Maoake Teriierooiterai f8f0e31598 fix some bug with my unit testing on the DFS 2026-03-23 19:24:32 +01:00
Maoake Teriierooiterai e75e14110d adding my maze need to be tested 2026-03-23 18:49:13 +01:00
Maoake Teriierooiterai 22c44333c1 Merge branch 'main' into parsing 2026-03-19 18:21:30 +01:00
Maoake Teriierooiterai b00ddc7d29 finish the unit testing on the parsing 2026-03-19 18:20:30 +01:00
Maoake Teriierooiterai e4e8ebfc13 adding the unit testing and modify some function for my unit testing its pretty good i learn how to get a good struct for my classes 2026-03-19 18:11:30 +01:00
da7e 0c20d2d063 pytest test_MazeGenerator 2026-03-19 17:45:00 +01:00
da7e 96b39fbeea Maze tester 2026-03-19 17:30:18 +01:00
da7e 97b35fe3eb add Cell tester + FIX: west setter for Cell class 2026-03-19 16:42:45 +01:00
da7e ac13df160f Merge branch 'config_class' 2026-03-19 16:14:04 +01:00
Maoake Teriierooiterai 721a7d00b9 change the name folder test into tests 2026-03-19 16:07:03 +01:00
Maoake Teriierooiterai 6d849a8121 Merge branch 'main' into parsing 2026-03-19 16:02:58 +01:00
Maoake Teriierooiterai a4d55d5692 finish the parsing need to be test 2026-03-19 16:00:19 +01:00
Maoake Teriierooiterai 6b90e5fce5 adding in the parsing class DataMaze the funciton transform_data 2026-03-16 15:37:49 +01:00
Maoake Teriierooiterai 2f5d200c0a training on pytest for the unitesting and doing the parsing with a init in a package need to validate this with my teammate 2026-03-16 15:19:11 +01:00
25 changed files with 761 additions and 88 deletions
+1 -1
View File
@@ -98,7 +98,7 @@ ipython_config.py
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more # This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries. # commonly ignored for libraries.
# uv.lock uv.lock
# poetry # poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+12 -1
View File
@@ -8,7 +8,7 @@ debug:
uv pdb python3 a_maze_ing.py config.txt uv pdb python3 a_maze_ing.py config.txt
clean: clean:
rm -rf __pycache__ .mypy_cache rm -rf __pycache__ .mypy_cache .venv
lint: lint:
uv run flake8 . --exclude=.venv uv run flake8 . --exclude=.venv
@@ -17,3 +17,14 @@ lint:
lint-strict: lint-strict:
uv run flake8 . uv run flake8 .
uv run mypy . --strict uv run mypy . --strict
run_test_parsing:
PYTHONPATH=src uv run pytest tests/test_parsing.py
run_test_dfs:
PYTHONPATH=src uv run pytest tests/test_Depth.py
run_test_maze_gen:
PYTHONPATH=src uv run pytest tests/test_MazeGenerator.py
run_test:
uv run pytest
+9 -8
View File
@@ -1,17 +1,18 @@
import os import os
from numpy import ma
from src.amaz_lib import MazeGenerator
from src.amaz_lib import Maze from src.amaz_lib import Maze
from src.amaz_lib import MazeGenerator
import src.amaz_lib as g
def main() -> None: def main(maze_gen: MazeGenerator) -> None:
# try: # try:
maze = Maze(maze=None, start=(1, 1), end=(16, 15)) maze = Maze(maze=None)
for alg in MazeGenerator.Kruskal.kruskal(20, 20): for alg in maze_gen.generator(10, 10):
maze.set_maze(alg) maze.set_maze(alg)
os.system("clear") os.system("clear")
maze.ascii_print() maze.ascii_print()
maze.export_maze("test.txt") # solver = AStar((1, 1), (14, 18))
# print(solver.solve(maze))
# except Exception as err: # except Exception as err:
@@ -19,4 +20,4 @@ def main() -> None:
if __name__ == "__main__": if __name__ == "__main__":
main() main(g.DepthFirstSearch())
+6
View File
@@ -0,0 +1,6 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
+4
View File
@@ -14,8 +14,12 @@ dependencies = [
dev = [ dev = [
"mypy>=1.19.1", "mypy>=1.19.1",
"flake8>=7.3.0", "flake8>=7.3.0",
"pytest>=9.0.2",
] ]
[tool.mypy] [tool.mypy]
python_version = "3.10" python_version = "3.10"
[tool.pytest.ini_options]
pythonpath = ["src"]
+7 -20
View File
@@ -1,8 +1,10 @@
from pydantic import BaseModel, Field from dataclasses import dataclass
class Cell(BaseModel): @dataclass
value: int = Field(ge=0, le=15) class Cell:
def __init__(self, value: int) -> None:
self.value = value
def __str__(self) -> str: def __str__(self) -> str:
return hex(self.value).removeprefix("0x").upper() return hex(self.value).removeprefix("0x").upper()
@@ -41,25 +43,10 @@ class Cell(BaseModel):
return self.value & 4 == 4 return self.value & 4 == 4
def set_west(self, is_wall: bool) -> None: def set_west(self, is_wall: bool) -> None:
if (not is_wall and self.value | 8 == 15) or ( if (not is_wall and self.value | 7 == 15) or (
is_wall and self.value | 8 != 15 is_wall and self.value | 7 != 15
): ):
self.value = self.value ^ (8) self.value = self.value ^ (8)
def get_west(self) -> bool: def get_west(self) -> bool:
return self.value & 8 == 8 return self.value & 8 == 8
def main() -> None:
c = Cell(value=1)
print(c.get_north())
c.set_north(True)
print(c.get_north())
c.set_north(True)
print(c.get_north())
c.set_north(False)
print(c.get_north())
if __name__ == "__main__":
main()
+7 -12
View File
@@ -25,20 +25,15 @@ class Maze:
res += "\n" res += "\n"
return res return res
def export_maze(self, file_name: str) -> None:
with open(file_name, "w") as file:
file.write(self.__str__())
def ascii_print(self) -> None: def ascii_print(self) -> None:
for cell in self.maze[0]:
print("_", end="")
if cell.get_north():
print("__", end="")
else:
print(" ", end="")
print("_")
for line in self.maze: 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: 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="")
+186 -41
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
@@ -7,16 +7,47 @@ import math
class MazeGenerator(ABC): class MazeGenerator(ABC):
@abstractmethod @abstractmethod
@classmethod
def generator( def generator(
cls, 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)]
@@ -37,66 +68,180 @@ 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")
@classmethod
def generator( def generator(
cls, 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): for w in range(width):
walls += [(w + (width * h), w + (width * h) + width)] walls += [(w + (width * h), w + (width * (h + 1)))]
print(walls)
np.random.shuffle(walls) np.random.shuffle(walls)
yield cls.walls_to_maze(walls, height, width) yield self.walls_to_maze(walls, height, width)
for wall in walls: while len(sets.sets) > 1:
if not cls.is_in_same_set(sets, wall): for wall in walls:
cls.merge_sets(sets, wall) if not self.is_in_same_set(sets, wall):
walls.remove(wall) self.merge_sets(sets, wall)
yield cls.walls_to_maze(walls, height, width) walls.remove(wall)
return cls.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)
def main(): class DepthFirstSearch(MazeGenerator):
try:
for alg in MazeGenerator.Kruskal.kruskal(10, 10):
maze = alg
# print(maze)
# print()
print(maze)
except GeneratorExit as maze: def generator(
print(maze) self, height: int, width: int, seed: int = None
) -> Generator[np.ndarray, None, np.ndarray]:
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 = self.lock_cell_ft(visited, forty_two)
path = list()
w_h = (width, height)
coord = (0, 0)
x, y = coord
first_iteration = True
while path or first_iteration:
first_iteration = False
if __name__ == "__main__": visited[y, x] = True
main() path = self.add_cell_visited(coord, path)
random_c = self.random_cells(visited, coord, w_h)
if not random_c:
path = self.back_on_step(path, w_h, visited)
if not path:
break
coord = path[-1]
random_c = self.random_cells(visited, coord, w_h)
x, y = coord
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
return maze
@staticmethod
def init_maze(width: int, height: int) -> np.ndarray:
maze = np.array(
[[Cell(value=15) for _ in range(width)] for _ in range(height)]
)
return maze
@staticmethod
def add_cell_visited(coord: tuple, path: set) -> list:
path.append(coord)
return path
@staticmethod
def random_cells(visited: np.array, coord: tuple, w_h: tuple) -> list:
rand_cell = []
x, y = coord
width, height = w_h
if y - 1 >= 0 and not visited[y - 1][x]:
rand_cell.append("N")
if y + 1 < height and not visited[y + 1][x]:
rand_cell.append("S")
if x - 1 >= 0 and not visited[y][x - 1]:
rand_cell.append("W")
if x + 1 < width and not visited[y][x + 1]:
rand_cell.append("E")
return rand_cell
@staticmethod
def next_step(rand_cell: list) -> str:
return np.random.choice(rand_cell)
@staticmethod
def broken_wall(cell: Cell, wall: str) -> Cell:
if wall == "N":
cell.set_north(False)
elif wall == "S":
cell.set_south(False)
elif wall == "W":
cell.set_west(False)
elif wall == "E":
cell.set_est(False)
return cell
@staticmethod
def next_cell(x: int, y: int, next: str) -> tuple:
next_step = {"N": (0, -1), "S": (0, 1), "W": (-1, 0), "E": (1, 0)}
add_x, add_y = next_step[next]
return (x + add_x, y + add_y)
@staticmethod
def reverse_path(direction: str) -> str:
return {"N": "S", "S": "N", "W": "E", "E": "W"}[direction]
@staticmethod
def back_on_step(path: list, w_h: tuple, visited: np.array) -> list:
while path:
last = path[-1]
if DepthFirstSearch.random_cells(visited, last, w_h):
break
path.pop()
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
+115 -2
View File
@@ -1,8 +1,121 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from .Maze import Maze from .Maze import Maze
import numpy as np
class MazeSolver(ABC): class MazeSolver(ABC):
def __init__(self, start: tuple[int, int], end: tuple[int, int]) -> None:
self.start = (start[0] - 1, start[1] - 1)
self.end = (end[0] - 1, end[1] - 1)
@abstractmethod @abstractmethod
@classmethod def solve(self, maze: Maze) -> str: ...
def solve(cls, maze: Maze) -> str: ...
class AStar(MazeSolver):
def __init__(self, start: tuple[int, int], end: tuple[int, int]) -> None:
super().__init__(start, end)
def f(self, n):
def g(n: tuple[int, int]) -> int:
res = 0
if n[0] < self.start[0]:
res += self.start[0] - n[0]
else:
res += n[0] - self.start[0]
if n[1] < self.start[1]:
res += self.start[1] - n[1]
else:
res += n[1] - self.start[1]
return res
def h(n: tuple[int, int]) -> int:
res = 0
if n[0] < self.end[0]:
res += self.end[0] - n[0]
else:
res += n[0] - self.end[0]
if n[1] < self.end[1]:
res += self.end[1] - n[1]
else:
res += n[1] - self.end[1]
return res
try:
return g(n) + h(n)
except Exception:
return 1000
def best_path(
self, maze: np.ndarray, actual: tuple[int, int]
) -> dict[str, int | None]:
print(actual)
path = {
"N": (
self.f((actual[1] - 1, actual[0]))
if not maze[actual[1]][actual[0]].get_north() and actual[0] > 0
else None
),
"E": (
self.f((actual[1], actual[0] + 1))
if not maze[actual[1]][actual[0]].get_est()
and actual[1] < len(maze) - 1
else None
),
"S": (
self.f((actual[1] + 1, actual[0]))
if not maze[actual[1]][actual[0]].get_south()
and actual[0] < len(maze) - 1
else None
),
"W": (
self.f((actual[1], actual[0] - 1))
if not maze[actual[1]][actual[0]].get_west() and actual[1] > 0
else None
),
}
return {
k: v for k, v in sorted(path.items(), key=lambda item: item[0])
}
def get_opposit(self, dir: str) -> str:
match dir:
case "N":
return "S"
case "E":
return "W"
case "S":
return "N"
case "W":
return "E"
case _:
return ""
def get_next_pos(
self, dir: str, actual: tuple[int, int]
) -> tuple[int, int]:
match dir:
case "N":
return (actual[0], actual[1] - 1)
case "E":
return (actual[0] + 1, actual[1])
case "S":
return (actual[0], actual[1] + 1)
case "W":
return (actual[0] - 1, actual[1])
case _:
return actual
def get_path(self, maze: np.ndarray) -> str | None:
actual = self.start
path = ""
return None
def solve(self, maze: Maze) -> str:
print(maze)
res = self.get_path(self.start, maze.get_maze(), None)
if res is None:
raise Exception("Path not found")
return res
+5 -3
View File
@@ -1,8 +1,10 @@
from .Cell import Cell from .Cell import Cell
from .Maze import Maze from .Maze import Maze
from .MazeGenerator import MazeGenerator from .MazeGenerator import MazeGenerator, DepthFirstSearch
from .MazeSolver import MazeSolver from .MazeGenerator import Kruskal
from .MazeSolver import MazeSolver, AStar
__version__ = "1.0.0" __version__ = "1.0.0"
__author__ = "us" __author__ = "us"
__all__ = ["Cell", "Maze", "MazeGenerator", "MazeSolver"] __all__ = ["Cell", "Maze", "MazeGenerator",
"MazeSolver", "AStar", "Kruskal", "DepthFirstSearch"]
+97
View File
@@ -0,0 +1,97 @@
class DataMaze:
@staticmethod
def get_file_data(name_file: str) -> str:
with open(name_file, "r") as file:
data = file.read()
if data == "":
raise ValueError("The file is empty")
return data
@staticmethod
def transform_data(data: str) -> dict:
tmp = data.split("\n")
tmp2 = [
value.split("=", 1) for value in tmp
]
data_t = {
value[0]: value[1] for value in tmp2
}
return data_t
@staticmethod
def verif_key_data(data: dict) -> None:
key_test = {
"WIDTH", "HEIGHT", "ENTRY", "EXIT", "OUTPUT_FILE", "PERFECT"
}
set_key = {
key for key in data.keys()
}
if len(set_key) != len(key_test):
raise KeyError("Missing some data the len do not correspond")
res_key = {key for key in set_key if key not in key_test}
if len(res_key) != 0:
raise KeyError("Some Key "
f"do not correspond the keys: {res_key}")
@staticmethod
def convert_values(data: dict):
key_int = {"WIDTH", "HEIGHT"}
key_tuple = {"ENTRY", "EXIT"}
key_bool = {"PERFECT"}
res: dict = {}
for key in key_int:
res.update({key: int(data[key])})
for key in key_tuple:
res.update({key: DataMaze.convert_tuple(data[key])})
for key in key_bool:
res.update({key: DataMaze.convert_bool(data[key])})
res.update({"OUTPUT_FILE": data["OUTPUT_FILE"]})
return res
@staticmethod
def get_data_maze(name_file: str) -> dict:
try:
data_str = DataMaze.get_file_data(name_file)
data_dict = DataMaze.transform_data(data_str)
DataMaze.verif_key_data(data_dict)
data_maze = DataMaze.convert_values(data_dict)
return data_maze
except FileNotFoundError:
print("The file do not exist")
exit()
except PermissionError:
print("We dont have the Permission")
exit()
except ValueError as e:
print(f"Error during the convert or the file is empty: {e}")
exit()
except KeyError as e:
print(f"Error on the key in the file: {e}")
exit()
except IndexError as e:
print("In the function transform Data some data cannot "
f"be splited by '=' because '=' was not present: {e}")
exit()
except AttributeError as e:
print("Error on the "
f"funciton get_data_maze : {e}")
exit()
@staticmethod
def convert_tuple(data: str) -> tuple:
data_t = data.split(",")
if len(data_t) != 2:
raise ValueError("There is too much "
"argument in the coordinate given")
x, y = data_t
tup = (int(x), int(y))
return tup
@staticmethod
def convert_bool(data: str) -> bool:
if data != "True" and data != "False":
raise ValueError("This is not True or False")
if data == "True":
return True
return False
+6
View File
@@ -0,0 +1,6 @@
__version__ = "1.0.0"
__author__ = "mteriier, dgaillet"
from .Parsing import DataMaze
__all__ = ["DataMaze"]
+31
View File
@@ -0,0 +1,31 @@
import pytest
from amaz_lib.Cell import Cell
def test_cell_setter_getter() -> None:
cell = Cell(value=0)
cell.set_north(True)
assert cell.get_north() is True
cell.set_north(False)
assert cell.get_north() is False
cell.set_est(True)
assert cell.get_est() is True
cell.set_est(False)
assert cell.get_est() is False
cell.set_south(True)
assert cell.get_south() is True
cell.set_south(False)
assert cell.get_south() is False
cell.set_west(True)
assert cell.get_west() is True
cell.set_west(False)
assert cell.get_west() is False
cell.set_value(8)
assert cell.get_value() == 8
cell.set_value(0)
assert cell.get_value() == 0
+27
View File
@@ -0,0 +1,27 @@
from amaz_lib.MazeGenerator import DepthFirstSearch
from amaz_lib.Cell import Cell
import numpy as np
class TestDepth:
def test_init_maze(self) -> None:
maze = DepthFirstSearch.init_maze(10, 10)
cell = Cell(value=15)
maze[1][1].set_est(False)
assert maze[0][0].value == cell.value
def test_rand_cells(self) -> None:
w_h = (10, 10)
lst = np.zeros((10, 10), dtype=bool)
lst[0, 0] = True
rand_cells = DepthFirstSearch.random_cells(lst, (0, 1), w_h)
assert len(rand_cells) == 2
def test_next_cell(self) -> None:
coord = (5, 4)
x, y = coord
assert DepthFirstSearch.next_cell(x, y, "N") == (2, 3)
def test_reverse_path(self) -> None:
assert DepthFirstSearch.reverse_path("N") == "S"
+31
View File
@@ -0,0 +1,31 @@
import numpy
from amaz_lib.Cell import Cell
from amaz_lib.Maze import Maze
def test_maze_setter_getter() -> None:
maze = Maze(numpy.array([]))
test = numpy.array(
[
[Cell(value=6), Cell(value=8), Cell(value=11)],
[Cell(value=6), Cell(value=8), Cell(value=11)],
[Cell(value=6), Cell(value=8), Cell(value=11)],
]
)
maze.set_maze(test)
assert numpy.array_equal(maze.get_maze(), test) is True
def test_maze_str() -> None:
test = numpy.array(
[
[Cell(value=6), Cell(value=8), Cell(value=11)],
[Cell(value=6), Cell(value=8), Cell(value=11)],
[Cell(value=6), Cell(value=8), Cell(value=11)],
]
)
maze = Maze(test)
assert maze.__str__() == "68B\n68B\n68B\n"
+14
View File
@@ -0,0 +1,14 @@
import numpy
from amaz_lib.MazeGenerator import DepthFirstSearch
class TestMazeGenerator:
def test_generator(self) -> None:
w_h = (300, 300)
maze = numpy.array([])
generator = DepthFirstSearch().generator(*w_h)
for output in generator:
maze = output
assert maze.shape == w_h
+19
View File
@@ -0,0 +1,19 @@
from amaz_lib.Cell import Cell
import numpy as np
from amaz_lib import AStar, Maze, MazeSolver
def test_solver() -> None:
maze = Maze(
np.array(
[
[Cell(value=13), Cell(value=3), Cell(value=11)],
[Cell(value=9), Cell(value=4), Cell(value=6)],
[Cell(value=12), Cell(value=5), Cell(value=7)],
]
)
)
print(maze)
solver = AStar((1, 1), (3, 3))
res = solver.solve(maze)
assert res == "ESWSEE"
+78
View File
@@ -0,0 +1,78 @@
from parsing.Parsing import DataMaze
import pytest
class TestParsing:
def test_get_data_valid(self):
data = DataMaze.get_file_data("tests/test_txt/config_1.txt")
assert isinstance(data, str) is True
def test_file_error(self):
with pytest.raises(FileNotFoundError):
DataMaze.get_file_data("tete")
# def test_permission_error(self):
# with pytest.raises(PermissionError):
# DataMaze.get_file_data("tests/test_txt/error_1.txt")
def test_empty_file_error(self):
with pytest.raises(ValueError):
DataMaze.get_file_data("tests/test_txt/error_6.txt")
def test_transform_data_valid(self):
data = DataMaze.get_file_data("tests/test_txt/config_1.txt")
data_2 = DataMaze.transform_data(data)
assert isinstance(data_2, dict)
def test_transform__index_error(self):
with pytest.raises(IndexError):
DataMaze.transform_data("asdasdasdasdasdasda\nasdasdas=asdasd")
def test_key_data_error(self):
with pytest.raises(KeyError):
data = DataMaze.get_file_data("tests/test_txt/error_8.txt")
data2 = DataMaze.transform_data(data)
DataMaze.verif_key_data(data2)
def test_key_data_error_2(self):
with pytest.raises(KeyError):
data = DataMaze.get_file_data("tests/test_txt/error_9.txt")
data2 = DataMaze.transform_data(data)
DataMaze.verif_key_data(data2)
def test_convert_int(self):
with pytest.raises(ValueError):
data = DataMaze.get_file_data("tests/test_txt/error_2.txt")
data2 = DataMaze.transform_data(data)
DataMaze.convert_values(data2)
def test_tuple_error(self):
with pytest.raises(ValueError):
DataMaze.convert_tuple("0,3,5,5")
def test_tuple_error1(self):
with pytest.raises(AttributeError):
DataMaze.convert_tuple(None)
def test_bool_error(self):
with pytest.raises(ValueError):
DataMaze.convert_bool("Trueeee")
def test_valid_tuple(self):
assert DataMaze.convert_tuple("7534564654, 78") == (7534564654, 78)
def test_valid_bool(self):
assert DataMaze.convert_bool("False") is False
def test_valid_bool1(self):
assert DataMaze.convert_bool("True") is True
def test_data_maze(self):
data = DataMaze.get_data_maze("tests/test_txt/config_1.txt")
assert data["WIDTH"] == 200
assert data["HEIGHT"] == 100
assert data["ENTRY"] == (0, 0)
assert data["EXIT"] == (19, 14)
assert data["OUTPUT_FILE"] == "maze.txt"
assert data["PERFECT"] is True
+6
View File
@@ -0,0 +1,6 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
+6
View File
@@ -0,0 +1,6 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
+6
View File
@@ -0,0 +1,6 @@
WIDTH=caca
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
View File
+4
View File
@@ -0,0 +1,4 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
+7
View File
@@ -0,0 +1,7 @@
WIDTH=200
HEIGHT=100
ENTRY=0,0
EXIT=19,14
OUTPUT_FILE=maze.txt
PERFECT=True
PIPI=tut
Generated
+77
View File
@@ -20,6 +20,7 @@ dependencies = [
dev = [ dev = [
{ name = "flake8" }, { name = "flake8" },
{ name = "mypy" }, { name = "mypy" },
{ name = "pytest" },
] ]
[package.metadata] [package.metadata]
@@ -32,6 +33,7 @@ requires-dist = [
dev = [ dev = [
{ name = "flake8", specifier = ">=7.3.0" }, { name = "flake8", specifier = ">=7.3.0" },
{ name = "mypy", specifier = ">=1.19.1" }, { name = "mypy", specifier = ">=1.19.1" },
{ name = "pytest", specifier = ">=9.0.2" },
] ]
[[package]] [[package]]
@@ -43,6 +45,27 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
] ]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "exceptiongroup"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
]
[[package]] [[package]]
name = "flake8" name = "flake8"
version = "7.3.0" version = "7.3.0"
@@ -57,6 +80,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" }, { url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" },
] ]
[[package]]
name = "iniconfig"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
]
[[package]] [[package]]
name = "librt" name = "librt"
version = "0.8.1" version = "0.8.1"
@@ -353,6 +385,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/57/a7/b35835e278c18b85206834b3aa3abe68e77a98769c59233d1f6300284781/numpy-2.4.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4b42639cdde6d24e732ff823a3fa5b701d8acad89c4142bc1d0bd6dc85200ba5", size = 12504685, upload-time = "2026-03-09T07:58:50.525Z" }, { url = "https://files.pythonhosted.org/packages/57/a7/b35835e278c18b85206834b3aa3abe68e77a98769c59233d1f6300284781/numpy-2.4.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4b42639cdde6d24e732ff823a3fa5b701d8acad89c4142bc1d0bd6dc85200ba5", size = 12504685, upload-time = "2026-03-09T07:58:50.525Z" },
] ]
[[package]]
name = "packaging"
version = "26.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
]
[[package]] [[package]]
name = "pathspec" name = "pathspec"
version = "1.0.4" version = "1.0.4"
@@ -362,6 +403,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" },
] ]
[[package]]
name = "pluggy"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]] [[package]]
name = "pycodestyle" name = "pycodestyle"
version = "2.14.0" version = "2.14.0"
@@ -513,6 +563,33 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" }, { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" },
] ]
[[package]]
name = "pygments"
version = "2.19.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
]
[[package]]
name = "pytest"
version = "9.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "pygments" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
]
[[package]] [[package]]
name = "tomli" name = "tomli"
version = "2.4.0" version = "2.4.0"