33 Commits

Author SHA1 Message Date
Maoake Teriierooiterai d2f38468a4 need to be merge to the main and add some line for the makefile 2026-04-01 17:17:20 +02:00
Maoake Teriierooiterai b659871902 finish the mypy 2026-04-01 16:09:42 +02:00
Maoake Teriierooiterai c9e0cf0610 fix some mypy need to fix for the others 2026-04-01 15:25:38 +02:00
Maoake Teriierooiterai aadccfba53 finish the mypy strict 2026-04-01 15:19:46 +02:00
Maoake Teriierooiterai c7c7213fb9 fix some mypy strict on file a_maze_ing.py 2026-04-01 15:03:22 +02:00
Maoake Teriierooiterai 03b5f9e6fd fix mypy strict on MazeSolver and Maze Generator 2026-04-01 14:12:39 +02:00
maoake ed16566677 finish to fix parsing mypy 2026-03-31 22:43:03 +02:00
maoake 40e25757c7 starting mypy with maze 2026-03-31 22:31:48 +02:00
maoake b1eda06fa5 fixing flake8 2026-03-31 22:01:45 +02:00
maoake 769198c06b adding the blink on the 42 2026-03-31 21:03:10 +02:00
maoake 2c7b565137 give a checkpoint to the project blink the 42 2026-03-31 20:29:01 +02:00
maoake d23959ce74 fix conflict 2026-03-31 20:17:08 +02:00
maoake 4cb678b5be something is up 2026-03-31 19:59:09 +02:00
da7e b520210d58 fix(MazeMLX): margin calculation, big maze are now display fully 2026-03-30 16:36:52 +02:00
da7e bdb1056d69 fix(AmazMLX): draw_ft margin 2026-03-30 15:57:16 +02:00
da7e b2aa93e04d add color to put block 2026-03-30 15:47:39 +02:00
da7e 56ebb2823a code refactor(AmazMLX) 2026-03-30 15:45:15 +02:00
da7e 150eaedc94 Merge branch 'main' of github.com:maoakeEnterprise/amazing 2026-03-30 15:41:35 +02:00
da7e 6f4699c29f wip(entry exit) 2026-03-30 15:37:45 +02:00
Maoake Teriierooiterai 5913f5267d trying to get the blink on the 42 2026-03-30 15:36:52 +02:00
Maoake Teriierooiterai d4251dc8b7 fixing the conflict 2026-03-30 14:47:16 +02:00
Maoake Teriierooiterai 282fbd6867 poop the conflict 2026-03-30 14:39:05 +02:00
da7e 0f77e0c6e4 fix buffer overflow in put pixel + margin calculation 2026-03-30 14:37:33 +02:00
Maoake Teriierooiterai cfac4bed25 need to add the color 2026-03-30 13:53:14 +02:00
Maoake Teriierooiterai cd3c75fb1e set up the path print with the button 2026-03-30 12:01:23 +02:00
Maoake Teriierooiterai 628bb8a94b put the functions color and need to refactor the code 2026-03-30 08:26:53 +02:00
mteriier dc19b526fa testing colors on the project cause we need to test it out 2026-03-29 23:35:42 +02:00
Maoake Teriierooiterai 68d710e313 color 42 2026-03-29 18:47:29 +02:00
da7e 92c6237f06 fix(astar): the actual astar wasn't the real astar algoritm 2026-03-29 15:38:40 +02:00
Maoake Teriierooiterai b682274102 opti path 2026-03-29 14:31:04 +02:00
mteriier d534993f4c starting my branch need to rush this 2026-03-28 23:01:42 +01:00
da7e fa38f7a311 Merge branch 'mlx' 2026-03-27 21:53:06 +01:00
da7e 16d97e9912 fix(astar): function f() miscalculate the best path 2026-03-27 21:51:49 +01:00
17 changed files with 499 additions and 353 deletions
+7 -3
View File
@@ -16,11 +16,15 @@ clean:
lint: lint:
uv run flake8 . --exclude=.venv uv run flake8 . --exclude=.venv
uv run mypy . --warn-return-any --warn-unused-ignores --ignore-missing-imports --disallow-untyped-defs --check-untyped-defs uv run env PYTHONPATH=src python3 -m mypy --warn-return-any --warn-unused-ignores --ignore-missing-imports --disallow-untyped-defs --check-untyped-defs src
uv run env PYTHONPATH=src python3 -m mypy --warn-return-any --warn-unused-ignores --ignore-missing-imports --disallow-untyped-defs --check-untyped-defs tests
uv run env PYTHONPATH=src python3 -m mypy --warn-return-any --warn-unused-ignores --ignore-missing-imports --disallow-untyped-defs --check-untyped-defs a_maze_ing.py
lint-strict: lint-strict:
uv run flake8 . uv run flake8 . --exclude=.venv
uv run mypy . --strict uv run env PYTHONPATH=src python3 -m mypy --strict src
uv run env PYTHONPATH=src python3 -m mypy --strict tests
uv run env PYTHONPATH=src python3 -m mypy --strict a_maze_ing.py
run_test_parsing: run_test_parsing:
PYTHONPATH=src uv run pytest tests/test_parsing.py PYTHONPATH=src uv run pytest tests/test_parsing.py
+229 -91
View File
@@ -1,9 +1,8 @@
from typing import Any, Generator from typing import Any
from numpy.typing import NDArray
from src.AMazeIng import AMazeIng from src.AMazeIng import AMazeIng
from src.parsing import Parsing from src.parsing import Parsing
from mlx import Mlx from mlx import Mlx
import numpy as np
import math
import time import time
@@ -12,6 +11,8 @@ class MazeMLX:
self.mlx = Mlx() self.mlx = Mlx()
self.height = height self.height = height
self.width = width self.width = width
self.print_path = False
self.color = [0x00, 0x00, 0xFF, 0xFF]
self.mlx_ptr = self.mlx.mlx_init() self.mlx_ptr = self.mlx.mlx_init()
self.win_ptr = self.mlx.mlx_new_window( self.win_ptr = self.mlx.mlx_new_window(
self.mlx_ptr, width, height + 200, "A-Maze-Ing" self.mlx_ptr, width, height + 200, "A-Maze-Ing"
@@ -20,12 +21,16 @@ class MazeMLX:
self.buf, self.bpp, self.size_line, self.format = ( self.buf, self.bpp, self.size_line, self.format = (
self.mlx.mlx_get_data_addr(self.img_ptr) self.mlx.mlx_get_data_addr(self.img_ptr)
) )
self.path_printer = None
self.generator = None
def close(self) -> None: def close(self) -> None:
self.mlx.mlx_destroy_image(self.mlx_ptr, self.img_ptr) self.mlx.mlx_destroy_image(self.mlx_ptr, self.img_ptr)
def close_loop(self, _: Any) -> None:
self.mlx.mlx_loop_exit(self.mlx_ptr)
def clear_image(self) -> None:
self.buf[:] = b"\x00" * len(self.buf)
def redraw_image(self) -> None: def redraw_image(self) -> None:
self.mlx.mlx_clear_window(self.mlx_ptr, self.win_ptr) self.mlx.mlx_clear_window(self.mlx_ptr, self.win_ptr)
self.mlx.mlx_put_image_to_window( self.mlx.mlx_put_image_to_window(
@@ -40,47 +45,101 @@ class MazeMLX:
"1: regen; 2: path; 3: color; 4: quit;", "1: regen; 2: path; 3: color; 4: quit;",
) )
def put_pixel(self, x, y) -> None: def put_pixel(self, x: int, y: int, color: list[Any] | None = None
) -> None:
if x < 0 or y < 0 or x >= self.width or y >= self.height:
return
offset = y * self.size_line + x * (self.bpp // 8) offset = y * self.size_line + x * (self.bpp // 8)
self.buf[offset + 0] = 0xFF if color:
self.buf[offset + 1] = 0xFF self.buf[offset + 0] = color[0]
self.buf[offset + 2] = 0xFF self.buf[offset + 1] = color[1]
if self.bpp >= 32: self.buf[offset + 2] = color[2]
self.buf[offset + 3] = 0xFF if self.bpp >= 32:
self.buf[offset + 3] = color[3]
else:
self.buf[offset + 0] = self.color[0]
self.buf[offset + 1] = self.color[1]
self.buf[offset + 2] = self.color[2]
if self.bpp >= 32:
self.buf[offset + 3] = self.color[3]
def clear_image(self) -> None: def put_line(
self.buf[:] = b"\x00" * len(self.buf) self,
start: tuple[int, int],
def put_line(self, start: tuple[int, int], end: tuple[int, int]) -> None: end: tuple[int, int],
color: list[Any] | None = None,
) -> None:
sx, sy = start sx, sy = start
ex, ey = end ex, ey = end
if sy == ey: if sy == ey:
for x in range(min(sx, ex), max(sx, ex) + 1): for x in range(min(sx, ex), max(sx, ex) + 1):
self.put_pixel(x, sy) self.put_pixel(x, sy, color)
if sx == ex: if sx == ex:
for y in range(min(sy, ey), max(sy, ey) + 1): for y in range(min(sy, ey), max(sy, ey) + 1):
self.put_pixel(sx, y) self.put_pixel(sx, y, color)
def update_maze(self, maze: np.ndarray) -> None: def put_block(
self.clear_image() self,
margin = math.trunc( ul: tuple[int, int],
math.sqrt(self.width if self.width > self.height else self.height) dr: tuple[int, int],
// 2 color: list[Any] | None = None,
) ) -> None:
line_len = math.trunc( for y in range(min(ul[1], dr[1]), max(dr[1], ul[1])):
( self.put_line(
(self.height - margin) // len(maze) (min(ul[0], dr[0]), y), (max(ul[0], dr[0]), y), color
if self.height > self.width
else (self.width - margin) // len(maze[0])
) )
)
@staticmethod
def random_color_ft() -> Any:
colors = [
[0xFF, 0xBF, 0x00, 0xFF], # blue
[0x00, 0xFF, 0x40, 0xFF], # green
[0xFF, 0x00, 0xFF, 0xFF], # pink
[0x00, 0xFF, 0xFF, 0xFF], # yellow
]
while True:
for color in colors:
yield color
@staticmethod
def random_color() -> Any:
colors = [
[0xFF, 0x00, 0xFF, 0xFF], # pink
[0x00, 0xFF, 0xFF, 0xFF], # yellow
[0x00, 0xFF, 0x40, 0xFF], # green
[0xFF, 0xBF, 0x00, 0xFF], # blue
[0xFF, 0x00, 0x80, 0xFF], # purple
[0x00, 0x00, 0xFF, 0xFF], # red
]
while True:
for color in colors:
yield color
def get_margin_line_len(self, maze: NDArray[Any]) -> tuple[int, int, int]:
rows = len(maze)
cols = len(maze[0])
line_len = min(self.width // cols, self.height // rows) - 1
maze_width = cols * line_len
maze_height = rows * line_len
margin_x = ((self.width - maze_width) // 2) + 1
margin_y = ((self.height - maze_height) // 2) + 1
return (line_len, margin_x, margin_y)
def update_maze(self, maze: NDArray[Any]) -> None:
self.clear_image()
line_len, margin_x, margin_y = self.get_margin_line_len(maze)
for y in range(len(maze)): for y in range(len(maze)):
for x in range(len(maze[0])): for x in range(len(maze[0])):
x0 = x * line_len + margin x0 = x * line_len + margin_x
y0 = y * line_len + margin y0 = y * line_len + margin_y
x1 = x * line_len + line_len + margin x1 = x * line_len + line_len + margin_x
y1 = y * line_len + line_len + margin y1 = y * line_len + line_len + margin_y
if maze[y][x].get_north(): if maze[y][x].get_north():
self.put_line((x0, y0), (x1, y0)) self.put_line((x0, y0), (x1, y0))
@@ -90,13 +149,8 @@ class MazeMLX:
self.put_line((x0, y1), (x1, y1)) self.put_line((x0, y1), (x1, y1))
if maze[y][x].get_west(): if maze[y][x].get_west():
self.put_line((x0, y0), (x0, y1)) self.put_line((x0, y0), (x0, y1))
self.redraw_image()
def put_block(self, ul: tuple[int, int], dr: tuple[int, int]) -> None: def put_path(self, amazing: AMazeIng) -> Any:
for y in range(min(ul[1], dr[1]), max(dr[1], ul[1])):
self.put_line((min(ul[0], dr[0]), y), (max(ul[0], dr[0]), y))
def put_path(self, amazing: AMazeIng):
path = amazing.solve_path() path = amazing.solve_path()
print(path) print(path)
actual = amazing.entry actual = amazing.entry
@@ -104,33 +158,23 @@ class MazeMLX:
maze = amazing.maze.get_maze() maze = amazing.maze.get_maze()
if maze is None: if maze is None:
return return
margin = math.trunc(
math.sqrt(self.width if self.width > self.height else self.height) line_len, margin_x, margin_y = self.get_margin_line_len(maze)
// 2
)
cell_size = math.trunc(
(
(self.height - margin) // len(maze)
if self.height > self.width
else (self.width - margin) // len(maze[0])
)
)
self.update_maze(maze)
for i in range(len(path)): for i in range(len(path)):
ul = ( ul = (
(actual[0]) * cell_size + margin + 12, (actual[0]) * line_len + margin_x + 12,
(actual[1]) * cell_size + 12 + margin, (actual[1]) * line_len + 12 + margin_y,
) )
dr = ( dr = (
(actual[0]) * cell_size + cell_size + margin - 12, (actual[0]) * line_len + line_len + margin_x - 12,
(actual[1]) * cell_size + cell_size - 12 + margin, (actual[1]) * line_len + line_len - 12 + margin_y,
) )
self.put_block(ul, dr) self.put_block(ul, dr)
self.redraw_image() x0 = actual[0] * line_len + margin_x + 12
x0 = actual[0] * cell_size + margin + 12 y0 = actual[1] * line_len + margin_y + 12
y0 = actual[1] * cell_size + margin + 12 x1 = actual[0] * line_len + line_len + margin_x - 12
x1 = actual[0] * cell_size + cell_size + margin - 12 y1 = actual[1] * line_len + line_len + margin_y - 12
y1 = actual[1] * cell_size + cell_size + margin - 12
yield yield
match path[i]: match path[i]:
case "N": case "N":
@@ -146,61 +190,155 @@ class MazeMLX:
self.put_block((x0, y0), (x0 - 24, y1)) self.put_block((x0, y0), (x0 - 24, y1))
actual = (actual[0] - 1, actual[1]) actual = (actual[0] - 1, actual[1])
ul = ( ul = (
(actual[0]) * cell_size + margin + 12, (actual[0]) * line_len + margin_x + 12,
(actual[1]) * cell_size + 12 + margin, (actual[1]) * line_len + 12 + margin_y,
) )
dr = ( dr = (
(actual[0]) * cell_size + cell_size + margin - 12, (actual[0]) * line_len + line_len + margin_x - 12,
(actual[1]) * cell_size + cell_size - 12 + margin, (actual[1]) * line_len + line_len - 12 + margin_y,
) )
self.put_block(ul, dr) self.put_block(ul, dr)
self.redraw_image()
return return
def close_loop(self, _: Any): def put_start_end(self, amazing: AMazeIng) -> None:
self.mlx.mlx_loop_exit(self.mlx_ptr) entry = amazing.entry
exit = amazing.exit
maze = amazing.maze.get_maze()
if maze is None:
return
line_len, margin_x, margin_y = self.get_margin_line_len(maze)
ul = (
(entry[0] - 1) * line_len + margin_x + 3,
(entry[1] - 1) * line_len + 3 + margin_y,
)
dr = (
(entry[0] - 1) * line_len + line_len + margin_x - 3,
(entry[1] - 1) * line_len + line_len - 3 + margin_y,
)
self.put_block(ul, dr, [0xFF, 0xBF, 0x00, 0x9F])
ul = (
(exit[0] - 1) * line_len + margin_x + 3,
(exit[1] - 1) * line_len + 3 + margin_y,
)
dr = (
(exit[0] - 1) * line_len + line_len + margin_x - 3,
(exit[1] - 1) * line_len + line_len - 3 + margin_y,
)
self.put_block(ul, dr, [0x00, 0xFF, 0x40, 0x9F])
def draw_ft(self, maze: NDArray[Any], color: list[Any] | None = None
) -> None:
line_len, margin_x, margin_y = self.get_margin_line_len(maze)
for y in range(len(maze)):
for x in range(len(maze[0])):
if maze[y][x].value == 15:
x0 = x * line_len + margin_x
y0 = y * line_len + margin_y
x1 = x * line_len + line_len + margin_x
y1 = y * line_len + line_len + margin_y
self.put_block((x0, y0), (x1, y1), color)
def draw_image(self, amazing: AMazeIng) -> None:
maze = amazing.maze.get_maze()
if self.render_maze(amazing):
if self.print_path:
if self.render_path():
color = next(self.color_gen_ft)
if maze is not None:
self.draw_ft(maze, color)
next(self.timer_gen)
else:
self.time_gen()
if maze is not None:
self.update_maze(maze)
self.draw_ft(maze)
self.put_start_end(amazing)
self.redraw_image()
def shift_color(self) -> None:
self.color_gen = self.random_color()
def shift_color_ft(self) -> None:
self.color_gen_ft = self.random_color_ft()
def time_gen(self) -> None:
self.timer_gen = self.time_generator()
def restart_maze(self, amazing: AMazeIng) -> None:
self.generator = amazing.generate()
def time_generator(self) -> Any:
yield
while True:
time.sleep(0.3)
yield
def restart_path(self, amazing: AMazeIng) -> None:
self.path_printer = self.put_path(amazing)
def render_path(self) -> bool:
try:
next(self.path_printer)
time.sleep(0.03)
return False
except StopIteration:
pass
return True
def render_maze(self, amazing: AMazeIng) -> bool:
try:
maze = amazing.maze.get_maze()
next(self.generator)
if maze is not None:
self.update_maze(maze)
return False
except StopIteration:
pass
return True
def handle_key_press(self, keycode: int, amazing: AMazeIng) -> None: def handle_key_press(self, keycode: int, amazing: AMazeIng) -> None:
if keycode == 49: if keycode == 49:
self.restart_maze(amazing) self.restart_maze(amazing)
self.print_path = False
if keycode == 50: if keycode == 50:
self.restart_path(amazing) self.restart_path(amazing)
self.print_path = True if self.print_path is False else False
if keycode == 51: if keycode == 51:
pass self.print_path = False
self.color = next(self.color_gen)
if keycode == 52: if keycode == 52:
self.close_loop(None) self.close_loop(None)
def handle_key_press_mteriier(self, keycode: int,
amazing: AMazeIng) -> None:
if keycode == 38:
self.restart_maze(amazing)
self.print_path = False
if keycode == 233:
self.restart_path(amazing)
self.print_path = True if self.print_path is False else False
if keycode == 34:
self.print_path = False
self.color = next(self.color_gen)
if keycode == 39:
self.close_loop(None)
def start(self, amazing: AMazeIng) -> None: def start(self, amazing: AMazeIng) -> None:
self.restart_maze(amazing) self.restart_maze(amazing)
self.mlx.mlx_loop_hook(self.mlx_ptr, self.render_maze, amazing) self.shift_color()
self.shift_color_ft()
self.time_gen()
self.mlx.mlx_loop_hook(self.mlx_ptr, self.draw_image, amazing)
self.mlx.mlx_hook(self.win_ptr, 33, 0, self.close_loop, None) self.mlx.mlx_hook(self.win_ptr, 33, 0, self.close_loop, None)
self.mlx.mlx_hook( self.mlx.mlx_hook(
self.win_ptr, 2, 1 << 0, self.handle_key_press, amazing self.win_ptr, 2, 1 << 0, self.handle_key_press, amazing
) )
self.mlx.mlx_loop(self.mlx_ptr) self.mlx.mlx_loop(self.mlx_ptr)
def restart_maze(self, amazing: AMazeIng) -> None:
self.generator = amazing.generate()
def restart_path(self, amazing: AMazeIng) -> None:
self.path_printer = self.put_path(amazing)
def render_path(self):
try:
next(self.path_printer)
time.sleep(0.03)
except StopIteration:
pass
def render_maze(self, amazing: AMazeIng):
try:
next(self.generator)
self.update_maze(amazing.maze.get_maze())
# time.sleep(0.01)
except StopIteration:
if self.path_printer is not None:
self.render_path()
def main() -> None: def main() -> None:
mlx = None mlx = None
+6 -6
View File
@@ -1,8 +1,8 @@
WIDTH=11 WIDTH=10
HEIGHT=11 HEIGHT=10
ENTRY=1,1 ENTRY=1,1
EXIT=11,11 EXIT=5,5
OUTPUT_FILE=maze.txt OUTPUT_FILE=maze.txt
PERFECT=True PERFECT=False
GENERATOR=Kruskal GENERATOR=DFS
SOLVER=AStar SOLVER=DFS
-25
View File
@@ -1,25 +0,0 @@
# 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})')
+1
View File
@@ -20,6 +20,7 @@ dev = [
[tool.mypy] [tool.mypy]
python_version = "3.10" python_version = "3.10"
explicit_package_bases = true
[tool.pytest.ini_options] [tool.pytest.ini_options]
pythonpath = ["src"] pythonpath = ["src"]
+1 -1
View File
@@ -2,7 +2,7 @@ from typing import Generator
from typing_extensions import Self from typing_extensions import Self
from pydantic import BaseModel, Field, model_validator, ConfigDict from pydantic import BaseModel, Field, model_validator, ConfigDict
from src.amaz_lib import Maze, MazeGenerator, MazeSolver from .amaz_lib import Maze, MazeGenerator, MazeSolver
class AMazeIng(BaseModel): class AMazeIng(BaseModel):
+8 -5
View File
@@ -1,16 +1,16 @@
from dataclasses import dataclass from dataclasses import dataclass
from numpy.typing import NDArray
import numpy from typing import Optional, Any
@dataclass @dataclass
class Maze: class Maze:
maze: numpy.ndarray maze: Optional[NDArray[Any]] = None
def get_maze(self) -> numpy.ndarray | None: def get_maze(self) -> Optional[NDArray[Any]]:
return self.maze return self.maze
def set_maze(self, new_maze: numpy.ndarray) -> None: def set_maze(self, new_maze: NDArray[Any]) -> None:
self.maze = new_maze self.maze = new_maze
def __str__(self) -> str: def __str__(self) -> str:
@@ -24,6 +24,9 @@ class Maze:
return res return res
def ascii_print(self) -> None: def ascii_print(self) -> None:
if self.maze is None:
print("None")
return
for cell in self.maze[0]: for cell in self.maze[0]:
print("_", end="") print("_", end="")
if cell.get_north(): if cell.get_north():
+37 -29
View File
@@ -1,12 +1,15 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Generator, Set from typing import Generator, Any
import numpy as np import numpy as np
from numpy.typing import NDArray
from .Cell import Cell from .Cell import Cell
import math import math
import random
class MazeGenerator(ABC): class MazeGenerator(ABC):
def __init__(self, start: tuple, end: tuple, perfect: bool) -> None: def __init__(self, start: tuple[int, int], end: tuple[int, int],
perfect: bool) -> None:
self.start = (start[0] - 1, start[1] - 1) self.start = (start[0] - 1, start[1] - 1)
self.end = (end[0] - 1, end[1] - 1) self.end = (end[0] - 1, end[1] - 1)
self.perfect = perfect self.perfect = perfect
@@ -14,10 +17,10 @@ class MazeGenerator(ABC):
@abstractmethod @abstractmethod
def generator( def generator(
self, height: int, width: int, seed: int | None = None self, height: int, width: int, seed: int | None = None
) -> Generator[np.ndarray, None, np.ndarray]: ... ) -> Generator[NDArray[Any], None, NDArray[Any]]: ...
@staticmethod @staticmethod
def get_cell_ft(width: int, height: int) -> set: def get_cell_ft(width: int, height: int) -> set[tuple[int, int]]:
forty_two = set() forty_two = set()
y, x = (int(height / 2), int(width / 2)) y, x = (int(height / 2), int(width / 2))
forty_two.add((y, x - 1)) forty_two.add((y, x - 1))
@@ -42,9 +45,10 @@ class MazeGenerator(ABC):
@staticmethod @staticmethod
def unperfect_maze(width: int, height: int, def unperfect_maze(width: int, height: int,
maze: np.ndarray, forty_two: set | None, maze: NDArray[Any],
forty_two: set[tuple[int, int]] | None,
prob: float = 0.1 prob: float = 0.1
) -> Generator[np.ndarray, None, np.ndarray]: ) -> Generator[NDArray[Any], None, NDArray[Any]]:
directions = { directions = {
"N": (0, -1), "N": (0, -1),
"S": (0, 1), "S": (0, 1),
@@ -94,19 +98,19 @@ class MazeGenerator(ABC):
class Kruskal(MazeGenerator): class Kruskal(MazeGenerator):
class Set: class KruskalSet:
def __init__(self, cells: list[int]) -> None: def __init__(self, cells: list[int]) -> None:
self.cells: list[int] = cells self.cells: list[int] = cells
class Sets: class Sets:
def __init__(self, sets: list[Set]) -> None: def __init__(self, sets: list['Kruskal.KruskalSet']) -> None:
self.sets = sets self.sets = sets
@staticmethod @staticmethod
def walls_to_maze( def walls_to_maze(
walls: np.ndarray, height: int, width: int walls: list[tuple[int, int]], height: int, width: int
) -> np.ndarray: ) -> NDArray[Any]:
maze: np.ndarray = np.array( maze: NDArray[Any] = np.array(
[[Cell(value=0) for _ in range(width)] for _ in range(height)] [[Cell(value=0) for _ in range(width)] for _ in range(height)]
) )
for wall in walls: for wall in walls:
@@ -171,7 +175,7 @@ class Kruskal(MazeGenerator):
def generator( def generator(
self, height: int, width: int, seed: int | None = None self, height: int, width: int, seed: int | None = None
) -> Generator[np.ndarray, None, np.ndarray]: ) -> Generator[NDArray[Any], None, NDArray[Any]]:
cells_ft = None cells_ft = None
if height > 10 and width > 10: if height > 10 and width > 10:
cells_ft = self.get_cell_ft(width, height) cells_ft = self.get_cell_ft(width, height)
@@ -180,7 +184,7 @@ class Kruskal(MazeGenerator):
if seed is not None: if seed is not None:
np.random.seed(seed) np.random.seed(seed)
sets = self.Sets([self.Set([i]) for i in range(height * width)]) sets = self.Sets([self.KruskalSet([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):
@@ -217,28 +221,29 @@ class Kruskal(MazeGenerator):
class DepthFirstSearch(MazeGenerator): class DepthFirstSearch(MazeGenerator):
def __init__(self, start: bool, end: bool, perfect: bool) -> None: def __init__(self, start: tuple[int, int], end: tuple[int, int],
perfect: bool) -> None:
self.start = (start[0] - 1, start[1] - 1) self.start = (start[0] - 1, start[1] - 1)
self.end = (end[0] - 1, end[1] - 1) self.end = (end[0] - 1, end[1] - 1)
self.perfect = perfect self.perfect = perfect
self.forty_two: set | None = None self.forty_two: set[tuple[int, int]] | None = None
def generator( def generator(
self, height: int, width: int, seed: int = None self, height: int, width: int, seed: int | None = None
) -> Generator[np.ndarray, None, np.ndarray]: ) -> Generator[NDArray[Any], None, NDArray[Any]]:
if seed is not None: if seed is not None:
np.random.seed(seed) np.random.seed(seed)
maze = self.init_maze(width, height) maze = self.init_maze(width, height)
if width > 9 and height > 9: if width > 9 and height > 9:
self.forty_two = self.get_cell_ft(width, height) self.forty_two = self.get_cell_ft(width, height)
visited = np.zeros((height, width), dtype=bool) visited: NDArray[np.object_] = np.zeros((height, width), dtype=bool)
if ( if (
self.forty_two self.forty_two
and self.start not in self.forty_two and self.start not in self.forty_two
and self.end not in self.forty_two and self.end not in self.forty_two
): ):
visited = self.lock_cell_ft(visited, self.forty_two) visited = self.lock_cell_ft(visited, self.forty_two)
path = list() path: list[tuple[int, int]] = list()
w_h = (width, height) w_h = (width, height)
coord = (0, 0) coord = (0, 0)
x, y = coord x, y = coord
@@ -277,20 +282,22 @@ class DepthFirstSearch(MazeGenerator):
return maze return maze
@staticmethod @staticmethod
def init_maze(width: int, height: int) -> np.ndarray: def init_maze(width: int, height: int) -> NDArray[Any]:
maze = np.array( maze = np.array(
[[Cell(value=15) for _ in range(width)] for _ in range(height)] [[Cell(value=15) for _ in range(width)] for _ in range(height)]
) )
return maze return maze
@staticmethod @staticmethod
def add_cell_visited(coord: tuple, path: set) -> list: def add_cell_visited(coord: tuple[int, int], path: list[tuple[int, int]]
) -> list[tuple[int, int]]:
path.append(coord) path.append(coord)
return path return path
@staticmethod @staticmethod
def random_cells(visited: np.array, coord: tuple, w_h: tuple) -> list: def random_cells(visited: NDArray[Any], coord: tuple[int, int],
rand_cell = [] w_h: tuple[int, int]) -> list[str]:
rand_cell: list[str] = []
x, y = coord x, y = coord
width, height = w_h width, height = w_h
@@ -308,8 +315,8 @@ class DepthFirstSearch(MazeGenerator):
return rand_cell return rand_cell
@staticmethod @staticmethod
def next_step(rand_cell: list) -> str: def next_step(rand_cell: list[str]) -> str:
return np.random.choice(rand_cell) return random.choice(rand_cell)
@staticmethod @staticmethod
def broken_wall(cell: Cell, wall: str) -> Cell: def broken_wall(cell: Cell, wall: str) -> Cell:
@@ -324,7 +331,7 @@ class DepthFirstSearch(MazeGenerator):
return cell return cell
@staticmethod @staticmethod
def next_cell(x: int, y: int, next: str) -> tuple: def next_cell(x: int, y: int, next: str) -> tuple[int, int]:
next_step = {"N": (0, -1), "S": (0, 1), "W": (-1, 0), "E": (1, 0)} next_step = {"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)
@@ -334,7 +341,8 @@ class DepthFirstSearch(MazeGenerator):
return {"N": "S", "S": "N", "W": "E", "E": "W"}[direction] return {"N": "S", "S": "N", "W": "E", "E": "W"}[direction]
@staticmethod @staticmethod
def back_on_step(path: list, w_h: tuple, visited: np.ndarray) -> list: def back_on_step(path: list[tuple[int, int]], w_h: tuple[int, int],
visited: NDArray[Any]) -> list[tuple[int, int]]:
while path: while path:
last = path[-1] last = path[-1]
if DepthFirstSearch.random_cells(visited, last, w_h): if DepthFirstSearch.random_cells(visited, last, w_h):
@@ -344,8 +352,8 @@ class DepthFirstSearch(MazeGenerator):
@staticmethod @staticmethod
def lock_cell_ft( def lock_cell_ft(
visited: np.ndarray, forty_two: set[tuple[int]] visited: NDArray[Any], forty_two: set[tuple[int, int]]
) -> np.ndarray: ) -> NDArray[Any]:
tab = [cell for cell in forty_two] tab = [cell for cell in forty_two]
for cell in tab: for cell in tab:
visited[cell] = True visited[cell] = True
+174 -156
View File
@@ -1,6 +1,9 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from .Maze import Maze from .Maze import Maze
from typing import Any
import numpy as np import numpy as np
from numpy.typing import NDArray
import random
class MazeSolver(ABC): class MazeSolver(ABC):
@@ -9,178 +12,187 @@ class MazeSolver(ABC):
self.end = (end[1] - 1, end[0] - 1) self.end = (end[1] - 1, end[0] - 1)
@abstractmethod @abstractmethod
def solve(self, maze: Maze, height: int = None, def solve(
width: int = None) -> str: ... self, maze: Maze, height: int | None = None, width: int | None = None
) -> str: ...
class AStar(MazeSolver): class AStar(MazeSolver):
class Node:
def __init__(
self,
coordinate: tuple[int, int],
g: int,
h: int,
f: int,
parent: Any,
) -> None:
self.coordinate = coordinate
self.g = g
self.h = h
self.f = f
self.parent = parent
def __eq__(self, value: object, /) -> bool:
return value == self.coordinate
def __init__(self, start: tuple[int, int], end: tuple[int, int]) -> None: def __init__(self, start: tuple[int, int], end: tuple[int, int]) -> None:
super().__init__(start, end) super().__init__(start, end)
def f(self, n): def h(self, n: tuple[int, int]) -> int:
def g(n: tuple[int, int]) -> int: return (
res = 0 max(n[0], self.end[0])
if n[0] < self.start[0]: - min(n[0], self.end[0])
res += self.start[0] - n[0] + max(n[1], self.end[1])
else: - min(n[1], self.end[1])
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],
last: str | None,
) -> dict[str, int]:
path = {
"N": (
self.f((actual[0], actual[1] - 1))
if not maze[actual[1]][actual[0]].get_north() and actual[1] > 0
else None
),
"E": (
self.f((actual[0] + 1, actual[1]))
if not maze[actual[1]][actual[0]].get_est()
and actual[0] < len(maze[0]) - 1
else None
),
"S": (
self.f((actual[0], actual[1] + 1))
if not maze[actual[1]][actual[0]].get_south()
and actual[1] < len(maze) - 1
else None
),
"W": (
self.f((actual[0] - 1, actual[1]))
if not maze[actual[1]][actual[0]].get_west() and actual[0] > 0
else None
),
}
return {
k: v
for k, v in sorted(path.items(), key=lambda item: item[0])
if v is not None and k != last
}
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:
path = [(self.start, self.best_path(maze, self.start, None))]
visited = [self.start]
while len(path) > 0 and path[-1][0] != self.end:
if len(path[-1][1]) == 0:
path.pop(-1)
if len(path) == 0:
break
k = next(iter(path[-1][1]))
path[-1][1].pop(k)
continue
while len(path[-1][1]) > 0:
next_pos = self.get_next_pos(
list(path[-1][1].keys())[0], path[-1][0]
)
if next_pos in visited:
k = next(iter(path[-1][1]))
path[-1][1].pop(k)
else:
break
if len(path[-1][1]) == 0:
path.pop(-1)
continue
pre = self.get_opposit(list(path[-1][1].keys())[0])
path.append(
(
next_pos,
self.best_path(maze, next_pos, pre),
)
)
visited += [next_pos]
if len(path) == 0:
return None
path[-1] = (self.end, {})
return "".join(
str(list(c[1].keys())[0]) for c in path if len(c[1]) > 0
) )
def solve(self, maze: Maze, height: int = None, def get_paths(
width: int = None) -> str: self,
res = self.get_path(maze.get_maze()) maze: NDArray[Any],
if res is None: actual: tuple[int, int],
raise Exception("Path not found") close: list['Node'],
) -> list[tuple[int, int]]:
path = [
(
(actual[0], actual[1] - 1)
if not maze[actual[1]][actual[0]].get_north()
and actual[1] > 0
and (actual[0], actual[1] - 1)
not in [n.coordinate for n in close]
else None
),
(
(actual[0] + 1, actual[1])
if not maze[actual[1]][actual[0]].get_est()
and actual[0] < len(maze[0]) - 1
and (actual[0] + 1, actual[1])
not in [n.coordinate for n in close]
else None
),
(
(actual[0], actual[1] + 1)
if not maze[actual[1]][actual[0]].get_south()
and actual[1] < len(maze) - 1
and (actual[0], actual[1] + 1)
not in [n.coordinate for n in close]
else None
),
(
(actual[0] - 1, actual[1])
if not maze[actual[1]][actual[0]].get_west()
and actual[0] > 0
and (actual[0] - 1, actual[1])
not in [n.coordinate for n in close]
else None
),
]
return [p for p in path if p is not None]
def get_path(self, maze: NDArray[Any]) -> list['Node']:
open: list[AStar.Node] = []
close: list[AStar.Node] = []
open.append(
AStar.Node(
self.start,
0,
self.h(self.start),
self.h(self.start),
None,
)
)
while len(open) > 0:
to_check = sorted(open, key=lambda x: x.f)[0]
open.remove(to_check)
close.append(to_check)
if to_check.coordinate == self.end:
return close
paths = self.get_paths(maze, to_check.coordinate, close)
for path in paths:
open.append(
self.Node(
path,
to_check.g + 1,
self.h(path),
self.h(path) + to_check.g + 1,
to_check,
)
)
raise Exception("Path not found")
def get_rev_dir(self, current: Node) -> str:
if current.parent.coordinate == (
current.coordinate[0],
current.coordinate[1] - 1,
):
return "S"
elif current.parent.coordinate == (
current.coordinate[0] + 1,
current.coordinate[1],
):
return "W"
elif current.parent.coordinate == (
current.coordinate[0],
current.coordinate[1] + 1,
):
return "N"
elif current.parent.coordinate == (
current.coordinate[0] - 1,
current.coordinate[1],
):
return "E"
else:
raise Exception("Translate error: AStar path not found")
def translate(self, close: list['Node']) -> str:
current = close[-1]
res = ""
while True:
res = self.get_rev_dir(current) + res
current = current.parent
if current.coordinate == self.start:
break
return res return res
def solve(
self, maze: Maze, height: int | None = None, width: int | None = None
) -> str:
maze_arr = maze.get_maze()
if maze_arr is None:
raise Exception("Maze is not initialized")
path: list[AStar.Node] = self.get_path(maze_arr)
return self.translate(path)
class DepthFirstSearchSolver(MazeSolver): class DepthFirstSearchSolver(MazeSolver):
def __init__(self, start, end): def __init__(self, start: tuple[int, int], end: tuple[int, int]):
super().__init__(start, end) super().__init__(start, end)
def solve(self, maze: Maze, height: int = None, def solve(
width: int = None) -> str: self, maze: Maze, height: int | None = None, width: int | None = None
) -> str:
path_str = "" path_str = ""
visited = np.zeros((height, width), dtype=bool) if height is None or width is None:
path = list() raise Exception("We need Height and Width in the arg")
move = list() visited: NDArray[Any] = np.zeros((height, width), dtype=bool)
path: list[tuple[int, int]] = list()
move: list[str] = list()
maze_s = maze.get_maze() maze_s = maze.get_maze()
if maze_s is None:
raise Exception("Maze is not initializef")
coord = self.start coord = self.start
h_w = (height, width) h_w: tuple[int, int] = (height, width)
while coord != self.end: while coord != self.end:
visited[coord] = True visited[coord] = True
path.append(coord) path.append(coord)
rand_p = self.random_path(visited, coord, maze_s, h_w) rand_p: list[str] = self.random_path(visited, coord, maze_s, h_w)
if not rand_p: if not rand_p:
path, move = self.back_on_step(path, visited, maze_s, h_w, path, move = self.back_on_step(
move) path, visited, maze_s, h_w, move
)
if not path: if not path:
break break
coord = path[-1] coord = path[-1]
@@ -195,8 +207,9 @@ class DepthFirstSearchSolver(MazeSolver):
return path_str return path_str
@staticmethod @staticmethod
def random_path(visited: np.ndarray, coord: tuple, def random_path(visited: NDArray[Any], coord: tuple[int, int],
maze: np.ndarray, h_w: tuple) -> list: maze: NDArray[Any], h_w: tuple[int, int]
) -> list[str]:
random_p = [] random_p = []
h, w = h_w h, w = h_w
y, x = coord y, x = coord
@@ -215,12 +228,17 @@ class DepthFirstSearchSolver(MazeSolver):
return random_p return random_p
@staticmethod @staticmethod
def next_path(rand_path: list) -> str: def next_path(rand_path: list[str]) -> str:
return np.random.choice(rand_path) return random.choice(rand_path)
@staticmethod @staticmethod
def back_on_step(path: list, visited: np.ndarray, def back_on_step(
maze: np.ndarray, h_w: tuple, move: list) -> list: path: list[tuple[int, int]],
visited: NDArray[Any],
maze: NDArray[Any],
h_w: tuple[int, int],
move: list[str],
) -> tuple[list[Any], list[Any]]:
while path: while path:
last = path[-1] last = path[-1]
if DepthFirstSearchSolver.random_path(visited, last, maze, h_w): if DepthFirstSearchSolver.random_path(visited, last, maze, h_w):
@@ -230,7 +248,7 @@ class DepthFirstSearchSolver(MazeSolver):
return path, move return path, move
@staticmethod @staticmethod
def next_cell(coord: tuple, next: str) -> tuple: def next_cell(coord: tuple[int, int], next: str) -> tuple[int, int]:
y, x = coord y, x = coord
next_step = {"N": (-1, 0), "S": (1, 0), "W": (0, -1), "E": (0, 1)} next_step = {"N": (-1, 0), "S": (1, 0), "W": (0, -1), "E": (0, 1)}
add_y, add_x = next_step[next] add_y, add_x = next_step[next]
View File
+14 -12
View File
@@ -1,5 +1,6 @@
from src.amaz_lib.MazeGenerator import DepthFirstSearch, Kruskal from ..amaz_lib import DepthFirstSearch, Kruskal
from src.amaz_lib.MazeSolver import AStar, DepthFirstSearchSolver from ..amaz_lib import AStar, DepthFirstSearchSolver
from typing import Any
class DataMaze: class DataMaze:
@@ -13,14 +14,14 @@ class DataMaze:
return data return data
@staticmethod @staticmethod
def transform_data(data: str) -> dict: def transform_data(data: str) -> dict[str, str]:
tmp = data.split("\n") tmp = data.split("\n")
tmp2 = [value.split("=", 1) for value in tmp if "=" in value] tmp2 = [value.split("=", 1) for value in tmp if "=" in value]
data_t = {value[0]: value[1] for value in tmp2} data_t = {value[0]: value[1] for value in tmp2}
return data_t return data_t
@staticmethod @staticmethod
def verif_key_data(data: dict) -> None: def verif_key_data(data: dict[str, str]) -> None:
key_test = { key_test = {
"WIDTH", "WIDTH",
"HEIGHT", "HEIGHT",
@@ -41,11 +42,11 @@ class DataMaze:
) )
@staticmethod @staticmethod
def convert_values(data: dict): def convert_values(data: dict[str, str]) -> dict[str, Any]:
key_int = {"WIDTH", "HEIGHT"} key_int = {"WIDTH", "HEIGHT"}
key_tuple = {"ENTRY", "EXIT"} key_tuple = {"ENTRY", "EXIT"}
key_bool = {"PERFECT"} key_bool = {"PERFECT"}
res: dict = {} res: dict[str, Any] = {}
for key in key_int: for key in key_int:
res.update({key: int(data[key])}) res.update({key: int(data[key])})
for key in key_tuple: for key in key_tuple:
@@ -60,13 +61,14 @@ class DataMaze:
return res return res
@staticmethod @staticmethod
def get_solver_generator(data: dict, entry: tuple, exit: tuple, def get_solver_generator(data: dict[str, str], entry: tuple[int, int],
perfect: bool) -> dict: exit: tuple[int, int],
available_generator = { perfect: bool) -> dict[str, Any]:
available_generator: dict[str, Any] = {
"Kruskal": Kruskal, "Kruskal": Kruskal,
"DFS": DepthFirstSearch, "DFS": DepthFirstSearch,
} }
available_solver = { available_solver: dict[str, Any] = {
"AStar": AStar, "AStar": AStar,
"DFS": DepthFirstSearchSolver "DFS": DepthFirstSearchSolver
} }
@@ -77,7 +79,7 @@ class DataMaze:
return res return res
@staticmethod @staticmethod
def convert_tuple(data: str) -> tuple: def convert_tuple(data: str) -> tuple[int, int]:
data_t = data.split(",") data_t = data.split(",")
if len(data_t) != 2: if len(data_t) != 2:
raise ValueError( raise ValueError(
@@ -96,7 +98,7 @@ class DataMaze:
return False return False
@staticmethod @staticmethod
def get_data_maze(name_file: str) -> dict: def get_data_maze(name_file: str) -> dict[str, Any]:
try: try:
data_str = DataMaze.get_file_data(name_file) data_str = DataMaze.get_file_data(name_file)
data_dict = DataMaze.transform_data(data_str) data_dict = DataMaze.transform_data(data_str)
View File
-1
View File
@@ -1,4 +1,3 @@
import pytest
from amaz_lib.Cell import Cell from amaz_lib.Cell import Cell
+3 -1
View File
@@ -15,7 +15,9 @@ def test_maze_setter_getter() -> None:
) )
maze.set_maze(test) maze.set_maze(test)
assert numpy.array_equal(maze.get_maze(), test) is True m = maze.get_maze()
assert m is not None
assert numpy.array_equal(m, test) is True
def test_maze_str() -> None: def test_maze_str() -> None:
+1 -5
View File
@@ -1,5 +1,5 @@
import numpy import numpy
from amaz_lib.MazeGenerator import DepthFirstSearch, MazeGenerator from amaz_lib.MazeGenerator import DepthFirstSearch
class TestMazeGenerator: class TestMazeGenerator:
@@ -12,7 +12,3 @@ class TestMazeGenerator:
maze = output maze = output
assert maze.shape == w_h assert maze.shape == w_h
def test_gen_broken(self) -> None:
test = MazeGenerator.gen_broken_set(50, 50)
assert len(test) > 0
+1 -1
View File
@@ -1,6 +1,6 @@
from amaz_lib.Cell import Cell from amaz_lib.Cell import Cell
import numpy as np import numpy as np
from amaz_lib import AStar, Maze, MazeSolver from amaz_lib import AStar, Maze
def test_solver() -> None: def test_solver() -> None:
+17 -17
View File
@@ -4,71 +4,71 @@ import pytest
class TestParsing: class TestParsing:
def test_get_data_valid(self): def test_get_data_valid(self) -> None:
data = DataMaze.get_file_data("tests/test_txt/config_1.txt") data = DataMaze.get_file_data("tests/test_txt/config_1.txt")
assert isinstance(data, str) is True assert isinstance(data, str) is True
def test_file_error(self): def test_file_error(self) -> None:
with pytest.raises(FileNotFoundError): with pytest.raises(FileNotFoundError):
DataMaze.get_file_data("tete") DataMaze.get_file_data("tete")
# def test_permission_error(self): # def test_permission_error(self) -> None:
# with pytest.raises(PermissionError): # with pytest.raises(PermissionError):
# DataMaze.get_file_data("tests/test_txt/error_1.txt") # DataMaze.get_file_data("tests/test_txt/error_1.txt")
def test_empty_file_error(self): def test_empty_file_error(self) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
DataMaze.get_file_data("tests/test_txt/error_6.txt") DataMaze.get_file_data("tests/test_txt/error_6.txt")
def test_transform_data_valid(self): def test_transform_data_valid(self) -> None:
data = DataMaze.get_file_data("tests/test_txt/config_1.txt") data = DataMaze.get_file_data("tests/test_txt/config_1.txt")
data_2 = DataMaze.transform_data(data) data_2 = DataMaze.transform_data(data)
assert isinstance(data_2, dict) assert isinstance(data_2, dict)
def test_transform__index_error(self): def test_transform__index_error(self) -> None:
with pytest.raises(IndexError): with pytest.raises(IndexError):
DataMaze.transform_data("asdasdasdasdasdasda\nasdasdas=asdasd") DataMaze.transform_data("asdasdasdasdasdasda\nasdasdas=asdasd")
def test_key_data_error(self): def test_key_data_error(self) -> None:
with pytest.raises(KeyError): with pytest.raises(KeyError):
data = DataMaze.get_file_data("tests/test_txt/error_8.txt") data = DataMaze.get_file_data("tests/test_txt/error_8.txt")
data2 = DataMaze.transform_data(data) data2 = DataMaze.transform_data(data)
DataMaze.verif_key_data(data2) DataMaze.verif_key_data(data2)
def test_key_data_error_2(self): def test_key_data_error_2(self) -> None:
with pytest.raises(KeyError): with pytest.raises(KeyError):
data = DataMaze.get_file_data("tests/test_txt/error_9.txt") data = DataMaze.get_file_data("tests/test_txt/error_9.txt")
data2 = DataMaze.transform_data(data) data2 = DataMaze.transform_data(data)
DataMaze.verif_key_data(data2) DataMaze.verif_key_data(data2)
def test_convert_int(self): def test_convert_int(self) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
data = DataMaze.get_file_data("tests/test_txt/error_2.txt") data = DataMaze.get_file_data("tests/test_txt/error_2.txt")
data2 = DataMaze.transform_data(data) data2 = DataMaze.transform_data(data)
DataMaze.convert_values(data2) DataMaze.convert_values(data2)
def test_tuple_error(self): def test_tuple_error(self) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
DataMaze.convert_tuple("0,3,5,5") DataMaze.convert_tuple("0,3,5,5")
def test_tuple_error1(self): def test_tuple_error1(self) -> None:
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
DataMaze.convert_tuple(None) DataMaze.convert_tuple("None")
def test_bool_error(self): def test_bool_error(self) -> None:
with pytest.raises(ValueError): with pytest.raises(ValueError):
DataMaze.convert_bool("Trueeee") DataMaze.convert_bool("Trueeee")
def test_valid_tuple(self): def test_valid_tuple(self) -> None:
assert DataMaze.convert_tuple("7534564654, 78") == (7534564654, 78) assert DataMaze.convert_tuple("7534564654, 78") == (7534564654, 78)
def test_valid_bool(self): def test_valid_bool(self) -> None:
assert DataMaze.convert_bool("False") is False assert DataMaze.convert_bool("False") is False
def test_valid_bool1(self): def test_valid_bool1(self) -> None:
assert DataMaze.convert_bool("True") is True assert DataMaze.convert_bool("True") is True
def test_data_maze(self): def test_data_maze(self) -> None:
data = DataMaze.get_data_maze("tests/test_txt/config_1.txt") data = DataMaze.get_data_maze("tests/test_txt/config_1.txt")
assert data["WIDTH"] == 200 assert data["WIDTH"] == 200
assert data["HEIGHT"] == 100 assert data["HEIGHT"] == 100