-from amazeing.display.observer import TTYTracker
+from amazeing.display.observer import MazeRegenerate, TTYTracker
from amazeing.maze import (
Maze,
Pattern,
PacmanTracker,
make_pacman,
make_perfect,
+ make_empty,
)
from amazeing.config.config_parser import Config
import random
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()
+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
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()