]> Untitled Git - axy/ft/a-maze-ing.git/commitdiff
Advanced layout
authorAxy <gilliardmarthey.axel@gmail.com>
Thu, 26 Mar 2026 17:16:39 +0000 (18:16 +0100)
committerAxy <gilliardmarthey.axel@gmail.com>
Thu, 26 Mar 2026 17:16:39 +0000 (18:16 +0100)
amazeing/config/config_parser.py
amazeing/display/observer.py
amazeing/display/tty.py
amazeing/maze/maze.py
amazeing/maze/path.py
example.conf

index f868827fbbb83bb30b4faa39c024767e9d345449..3bf152d462efc1a62df9cea1edb20f88d39a3b6e 100644 (file)
@@ -383,6 +383,9 @@ class Config:
     tilemap_path: list[list[ColoredLine]]
     tilemap_background_size: IVec2
     tilemap_background: list[list[ColoredLine]]
+    tilemap_box_size: IVec2
+    tilemap_box_bridge_size: IVec2
+    tilemap_box: list[ColoredLine]
     maze_pattern: list[str]
 
     def __init__(self) -> None:
@@ -433,6 +436,21 @@ class Config:
                     "MAZE_PATTERN": DefaultedField(
                         PatternField, Pattern.FT_PATTERN
                     ),
+                    "TILEMAP_BOX_SIZE": DefaultedField(
+                        CoordField, IVec2(1, 1)
+                    ),
+                    "TILEMAP_BOX_BRIDGE_SIZE": DefaultedField(
+                        CoordField, IVec2(1, 1)
+                    ),
+                    "TILEMAP_BOX": DefaultedStrField(
+                        ListParser(parse_colored_line),
+                        [
+                            '"{1000,500,500:0,0,0}╔═╦╗"',
+                            '"{1000,500,500:0,0,0}║ ║║"',
+                            '"{1000,500,500:0,0,0}╠═╬╣"',
+                            '"{1000,500,500:0,0,0}╚═╩╝"',
+                        ],
+                    ),
                 }
             )
         )(s)
index 55cce1db28e41f9845e311f40364b06752156cfe..8303a5cf217a07649fb7559cb065863fd1206807 100644 (file)
@@ -11,11 +11,8 @@ class TTYTracker:
     def __init__(self, maze: Maze, config: Config):
         self.maze = maze
         self.dirty_tracker = DirtyTracker(maze)
-        self.backend = TTYBackend(
-            maze.dims, config.tilemap_wall_size, config.tilemap_cell_size
-        )
-        self.pair_map = extract_pairs(config)
-        tilemaps = TileMaps(config, self.pair_map, self.backend)
+        self.backend = TTYBackend(config)
+        tilemaps = self.backend.tilemaps
         self.filler_style = TileCycle(tilemaps.filler, self.backend.set_filler)
         self.empty_style = TileCycle(
             tilemaps.empty, self.backend.map_style_cb()
index 892318b9b6ce3bb5edd2a4376bcef92679c4412d..36bc147404316b22485ee37a46108337d16ce41f 100644 (file)
@@ -18,6 +18,8 @@ from amazeing.display.layout import (
 from amazeing.utils import Rect, QuadTree, IVec2
 import curses
 
+from amazeing.utils.coords import Orientation
+
 
 class BackendException(Exception):
     pass
@@ -184,11 +186,11 @@ class MazeTileMap:
     def __init__(self, wall_dim: IVec2, cell_dim: IVec2) -> None:
         self.__wall_dim: IVec2 = wall_dim
         self.__cell_dim: IVec2 = cell_dim
-        self.__tiles: list[Tile] = []
+        self.tiles: list[ITile] = []
 
-    def add_tile(self, tile: Tile) -> int:
-        res = len(self.__tiles)
-        self.__tiles.append(tile)
+    def add_tile(self, tile: ITile) -> int:
+        res = len(self.tiles)
+        self.tiles.append(tile)
         return res
 
     def dst_coord(self, pos: IVec2) -> IVec2:
@@ -211,7 +213,7 @@ class MazeTileMap:
         ) * self.__wall_dim + pos % IVec2.splat(2) * self.__cell_dim
 
     def draw_at(self, at: IVec2, idx: int, window: curses.window) -> None:
-        self.__tiles[idx].blit(
+        self.tiles[idx].blit(
             self.src_coord(at),
             self.dst_coord(at),
             self.tile_size(at),
@@ -226,7 +228,7 @@ class MazeTileMap:
         idx: int,
         window: curses.window,
     ) -> None:
-        self.__tiles[idx].blit_wrapping(start, at, into, window)
+        self.tiles[idx].blit_wrapping(start, at, into, window)
 
 
 class ScrollablePad:
@@ -289,7 +291,7 @@ def extract_pairs(
             config.tilemap_background,
         )
         for e in tilemaps
-    ]
+    ] + [config.tilemap_box]
     pairs = {
         pair
         for tilemap in all_tilemaps
@@ -376,6 +378,26 @@ class TileMaps:
             )
         )
 
+        box = new_tilemap(
+            config.tilemap_box,
+            config.tilemap_box_size * IVec2.splat(3)
+            + config.tilemap_box_bridge_size,
+        )
+
+        self.box: list[list[int]] = []
+        corner = config.tilemap_box_size
+        bridge = config.tilemap_box_bridge_size
+        y = 0
+        for height in (corner.y, bridge.y, corner.y, corner.y):
+            x = 0
+            line: list[int] = []
+            for width in (corner.x, bridge.x, corner.x, corner.x):
+                tile = SubTile(box, IVec2(x, y), IVec2(width, height))
+                line.append(backend.add_style(tile))
+                x += width
+            self.box.append(line)
+            y += height
+
 
 class TileCycle[T]:
     def __init__(
@@ -400,14 +422,18 @@ class TileCycle[T]:
 
 class TTYBackend:
     def __init__(
-        self, maze_dims: IVec2, wall_dim: IVec2, cell_dim: IVec2
+        self,
+        config: Config,
     ) -> None:
         super().__init__()
-        self.__tilemap: MazeTileMap = MazeTileMap(wall_dim, cell_dim)
+        self.__tilemap: MazeTileMap = MazeTileMap(
+            config.tilemap_wall_size, config.tilemap_cell_size
+        )
         self.__style = 0
+        self.__dims = IVec2(config.width, config.height)
 
         dims = self.__tilemap.dst_coord(
-            maze_dims * IVec2.splat(2) + IVec2.splat(1)
+            self.__dims * IVec2.splat(2) + IVec2.splat(1)
         )
 
         self.__screen: curses.window = curses.initscr()
@@ -417,10 +443,12 @@ class TTYBackend:
         curses.curs_set(0)
         self.__screen.keypad(True)
 
+        pair_map = extract_pairs(config)
+        self.tilemaps = TileMaps(config, pair_map, self)
+
         self.__scratch: curses.window = curses.newpad(1, 1)
         self.__drawn: QuadTree = QuadTree()
         self.__pad: ScrollablePad = ScrollablePad(dims, self.pad_callback)
-        self.__dims = maze_dims
 
         maze_box = FBox(
             IVec2(BInt(dims.x), BInt(dims.y)),
@@ -448,18 +476,42 @@ class TTYBackend:
             )
             return res
 
+        def border_box(x: int, y: int, orient: Orientation | None) -> Box:
+            tile = self.tilemaps.box[y][x]
+            dims = self.__tilemap.tiles[tile].size()
+            box_dims = IVec2(BInt(0, True), BInt(0, True))
+            match orient:
+                case Orientation.HORIZONTAL:
+                    box_dims.y = BInt(dims.y)
+                case Orientation.VERTICAL:
+                    box_dims.x = BInt(dims.x)
+                case None:
+                    box_dims.x = BInt(dims.x)
+                    box_dims.y = BInt(dims.y)
+
+            return FBox(
+                box_dims,
+                lambda at, into: self.__tilemap.draw_at_wrapping(
+                    IVec2(0, 0), at, into, tile, self.__scratch
+                ),
+            )
+
         f: Callable[[int], int] = lambda e: e
         layout = layout_split(
             layout_fair, layout_sort_chunked(layout_fair, layout_priority, f)
         )
-        self.__layout: Box = VBox(
+        maze_box = VBox(
             layout,
             [
                 (filler_box(), 0),
                 (
                     HBox(
                         layout,
-                        [(filler_box(), 0), (maze_box, 1), (filler_box(), 0)],
+                        [
+                            (filler_box(), 0),
+                            (maze_box, 1),
+                            (filler_box(), 0),
+                        ],
                     ),
                     1,
                 ),
@@ -467,6 +519,39 @@ class TTYBackend:
             ],
         )
 
+        prompt_box = filler_box()
+
+        def border_line_box(y: int) -> Box:
+            return HBox.noassoc(
+                layout_fair,
+                [
+                    border_box(0, y, None),
+                    border_box(1, y, Orientation.HORIZONTAL),
+                    border_box(3, y, None),
+                ],
+            )
+
+        def border_column_sides(box: Box) -> Box:
+            return HBox.noassoc(
+                layout_fair,
+                [
+                    border_box(0, 1, Orientation.VERTICAL),
+                    box,
+                    border_box(3, 1, Orientation.VERTICAL),
+                ],
+            )
+
+        self.__layout: Box = VBox.noassoc(
+            layout_fair,
+            [
+                border_line_box(0),
+                border_column_sides(maze_box),
+                border_line_box(2),
+                border_column_sides(prompt_box),
+                border_line_box(3),
+            ],
+        )
+
         self.__resize: bool = False
 
         self.__filler: None | int = None
@@ -540,7 +625,7 @@ class TTYBackend:
 
         return inner
 
-    def add_style(self, style: Tile) -> int:
+    def add_style(self, style: ITile) -> int:
         return self.__tilemap.add_tile(style)
 
     def dims(self) -> IVec2:
index d1b6e1c6d024531dc916722bf8686b76774ceecd..82209571f13fe346556d90e644f2c3f3a54a530b 100644 (file)
@@ -52,7 +52,12 @@ class Maze:
         return CellCoord(self.dims).all_up_to()
 
     def check_cell(self, cell: CellCoord) -> bool:
-        return self.dims.x > cell.x and self.dims.y > cell.y
+        return (
+            self.dims.x > cell.x
+            and self.dims.y > cell.y
+            and cell.x >= 0
+            and cell.y >= 0
+        )
 
     def check_coord(self, coord: WallCoord) -> bool:
         if coord.a < 0 or coord.b < 0:
index 0835e07f997217260bb3a879a1a28686a14ccd42..0062be5be598adfc67b6a4661f9e3cac32456b08 100644 (file)
@@ -1,13 +1,10 @@
 from collections.abc import Generator
 from dataclasses import dataclass
 from amazeing.maze.maze import Maze
-from amazeing.maze.network_tracker import NetworkTracker
 from amazeing.utils.coords import Cardinal, CellCoord
 from amazeing.utils.ivec2 import IVec2
 import heapq
 
-from amazeing.utils.quadtree import rect_collides
-
 
 def taxicab_distance(a: IVec2, b: IVec2) -> int:
     return sum(a.with_op(lambda lhs, rhs: abs(lhs - rhs), b).xy())
index ba2f5395ea3f069dee9172a4e0cf006db8ef2efe..03540a4036b82c7815df41d133f6568f2684bdb9 100644 (file)
@@ -1,5 +1,5 @@
-WIDTH=25
-HEIGHT=25
+WIDTH=16
+HEIGHT=16
 ENTRY=0,0
 EXIT=24,24
 OUTPUT_FILE=test
@@ -29,6 +29,13 @@ TILEMAP_BACKGROUND=1"{100,1000,1000:0,0,0}######  "
 TILEMAP_BACKGROUND=1"{100,1000,1000:0,0,0}    ##  "
 TILEMAP_BACKGROUND=1"{100,1000,1000:0,0,0}##  ##  "
 
+#TILEMAP_BOX_SIZE=1,1
+#TILEMAP_BOX_BRIDGE_SIZE=1,1
+#TILEMAP_BOX="{200,100,100:0,0,0}+-++"
+#TILEMAP_BOX="{200,100,100:0,0,0}| ||"
+#TILEMAP_BOX="{200,100,100:0,0,0}+-++"
+#TILEMAP_BOX="{200,100,100:0,0,0}+-++"
+
 #MAZE_PATTERN=" #   # "
 #MAZE_PATTERN="  # #  "
 #MAZE_PATTERN="   #   "