import random
from amazeing.config.config_parser import Config
-from amazeing.maze_class.maze_walls import CellCoord
+from amazeing.maze_class.maze_walls import Cardinal, CellCoord
from amazeing.maze_display.TTYdisplay import TileCycle, TileMaps, extract_pairs
from amazeing.maze_display.backend import CloseRequested, IVec2
tilemaps = TileMaps(config, pair_map, backend)
filler = TileCycle(tilemaps.filler, backend.set_filler)
-backend.set_style(tilemaps.empty[0])
+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())
+full = TileCycle(tilemaps.full, backend.map_style_cb())
+
+path = TileCycle(tilemaps.path, backend.map_style_cb())
+
def clear_backend() -> None:
- backend.set_style(tilemaps.empty[0])
+ backend.set_style(empty.curr_style())
for wall in maze.walls_dirty():
if maze.get_wall(wall).is_full():
continue
def display_maze(maze: Maze) -> None:
clear_backend()
- backend.set_style(tilemaps.full[0])
+ pathfind()
+ backend.set_style(full.curr_style())
rewrites = {
wall for wall in maze.walls_dirty() if maze.get_wall(wall).is_full()
exit(0)
if event.sym == "c":
filler.cycle()
+ full.cycle()
+ path.cycle()
+ empty.cycle()
else:
continue
backend.present()
+prev_path: list[IVec2] = []
+
+
+def pathfind() -> None:
+ if config.entry is None or config.exit is None:
+ return
+ solution = maze.pathfind(CellCoord(config.entry), CellCoord(config.exit))
+ if solution is None:
+ return
+ tiles = Cardinal.path_to_tiles(solution, CellCoord(config.entry))
+ if prev_path == tiles:
+ return
+ backend.set_style(empty.curr_style())
+ for tile in prev_path:
+ backend.draw_tile(tile)
+ prev_path.clear()
+ prev_path.extend(tiles)
+ backend.set_style(path.curr_style())
+ for tile in tiles:
+ backend.draw_tile(tile)
+ backend.present()
+
+
maze_make_perfect(maze, callback=display_maze)
maze_make_pacman(maze, walls_const, callback=display_maze)
-if config.entry is not None and config.exit is not None:
- path = maze.pathfind(CellCoord(config.entry), CellCoord(config.exit))
+
+
+pathfind()
+
+
while False:
maze_make_perfect(maze, callback=display_maze)
# poll_events(200)
tilemap_cell_size: IVec2
tilemap_full: list[list[ColoredLine]]
tilemap_empty: list[list[ColoredLine]]
+ tilemap_path: list[list[ColoredLine]]
tilemap_background_size: IVec2
tilemap_background: list[list[ColoredLine]]
maze_pattern: list[str]
ColoredLineField,
['"{BLACK:BLACK} "', '"{BLACK:BLACK} "'],
),
+ "TILEMAP_PATH": DefaultedStrField(
+ ColoredLineField,
+ ['"{BLUE:BLUE} "', '"{BLUE:BLUE} "'],
+ ),
"TILEMAP_BACKGROUND_SIZE": DefaultedField(
CoordField, IVec2(4, 2)
),
def all() -> list["Cardinal"]:
return [Cardinal.NORTH, Cardinal.SOUTH, Cardinal.EAST, Cardinal.WEST]
+ @staticmethod
+ def path_to_tiles(path: list["Cardinal"], src: "CellCoord") -> list[IVec2]:
+ res = [src.tile_coords()]
+ for card in path:
+ nxt = src.get_neighbour(card)
+ res.append((src.tile_coords() + nxt.tile_coords()) // 2)
+ res.append(nxt.tile_coords())
+ src = nxt
+ return res
+
class WallCoord:
def __init__(self, orientation: Orientation, a: int, b: int) -> None:
super().__init__(a.x, a.y)
def walls(self) -> Iterable[WallCoord]:
- return map(
- self.get_wall,
- [Cardinal.NORTH, Cardinal.SOUTH, Cardinal.EAST, Cardinal.WEST],
- )
+ return map(self.get_wall, Cardinal.all())
def get_wall(self, cardinal: Cardinal) -> WallCoord:
match cardinal:
for tilemaps in (
config.tilemap_empty,
config.tilemap_full,
+ config.tilemap_path,
config.tilemap_background,
)
for e in tilemaps
self.empty: list[int] = list(map(add_style, config.tilemap_empty))
self.full: list[int] = list(map(add_style, config.tilemap_full))
+ self.path: list[int] = list(map(add_style, config.tilemap_path))
self.filler: list[int] = list(
map(
lambda e: add_style(e, config.tilemap_background_size),
)
-class TileCycle:
- def __init__[T](
- self, styles: list[T], cb: Callable[[T], None], i=0
- ) -> None:
+class TileCycle[T]:
+ def __init__(self, styles: list[T], cb: Callable[[T], None], i=0) -> None:
+ if len(styles) == 0:
+ raise BackendException("No styles provided in tilecycle")
self.__styles = styles
self.__cb = cb
self.__i = i
cb(styles[i])
def cycle(self, by: int = 1):
- self.__i += by
- self.__i %= len(self.__styles)
- self.__cb(self.__styles[self.__i])
+ new = (self.__i + by) % len(self.__styles)
+ if new != self.__i:
+ self.__cb(self.__styles[new])
+ self.__i = new
+
+ def curr_style(self) -> T:
+ return self.__styles[self.__i]
class TTYBackend(Backend[int]):
self.__filler: None | int = None
+ self.__style_mapping: dict[int, set[IVec2]] = {}
+ self.__style_revmapping: dict[IVec2, int] = {}
+
def __del__(self):
curses.curs_set(1)
curses.nocbreak()
for box in self.__filler_boxes:
box.mark_dirty()
+ def get_styled(self, style: int) -> Iterable[IVec2]:
+ return set(
+ self.__style_mapping[style]
+ if style in self.__style_mapping
+ else []
+ )
+
+ def map_style_cb(self) -> Callable[[int], None]:
+ curr: int | None = None
+
+ def inner(new: int) -> None:
+ nonlocal curr
+ if curr == None:
+ curr = new
+ if curr == new:
+ return
+ self.set_style(new)
+ for tile in self.get_styled(curr):
+ self.draw_tile(tile)
+ curr = new
+
+ return inner
+
def add_style(self, style: Tile) -> int:
return self.__tilemap.add_tile(style)
return self.__dims
def draw_tile(self, pos: IVec2) -> None:
- self.__tilemap.draw_at(pos, self.__style, self.__pad.pad)
+ style = self.__style
+ mapping = self.__style_mapping
+ revmapping = self.__style_revmapping
+
+ if pos in revmapping:
+ mapping[revmapping[pos]].remove(pos)
+ revmapping[pos] = style
+ if style not in mapping:
+ mapping[style] = set()
+ mapping[style].add(pos)
+
+ self.__tilemap.draw_at(pos, style, self.__pad.pad)
def set_style(self, style: int) -> None:
self.__style = style
-WIDTH=20
-HEIGHT=20
+WIDTH=40
+HEIGHT=40
ENTRY=5,5
-EXIT=10,10
+EXIT=25,25
OUTPUT_FILE=test
PERFECT=False
SEED=111
TILEMAP_FULL="{1000,1000,1000:1000,1000,1000}######"
TILEMAP_FULL="{1000,1000,1000:1000,1000,1000}######"
TILEMAP_FULL="{1000,1000,1000:1000,1000,1000}######"
+TILEMAP_FULL=1"{100,1000,1000:1000,1000,1000}######"
+TILEMAP_FULL=1"{100,1000,1000:1000,1000,1000}######"
+TILEMAP_FULL=1"{100,1000,1000:1000,1000,1000}######"
+TILEMAP_PATH="{100,100,1000:100,100,1000} "
+TILEMAP_PATH="{100,100,1000:100,100,1000} "
+TILEMAP_PATH="{100,100,1000:100,100,1000} "
TILEMAP_EMPTY="{0,0,0:0,0,0} "
TILEMAP_EMPTY="{0,0,0:0,0,0} "
TILEMAP_EMPTY="{0,0,0:0,0,0} "