]> Untitled Git - axy/ft/a-maze-ing.git/commitdiff
Slightly broken, style remapping doesn't work properly but the rest is fine
authorAxy <gilliardmarthey.axel@gmail.com>
Fri, 20 Mar 2026 20:23:39 +0000 (21:23 +0100)
committerAxy <gilliardmarthey.axel@gmail.com>
Fri, 20 Mar 2026 20:23:39 +0000 (21:23 +0100)
__main__.py
amazeing/maze_class/maze_pattern.py
amazeing/maze_display/TTYdisplay.py
amazeing/utils/bi_map.py
amazeing/utils/quadtree.py
example.conf

index 656eb62818439e988efa9b97230bcc304b263cbc..836e648b8c4557ec27e348710ed8b89afc023604 100644 (file)
@@ -29,32 +29,14 @@ maze = Maze(dims)
 
 dirty_tracker = MazeDirtyTracker(maze)
 pacman_tracker = MazePacmanTracker(maze)
-
-maze.outline()
-
-excluded = set()
-if config.entry is not None:
-    excluded.add(CellCoord(config.entry))
-if config.exit is not None:
-    excluded.add(CellCoord(config.exit))
-
-pattern = Pattern(config.maze_pattern).centered_for(dims, excluded)
-pattern.fill(maze)
-
-walls_const = set(maze.walls_full())
+network_tracker = MazeNetworkTracker(maze)
 
 backend = TTYBackend(dims, config.tilemap_wall_size, config.tilemap_cell_size)
 pair_map = extract_pairs(config)
 tilemaps = TileMaps(config, pair_map, backend)
 filler = TileCycle(tilemaps.filler, backend.set_filler)
-
 empty = TileCycle(tilemaps.empty, backend.map_style_cb())
-backend.set_style(empty.curr_style())
-for wall in maze.all_walls():
-    for tile in wall.tile_coords():
-        backend.draw_tile(tile)
-for cell in CellCoord(dims).all_up_to():
-    backend.draw_tile(cell.tile_coords())
+backend.set_bg_init(lambda _: empty.curr_style())
 
 full = TileCycle(tilemaps.full, backend.map_style_cb())
 
@@ -128,70 +110,20 @@ def poll_events(timeout_ms: int = -1) -> None:
             continue
 
 
-prev_solution: list[Cardinal] = []
-
-
-def manhattan_distance(a: IVec2, b: IVec2) -> int:
-    return sum(map(abs, (a - b).xy()))
-
-
-def elipse_manhattan(a: IVec2, b: IVec2, a2: IVec2, b2: IVec2) -> int:
-    return min(
-        manhattan_distance(a1, a2) + manhattan_distance(b1, b2)
-        for a1, b1 in ((a, b), (b, a))
-    )
-
-
-# def pathfind_necessary() -> bool:
-#    entry = config.entry
-#    exit = config.exit
-#    if entry is None or exit is None:
-#        return False
-#    if len(prev_solution) == 0:
-#        return True
-#    if any(
-#        map(
-#            lambda e: e in dirty_tracker.curr_dirty() and maze.get_wall(e),
-#            Cardinal.path_to_walls(prev_solution, CellCoord(entry)),
-#        )
-#    ):
-#        return True
-#    if any(
-#        map(
-#            lambda e: elipse_manhattan(entry, exit, *e.neighbour_cells())
-#            < len(prev_solution),
-#            filter(
-#                lambda wall: not maze.get_wall(wall),
-#                dirty_tracker.curr_dirty(),
-#            ),
-#        )
-#    ):
-#        return True
-#    return False
-#
-#
-# def pathfind() -> None:
-#    if not pathfind_necessary():
-#        return
-#    if config.entry is None or config.exit is None:
-#        return
-#    solution = maze.pathfind(CellCoord(config.entry), CellCoord(config.exit))
-#    if solution is None or prev_solution == solution:
-#        return
-#   prev_tiles = Cardinal.path_to_tiles(prev_solution, CellCoord(config.entry))
-#    tiles = Cardinal.path_to_tiles(solution, CellCoord(config.entry))
-#    backend.set_style(empty.curr_style())
-#    for tile in prev_tiles:
-#        backend.draw_tile(tile)
-#    backend.set_style(path.curr_style())
-#    for tile in tiles:
-#        backend.draw_tile(tile)
-#    backend.present()
-#    prev_solution.clear()
-#    prev_solution.extend(solution)
+excluded = set()
+if config.entry is not None:
+    excluded.add(CellCoord(config.entry))
+if config.exit is not None:
+    excluded.add(CellCoord(config.exit))
+
+pattern = Pattern(config.maze_pattern).centered_for(dims, excluded)
+pattern.fill(maze)
+
+maze.outline()
+
+walls_const = set(maze.walls_full())
 
 
-network_tracker = MazeNetworkTracker(maze)
 maze_make_perfect(maze, network_tracker, callback=display_maze)
 maze_make_pacman(maze, walls_const, pacman_tracker, callback=display_maze)
 
index efb401a7633b3c5318cd4e5fb18b0cfb7bf37ee2..62cd09fcd606fca9cc7985ad24a6b92e4e253dcd 100644 (file)
@@ -1,8 +1,7 @@
-from collections.abc import Iterable
+from collections.abc import Iterable, Generator, Callable
 from amazeing.maze_display.backend import IVec2
 from .maze import Maze
 from .maze_coords import CellCoord
-from typing import Callable
 
 
 class Pattern:
@@ -93,22 +92,28 @@ class Pattern:
         normalized: Pattern = self.normalized()
         negative = normalized.flood_filled().mirrored()
         dims = normalized.dims()
-        slots = set(
-            map(
-                lambda e: CellCoord(e + IVec2.splat(1)),
-                CellCoord(canvas - dims - IVec2.splat(1)).all_up_to(),
-            )
-        )
-        for excluded in excluding:
-            slots -= negative.offset(excluded).__cells
-        if len(slots) == 0:
-            return Pattern([])
-        ideal = (canvas - dims) // IVec2.splat(2)
-        slot = min(
-            slots, key=lambda c: int.__add__(*((e := c - ideal) * e).xy())
-        )
 
-        return normalized.offset(slot)
+        def middle_range_iter(start: int, end: int) -> Generator[int]:
+            r1 = range(end // 2, start - 1, -1)
+            r2 = range(end // 2 + 1, end)
+            for a, b in zip(r1, r2):
+                yield a
+                yield b
+            for e in r1:
+                yield e
+            for e in r2:
+                yield e
+
+        blacklist = set()
+        for excluded in excluding:
+            blacklist |= negative.offset(excluded).__cells
+        slots = canvas - dims
+        for x in middle_range_iter(1, slots.x):
+            for y in middle_range_iter(1, slots.y):
+                pos = CellCoord(x, y)
+                if pos not in blacklist:
+                    return normalized.offset(pos)
+        return Pattern([])
 
     def fill(self, maze: "Maze") -> None:
         for cell in self.__cells:
index d1ede806c6d6f746a048a66bac37bfb22df695d8..162e74663160c27666d3cbdc9dc72e3b1e27050a 100644 (file)
@@ -470,6 +470,8 @@ class TTYBackend:
         self.__filler: None | int = None
 
         self.__style_bimap: BiMap[int, IVec2] = BiMap()
+        self.__style_rename_bimap: BiMap[int, int] = BiMap()
+        self.__bg_init: Callable[[IVec2], int] | None = None
 
     def __del__(self) -> None:
         curses.curs_set(1)
@@ -485,8 +487,19 @@ class TTYBackend:
             self.__tilemap.dst_coord_rev(end_excl - IVec2.splat(1))
             + IVec2.splat(1),
         )
-        self.__drawn += QuadTree.rectangle(drawn_rect)
-        pass
+        drawn_tree = QuadTree.rectangle(drawn_rect)
+        redrawn = drawn_tree - self.__drawn
+        for tile in redrawn.tiles():
+            if self.__style_bimap.revcontains(tile):
+                style = self.__style_bimap.revget(tile)
+                if self.__style_rename_bimap.revcontains(style):
+                    style = self.__style_rename_bimap.revget(style)
+                self.set_style(style)
+                self.draw_tile(tile)
+            elif self.__bg_init is not None:
+                self.set_style(self.__bg_init(tile))
+                self.draw_tile(tile)
+        self.__drawn += drawn_tree
 
     def set_filler(self, style: int) -> None:
         if self.__filler == style:
@@ -495,7 +508,10 @@ class TTYBackend:
         for box in self.__filler_boxes:
             box.mark_dirty()
 
-    def get_styled(self, style: int) -> Iterable[IVec2]:
+    def set_bg_init(self, bg_init: Callable[[IVec2], int]) -> None:
+        self.__bg_init = bg_init
+
+    def get_styled(self, style: int) -> set[IVec2]:
         return self.__style_bimap.get(style)
 
     def map_style_cb(self) -> Callable[[int], None]:
@@ -507,9 +523,9 @@ class TTYBackend:
                 curr = new
             if curr == new:
                 return
-            self.set_style(new)
-            for tile in self.get_styled(curr):
-                self.draw_tile(tile)
+            if len(self.get_styled(curr)) != 0:
+                self.__drawn = QuadTree()
+                self.__style_rename_bimap.add(new, curr)
             curr = new
 
         return inner
index 5cfaf76cc4ccbfab916f0057b6c0708a7153d870..25ca372e7b2a95ac2733e245d9e8958bf4eb7de2 100644 (file)
@@ -25,8 +25,8 @@ class BiMap[K, R]:
         if len(self.__map[key]) == 0:
             self.__map.pop(key)
 
-    def get(self, key: K) -> Iterable[R]:
-        return list(self.__map[key] if self.contains(key) else [])
+    def get(self, key: K) -> set[R]:
+        return self.__map[key] if self.contains(key) else set()
 
     def revget(self, revkey: R) -> K:
         return self.__revmap[revkey]
index 47e06fd512f705666965b1715708cfe725f2638d..222e11b4bb76b66a6ae6e3f33c984246890aeb69 100644 (file)
@@ -1,4 +1,4 @@
-from collections.abc import Callable
+from collections.abc import Callable, Generator, Iterable
 from typing import cast
 from amazeing.maze_display.backend import IVec2
 from functools import partial
@@ -106,6 +106,23 @@ class Tree:
     def __sub__(self, other: "Tree") -> "Tree":
         return self.shared_layer_apply(Tree.node_sub, other)
 
+    def tiles(self) -> Generator[IVec2]:
+        return Tree.node_tiles(self.__root, IVec2.splat(0), self.__height)
+
+    @staticmethod
+    def node_tiles(
+        node: MaybeNode, pos: IVec2, height: int
+    ) -> Generator[IVec2]:
+        if height == 0 and node == True:
+            yield pos
+        if height == 0 or node == False:
+            return
+        for pos, node in zip4(
+            Tree.node_starts(pos, height), Tree.node_split(node)
+        ):
+            for pos in Tree.node_tiles(node, pos, height - 1):
+                yield pos
+
     @staticmethod
     def rectangle(rect: Rect) -> "Tree":
         res = Tree()
index a0f7394f4dc7d8a57d798b5ba7fde6903db9fc7e..e023c67a7578ec3acaed0dcd5a62e43e943a8dee 100644 (file)
@@ -1,5 +1,5 @@
-WIDTH=100
-HEIGHT=100
+WIDTH=1000
+HEIGHT=1000
 ENTRY=0,0
 EXIT=24,24
 OUTPUT_FILE=test