24 Commits

Author SHA1 Message Date
da7e 843fe5f80c uv config for build wheel package
add clean and fclean method to Makefile
2026-04-01 14:31:11 +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
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
12 changed files with 260 additions and 114 deletions
+1
View File
@@ -216,3 +216,4 @@ __marimo__/
.streamlit/secrets.toml
test.txt
mazegen-1.0.0-py3-none-any.whl
+10 -1
View File
@@ -1,3 +1,7 @@
build:
uv build --clear --wheel
cp dist/*.whl mazegen-1.0.0-py3-none-any.whl
install:
uv sync
uv pip install mlx-2.2-py3-none-any.whl
@@ -12,7 +16,10 @@ debug:
uv pdb python3 a_maze_ing.py config.txt
clean:
rm -rf __pycache__ .mypy_cache .venv
rm -rf */**__pycache__ __pycache__ .mypy_cache .venv dist build */**/*.egg-info *.egg-info
fclean: clean
rm mazegen-1.0.0-py3-none-any.whl
lint:
uv run flake8 . --exclude=.venv
@@ -34,3 +41,5 @@ run_test:
uv run pytest
mlx:
uv run python3 test.py
.PHONY: build install run debug clean fclean lint lint-strict run_test
View File
+220 -86
View File
@@ -1,9 +1,8 @@
from typing import Any, Generator
from typing import Any
from src.AMazeIng import AMazeIng
from src.parsing import Parsing
from src.parsing.Parsing import DataMaze as Parsing
from mlx import Mlx
import numpy as np
import math
import time
@@ -12,6 +11,8 @@ class MazeMLX:
self.mlx = Mlx()
self.height = height
self.width = width
self.print_path = False
self.color = [0x00, 0x00, 0xFF, 0xFF]
self.mlx_ptr = self.mlx.mlx_init()
self.win_ptr = self.mlx.mlx_new_window(
self.mlx_ptr, width, height + 200, "A-Maze-Ing"
@@ -26,6 +27,12 @@ class MazeMLX:
def close(self) -> None:
self.mlx.mlx_destroy_image(self.mlx_ptr, self.img_ptr)
def close_loop(self, _: Any):
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:
self.mlx.mlx_clear_window(self.mlx_ptr, self.win_ptr)
self.mlx.mlx_put_image_to_window(
@@ -40,47 +47,100 @@ class MazeMLX:
"1: regen; 2: path; 3: color; 4: quit;",
)
def put_pixel(self, x, y) -> None:
def put_pixel(self, x, y, color: list | 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)
self.buf[offset + 0] = 0xFF
self.buf[offset + 1] = 0xFF
self.buf[offset + 2] = 0xFF
if self.bpp >= 32:
self.buf[offset + 3] = 0xFF
if color:
self.buf[offset + 0] = color[0]
self.buf[offset + 1] = color[1]
self.buf[offset + 2] = color[2]
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:
self.buf[:] = b"\x00" * len(self.buf)
def put_line(self, start: tuple[int, int], end: tuple[int, int]) -> None:
def put_line(
self,
start: tuple[int, int],
end: tuple[int, int],
color: list | None = None,
) -> None:
sx, sy = start
ex, ey = end
if sy == ey:
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:
for y in range(min(sy, ey), max(sy, ey) + 1):
self.put_pixel(sx, y)
self.put_pixel(sx, y, color)
def put_block(
self,
ul: tuple[int, int],
dr: tuple[int, int],
color: list | None = None,
) -> None:
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), color
)
@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: np.ndarray) -> 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: np.ndarray) -> None:
self.clear_image()
margin = math.trunc(
math.sqrt(self.width if self.width > self.height else self.height)
// 2
)
line_len = math.trunc(
(
(self.height - margin) // len(maze)
if self.height > self.width
else (self.width - margin) // len(maze[0])
)
)
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])):
x0 = x * line_len + margin
y0 = y * line_len + margin
x1 = x * line_len + line_len + margin
y1 = y * line_len + line_len + margin
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
if maze[y][x].get_north():
self.put_line((x0, y0), (x1, y0))
@@ -90,13 +150,8 @@ class MazeMLX:
self.put_line((x0, y1), (x1, y1))
if maze[y][x].get_west():
self.put_line((x0, y0), (x0, y1))
self.redraw_image()
def put_block(self, ul: tuple[int, int], dr: tuple[int, int]) -> None:
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):
def put_path(self, amazing: AMazeIng) -> Any:
path = amazing.solve_path()
print(path)
actual = amazing.entry
@@ -104,33 +159,23 @@ class MazeMLX:
maze = amazing.maze.get_maze()
if maze is None:
return
margin = math.trunc(
math.sqrt(self.width if self.width > self.height else self.height)
// 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)
line_len, margin_x, margin_y = self.get_margin_line_len(maze)
for i in range(len(path)):
ul = (
(actual[0]) * cell_size + margin + 12,
(actual[1]) * cell_size + 12 + margin,
(actual[0]) * line_len + margin_x + 12,
(actual[1]) * line_len + 12 + margin_y,
)
dr = (
(actual[0]) * cell_size + cell_size + margin - 12,
(actual[1]) * cell_size + cell_size - 12 + margin,
(actual[0]) * line_len + line_len + margin_x - 12,
(actual[1]) * line_len + line_len - 12 + margin_y,
)
self.put_block(ul, dr)
self.redraw_image()
x0 = actual[0] * cell_size + margin + 12
y0 = actual[1] * cell_size + margin + 12
x1 = actual[0] * cell_size + cell_size + margin - 12
y1 = actual[1] * cell_size + cell_size + margin - 12
x0 = actual[0] * line_len + margin_x + 12
y0 = actual[1] * line_len + margin_y + 12
x1 = actual[0] * line_len + line_len + margin_x - 12
y1 = actual[1] * line_len + line_len + margin_y - 12
yield
match path[i]:
case "N":
@@ -146,67 +191,156 @@ class MazeMLX:
self.put_block((x0, y0), (x0 - 24, y1))
actual = (actual[0] - 1, actual[1])
ul = (
(actual[0]) * cell_size + margin + 12,
(actual[1]) * cell_size + 12 + margin,
(actual[0]) * line_len + margin_x + 12,
(actual[1]) * line_len + 12 + margin_y,
)
dr = (
(actual[0]) * cell_size + cell_size + margin - 12,
(actual[1]) * cell_size + cell_size - 12 + margin,
(actual[0]) * line_len + line_len + margin_x - 12,
(actual[1]) * line_len + line_len - 12 + margin_y,
)
self.put_block(ul, dr)
self.redraw_image()
return
def close_loop(self, _: Any):
self.mlx.mlx_loop_exit(self.mlx_ptr)
def put_start_end(self, amazing: AMazeIng):
entry = amazing.entry
exit = amazing.exit
maze = amazing.maze.get_maze()
if maze is None:
return
def handle_key_press(self, keycode: int, amazing: AMazeIng) -> None:
if keycode == 49:
self.restart_maze(amazing)
if keycode == 50:
self.restart_path(amazing)
if keycode == 51:
pass
if keycode == 52:
self.close_loop(None)
line_len, margin_x, margin_y = self.get_margin_line_len(maze)
def start(self, amazing: AMazeIng) -> None:
self.restart_maze(amazing)
self.mlx.mlx_loop_hook(self.mlx_ptr, self.render_maze, amazing)
self.mlx.mlx_hook(self.win_ptr, 33, 0, self.close_loop, None)
self.mlx.mlx_hook(
self.win_ptr, 2, 1 << 0, self.handle_key_press, amazing
ul = (
(entry[0] - 1) * line_len + margin_x + 3,
(entry[1] - 1) * line_len + 3 + margin_y,
)
self.mlx.mlx_loop(self.mlx_ptr)
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: np.ndarray, color: list | 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:
if self.render_maze(amazing):
if self.path_printer and self.print_path:
if self.render_path():
color = next(self.color_gen_ft)
self.draw_ft(amazing.maze.get_maze(), color)
next(self.timer_gen)
else:
self.time_gen()
self.update_maze(amazing.maze.get_maze())
self.draw_ft(amazing.maze.get_maze())
self.put_start_end(amazing)
self.redraw_image()
def shift_color(self):
self.color_gen = self.random_color()
def shift_color_ft(self):
self.color_gen_ft = self.random_color_ft()
def time_gen(self):
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):
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):
def render_maze(self, amazing: AMazeIng) -> bool:
try:
next(self.generator)
self.update_maze(amazing.maze.get_maze())
# time.sleep(0.01)
return False
except StopIteration:
if self.path_printer is not None:
self.render_path()
pass
return True
def handle_key_press(self, keycode: int, amazing: AMazeIng) -> None:
if keycode == 49:
self.restart_maze(amazing)
self.print_path = False
if keycode == 50:
self.restart_path(amazing)
self.print_path = True if self.print_path is False else False
if keycode == 51:
self.print_path = False
self.color = next(self.color_gen)
if keycode == 52:
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:
self.restart_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, 2, 1 << 0, self.handle_key_press_mteriier, amazing
)
self.mlx.mlx_loop(self.mlx_ptr)
def main() -> None:
mlx = None
try:
mlx = MazeMLX(1000, 1000)
config = Parsing.DataMaze.get_data_maze("config.txt")
config = Parsing.get_data_maze("config.txt")
amazing = AMazeIng(**config)
mlx.start(amazing)
with open("test.txt", "w") as output:
+3 -3
View File
@@ -1,7 +1,7 @@
WIDTH=15
HEIGHT=15
WIDTH=13
HEIGHT=13
ENTRY=1,1
EXIT=15,15
EXIT=5,5
OUTPUT_FILE=maze.txt
PERFECT=False
GENERATOR=Kruskal
+8
View File
@@ -23,3 +23,11 @@ python_version = "3.10"
[tool.pytest.ini_options]
pythonpath = ["src"]
[build-system]
requires = ["setuptools>=78.1.0", "wheel>=0.45.1"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
package-dir = {"" = "src/amaz_lib"}
+8 -5
View File
@@ -1,16 +1,16 @@
from dataclasses import dataclass
import numpy
from numpy.typing import NDArray
from typing import Optional, Any
@dataclass
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
def set_maze(self, new_maze: numpy.ndarray) -> None:
def set_maze(self, new_maze: NDArray[Any]) -> None:
self.maze = new_maze
def __str__(self) -> str:
@@ -24,6 +24,9 @@ class Maze:
return res
def ascii_print(self) -> None:
if self.maze is None:
print("None")
return
for cell in self.maze[0]:
print("_", end="")
if cell.get_north():
+8 -10
View File
@@ -11,7 +11,7 @@ class MazeSolver(ABC):
@abstractmethod
def solve(
self, maze: Maze, height: int = None, width: int = None
self, maze: Maze, height: int | None = None, width: int | None = None
) -> str: ...
@@ -38,9 +38,6 @@ class AStar(MazeSolver):
super().__init__(start, end)
self.path = []
def g(self, n: tuple[int, int]) -> int:
return len(self.path) + 1
def h(self, n: tuple[int, int]) -> int:
return (
max(n[0], self.end[0])
@@ -49,9 +46,6 @@ class AStar(MazeSolver):
- min(n[1], self.end[1])
)
def f(self, n: tuple[int, int]) -> int:
return self.g(n) + self.h(n)
def get_paths(
self,
maze: np.ndarray,
@@ -103,7 +97,7 @@ class AStar(MazeSolver):
self.start,
0,
self.h(self.start),
self.f(self.start),
self.h(self.start),
None,
)
)
@@ -161,7 +155,9 @@ class AStar(MazeSolver):
break
return res
def solve(self, maze: Maze, height: int = None, width: int = None) -> str:
def solve(
self, maze: Maze, height: int | None = None, width: int | None = None
) -> str:
path = self.get_path(maze.get_maze())
return self.translate(path)
@@ -170,7 +166,9 @@ class DepthFirstSearchSolver(MazeSolver):
def __init__(self, start, end):
super().__init__(start, end)
def solve(self, maze: Maze, height: int = None, width: int = None) -> str:
def solve(
self, maze: Maze, height: int | None = None, width: int | None = None
) -> str:
path_str = ""
visited = np.zeros((height, width), dtype=bool)
path = list()
-6
View File
@@ -1,6 +0,0 @@
__version__ = "1.0.0"
__author__ = "mteriier, dgaillet"
from .Parsing import DataMaze
__all__ = ["DataMaze"]
-1
View File
@@ -1,4 +1,3 @@
import pytest
from amaz_lib.Cell import Cell
+1 -1
View File
@@ -1,6 +1,6 @@
from amaz_lib.Cell import Cell
import numpy as np
from amaz_lib import AStar, Maze, MazeSolver
from amaz_lib import AStar, Maze
def test_solver() -> None:
Generated
+1 -1
View File
@@ -9,7 +9,7 @@ resolution-markers = [
[[package]]
name = "a-maze-ing"
version = "0.1.0"
source = { virtual = "." }
source = { editable = "." }
dependencies = [
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "numpy", version = "2.4.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },