From: Axy Date: Fri, 27 Mar 2026 12:08:38 +0000 (+0100) Subject: Plugging things in X-Git-Url: https://git.uwuaxy.net/flexible_layout.mp4?a=commitdiff_plain;h=0e8a523ea742caa74a902c0cbb6aed6a2aad4022;p=axy%2Fft%2Fa-maze-ing.git Plugging things in --- diff --git a/__main__.py b/__main__.py index 2ca0d66..bc8828d 100644 --- a/__main__.py +++ b/__main__.py @@ -1,4 +1,4 @@ -from amazeing.display.observer import TTYTracker +from amazeing.display.observer import MazeRegenerate, TTYTracker from amazeing.maze import ( Maze, Pattern, @@ -7,6 +7,7 @@ from amazeing.maze import ( PacmanTracker, make_pacman, make_perfect, + make_empty, ) from amazeing.config.config_parser import Config import random @@ -20,27 +21,41 @@ maze = Maze(config) pacman_tracker = PacmanTracker(maze) network_tracker = NetworkTracker(maze) -tty_tracker = TTYTracker(maze, config) +tty_tracker = TTYTracker(maze, config) if config.visual else None excluded = {maze.entry, maze.exit} pattern = Pattern(config.maze_pattern).centered_for(maze.dims, excluded) -pattern.fill(maze) -maze.outline() -walls_const = set(maze.walls_full()) -make_perfect(maze, network_tracker) -make_pacman(maze, walls_const, pacman_tracker) +def maze_main() -> None: + pattern.fill(maze) + maze.outline() + walls_const = set(maze.walls_full()) -while False: make_perfect(maze, network_tracker) - make_pacman(maze, walls_const, pacman_tracker) - make_empty(maze, walls_const) - - -while True: - tty_tracker.display_maze(wait_for_tick=True) - -tty_tracker.backend.uninit() + if not config.perfect: + make_pacman(maze, walls_const, pacman_tracker) + + while config.screensaver: + make_perfect(maze, network_tracker) + make_pacman(maze, walls_const, pacman_tracker) + + +if config.visual: + while True: + try: + if tty_tracker is not None: + tty_tracker.update = False + make_empty(maze, set()) + tty_tracker.update = True + + maze_main() + + while tty_tracker is not None: + tty_tracker.display_maze(wait_for_tick=True) + except MazeRegenerate: + continue +else: + maze_main() diff --git a/amazeing/config/config_parser.py b/amazeing/config/config_parser.py index cddcc40..63f18dd 100644 --- a/amazeing/config/config_parser.py +++ b/amazeing/config/config_parser.py @@ -389,7 +389,6 @@ class Config: seed: int | None screensaver: bool visual: bool - interactive: bool tilemap_wall_size: IVec2 tilemap_cell_size: IVec2 tilemap_full: list[list[ColoredLine]] @@ -423,7 +422,6 @@ class Config: "SEED": OptionalField(IntField), "SCREENSAVER": DefaultedField(BoolField, False), "VISUAL": DefaultedField(BoolField, False), - "INTERACTIVE": DefaultedField(BoolField, False), "TILEMAP_WALL_SIZE": DefaultedField( CoordField, IVec2(2, 1) ), diff --git a/amazeing/display/observer.py b/amazeing/display/observer.py index a412213..fe61fbe 100644 --- a/amazeing/display/observer.py +++ b/amazeing/display/observer.py @@ -1,72 +1,91 @@ +from sys import stderr import time from amazeing.config.config_parser import Config -from amazeing.display.tty import TTYBackend, TileCycle, TileMaps, extract_pairs +from amazeing.display.tty import TTYBackend, TileCycle from amazeing.maze.dirty_tracker import DirtyTracker from amazeing.maze.maze import Maze from amazeing.maze.path import path_pixels, pathfind_astar from amazeing.utils.coords import Cardinal +class MazeRegenerate(Exception): + pass + + class TTYTracker: - def __init__(self, maze: Maze, config: Config): - self.maze = maze - self.dirty_tracker = DirtyTracker(maze) - 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() + def __init__( + self, + maze: Maze, + config: Config, + ): + self.__maze = maze + self.__frametime: float = 0.016 + self.__dirty_tracker = DirtyTracker(maze) + 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() + ) + self.__full_style = TileCycle( + tilemaps.full, self.__backend.map_style_cb() + ) + self.__path_style = TileCycle( + tilemaps.path, self.__backend.map_style_cb() ) - self.full_style = TileCycle(tilemaps.full, self.backend.map_style_cb()) - self.path_style = TileCycle(tilemaps.path, self.backend.map_style_cb()) - self.backend.set_bg_init(lambda _: self.empty_style.curr_style()) + self.__backend.set_bg_init(lambda _: self.__empty_style.curr_style()) - self.tick: float | None = None - self.prev_path: list[Cardinal] | None = None - self.draw_path: bool = True + self.__tick: float | None = None + self.__path: list[Cardinal] | None = None + self.__draw_path: bool = True maze.observers.add(lambda _: self.display_maze()) + self.__paused: bool = False + + self.update: bool = True def clear_backend(self) -> None: - self.backend.set_style(self.empty_style.curr_style()) - for wall in self.dirty_tracker.curr_dirty(): - if self.maze.get_wall(wall): + self.__backend.set_style(self.__empty_style.curr_style()) + for wall in self.__dirty_tracker.curr_dirty(): + if self.__maze.get_wall(wall): continue for tile in wall.tile_coords(): - self.backend.draw_tile(tile) + self.__backend.draw_tile(tile) def path_invalidated(self) -> bool: - if self.prev_path is None: + if self.__path is None: return True - src = self.maze.entry - for card in self.prev_path: - if src.get_wall(card) in self.dirty_tracker.curr_dirty(): + src = self.__maze.entry + for card in self.__path: + if src.get_wall(card) in self.__dirty_tracker.curr_dirty(): return True src = src.get_neighbour(card) return False + def redraw_path(self, style: int) -> None: + if self.__path is not None: + self.__backend.set_style(style) + for tile in path_pixels(self.__maze.entry, self.__path): + self.__backend.draw_tile(tile) + def display_path(self) -> None: if ( - all(map(self.maze.get_wall, self.dirty_tracker.curr_dirty())) + all(map(self.__maze.get_wall, self.__dirty_tracker.curr_dirty())) and not self.path_invalidated() - and self.draw_path + and self.__draw_path ): return None - path = pathfind_astar(self.maze) if self.draw_path else None - if self.prev_path is not None: - self.backend.set_style(self.empty_style.curr_style()) - for tile in path_pixels(self.maze.entry, self.prev_path): - self.backend.draw_tile(tile) - self.prev_path = path - if path is not None: - self.backend.set_style(self.path_style.curr_style()) - for tile in path_pixels(self.maze.entry, path): - self.backend.draw_tile(tile) + path = pathfind_astar(self.__maze) if self.__draw_path else None + self.redraw_path(self.__empty_style.curr_style()) + self.__path = path + self.redraw_path(self.__path_style.curr_style()) def poll_events(self) -> None: while True: - event = self.backend.event() + event = self.__backend.event() if isinstance(event, bool): if not event: return @@ -74,49 +93,63 @@ class TTYTracker: if event.sym == "q": exit(0) if event.sym == "c": - self.filler_style.cycle() - self.full_style.cycle() - self.path_style.cycle() - self.empty_style.cycle() + self.__filler_style.cycle() + self.__full_style.cycle() + self.__path_style.cycle() + self.__empty_style.cycle() if event.sym == "v": - self.filler_style.cycle(-1) - self.full_style.cycle(-1) - self.path_style.cycle(-1) - self.empty_style.cycle(-1) + self.__filler_style.cycle(-1) + self.__full_style.cycle(-1) + self.__path_style.cycle(-1) + self.__empty_style.cycle(-1) if event.sym == "p": - self.draw_path = not self.draw_path + self.__draw_path = not self.__draw_path + if event.sym == "k": + self.__paused = not self.__paused + try: + while self.__paused: + self.display_maze(True) + finally: + self.__paused = False + if event.sym == "r": + self.redraw_path(self.__filler_style.curr_style()) + self.__path = None + raise MazeRegenerate else: continue - def display_maze( - self, wait_for_tick: bool = False, frametime: float = 0.016 - ) -> None: + def display_maze(self, wait_for_tick: bool = False) -> None: now = time.monotonic() - if self.tick is not None: + if self.__tick is not None: if wait_for_tick: - time.sleep(max(0.0, frametime - now + self.tick)) - elif now - self.tick < frametime: + time.sleep(max(0.0, self.__frametime - now + self.__tick)) + elif now - self.__tick < self.__frametime: return - self.tick = time.monotonic() + self.__tick = time.monotonic() + + if not self.update: + self.__backend.present() + self.poll_events() + return self.clear_backend() self.display_path() rewrites = { wall - for wall in self.dirty_tracker.curr_dirty() - if self.maze.get_wall(wall) + for wall in self.__dirty_tracker.curr_dirty() + if self.__maze.get_wall(wall) } | { e - for wall in self.dirty_tracker.curr_dirty() + for wall in self.__dirty_tracker.curr_dirty() for e in wall.neighbours() - if self.maze.check_coord(e) and self.maze.get_wall(e) + if self.__maze.check_coord(e) and self.__maze.get_wall(e) } - self.backend.set_style(self.full_style.curr_style()) + self.__backend.set_style(self.__full_style.curr_style()) for wall in rewrites: for pixel in wall.tile_coords(): - self.backend.draw_tile(pixel) - self.dirty_tracker.clear() - self.backend.present() + self.__backend.draw_tile(pixel) + self.__dirty_tracker.clear() self.poll_events() + self.__backend.present() diff --git a/amazeing/maze/make_empty.py b/amazeing/maze/make_empty.py index 8b5bcea..f56d53d 100644 --- a/amazeing/maze/make_empty.py +++ b/amazeing/maze/make_empty.py @@ -1,4 +1,3 @@ -from collections.abc import Callable from amazeing.maze import Maze from amazeing.utils import WallCoord import random @@ -7,10 +6,8 @@ import random def make_empty( maze: Maze, walls_const: set[WallCoord], - callback: Callable[[Maze], None] = lambda _: None, ) -> None: walls = [wall for wall in maze.walls_full() if wall not in walls_const] random.shuffle(walls) for wall in walls: maze.set_wall(wall, False) - callback(maze) diff --git a/amazeing/maze/make_perfect.py b/amazeing/maze/make_perfect.py index 529ffff..eb45b61 100644 --- a/amazeing/maze/make_perfect.py +++ b/amazeing/maze/make_perfect.py @@ -1,4 +1,3 @@ -from typing import Callable from amazeing.maze import Maze import random diff --git a/example.conf b/example.conf index 4310962..d752314 100644 --- a/example.conf +++ b/example.conf @@ -3,7 +3,9 @@ HEIGHT=100 ENTRY=0,0 EXIT=24,24 OUTPUT_FILE=test -PERFECT=False +PERFECT=True +VISUAL=True +SCREENSAVER=False SEED=111 #TILEMAP_WALL_SIZE=2,1