From: Axy Date: Mon, 9 Mar 2026 18:48:23 +0000 (+0100) Subject: Pathfinding X-Git-Url: https://git.uwuaxy.net/?a=commitdiff_plain;h=27b0f26d2fec650a4280a4942b40d7d3b2de6068;p=axy%2Fft%2Fa-maze-ing.git Pathfinding --- diff --git a/__main__.py b/__main__.py index 0e23b76..22d26e9 100644 --- a/__main__.py +++ b/__main__.py @@ -27,9 +27,13 @@ maze = Maze(dims) maze.outline() -pattern = Pattern(config.maze_pattern).centered_for( - dims, {CellCoord(5, 5), CellCoord(10, 10)} -) +excluded = set() +if config.entry is not None: + excluded.add(config.entry) +if config.exit is not None: + excluded.add(config.exit) + +pattern = Pattern(config.maze_pattern).centered_for(dims, excluded) pattern.fill(maze) walls_const = set(maze.walls_full()) @@ -54,7 +58,6 @@ def clear_backend() -> None: continue for tile in wall.tile_coords(): backend.draw_tile(tile) - pass def display_maze(maze: Maze) -> None: @@ -76,7 +79,6 @@ def display_maze(maze: Maze) -> None: maze.clear_dirty() backend.present() poll_events(0) - # poll_events(0) def poll_events(timeout_ms: int = -1) -> None: @@ -97,6 +99,9 @@ def poll_events(timeout_ms: int = -1) -> None: maze_make_perfect(maze, callback=display_maze) maze_make_pacman(maze, walls_const, callback=display_maze) +print( + maze.pathfind(CellCoord(config.entry), CellCoord(config.exit)), file=stderr +) while False: maze_make_perfect(maze, callback=display_maze) # poll_events(200) diff --git a/amazeing/config/config_parser.py b/amazeing/config/config_parser.py index 0b20ed7..b6bd56c 100644 --- a/amazeing/config/config_parser.py +++ b/amazeing/config/config_parser.py @@ -44,6 +44,10 @@ def parse_comment(s: str) -> ParseResult[str]: return recognize(seq(tag("#"), many_count(none_of("\n"))))(s) +def parse_empty_line(s: str) -> ParseResult[None]: + return (None, s) if s.startswith("\n") else None + + def spaced[T](parser: Parser[T]) -> Parser[T]: return delimited(multispace0, parser, multispace0) @@ -291,6 +295,7 @@ def line_parser[T]( ) for name, field in fields.items() ), + parser_map(lambda _: None, parse_empty_line), ) diff --git a/amazeing/maze_class/maze.py b/amazeing/maze_class/maze.py index a01e07d..28804ce 100644 --- a/amazeing/maze_class/maze.py +++ b/amazeing/maze_class/maze.py @@ -1,7 +1,10 @@ +from sys import stderr from typing import Callable, Generator, Iterable, cast from amazeing.maze_display.backend import IVec2 from .maze_walls import ( + Cardinal, + CellCoord, MazeWall, NetworkID, Orientation, @@ -191,3 +194,43 @@ class Maze: def clear_dirty(self) -> None: self.__dirty = set() + + def pathfind( + self, src: CellCoord, dst: CellCoord + ) -> list[Cardinal] | None: + class Path: + def __init__(self, prev: tuple["Path", Cardinal] | None) -> None: + self.prev: tuple["Path", Cardinal] | None = prev + + def to_list(self) -> list[Cardinal]: + if self.prev is None: + return [] + prev, direction = self.prev + prev_list = prev.to_list() + prev_list.append(direction) + return prev_list + + def __add__(self, value: Cardinal) -> "Path": + return Path((self, value)) + + walls_empty = set(self.walls_empty()) + visited = set() + border = {src: Path(None)} + while len(border) != 0: + border_next = {} + for pos, path in border.items(): + if pos == dst: + return path.to_list() + visited.add(pos) + for direction in Cardinal.all(): + if pos.get_wall(direction) not in walls_empty: + continue + neighbour = pos.get_neighbour(direction) + if neighbour in visited: + continue + if neighbour in border or neighbour in border_next: + continue + border_next[neighbour] = path + direction + border = border_next + + return None diff --git a/amazeing/maze_class/maze_pattern.py b/amazeing/maze_class/maze_pattern.py index ceaaa21..69ff2b6 100644 --- a/amazeing/maze_class/maze_pattern.py +++ b/amazeing/maze_class/maze_pattern.py @@ -88,7 +88,12 @@ class Pattern: normalized: Pattern = self.normalized() negative = normalized.flood_filled().mirrored() dims = normalized.dims() - slots = set(CellCoord(canvas - dims + 1).all_up_to()) + slots = set( + map( + lambda e: CellCoord(e + 1), + CellCoord(canvas - dims - 1).all_up_to(), + ) + ) for excluded in excluding: slots -= negative.offset(excluded).__cells if len(slots) == 0: diff --git a/amazeing/maze_class/maze_walls.py b/amazeing/maze_class/maze_walls.py index bc06080..ff63362 100644 --- a/amazeing/maze_class/maze_walls.py +++ b/amazeing/maze_class/maze_walls.py @@ -76,6 +76,10 @@ class Cardinal(Enum): def right(self) -> "Cardinal": return self.left().opposite() + @staticmethod + def all() -> list["Cardinal"]: + return [Cardinal.NORTH, Cardinal.SOUTH, Cardinal.EAST, Cardinal.WEST] + class WallCoord: def __init__(self, orientation: Orientation, a: int, b: int) -> None: @@ -161,11 +165,18 @@ class CellCoord(IVec2): return WallCoord(Orientation.HORIZONTAL, self.y, self.x) case Cardinal.SOUTH: return WallCoord(Orientation.HORIZONTAL, self.y + 1, self.x) - case Cardinal.EAST: - return WallCoord(Orientation.VERTICAL, self.x, self.y) case Cardinal.WEST: + return WallCoord(Orientation.VERTICAL, self.x, self.y) + case Cardinal.EAST: return WallCoord(Orientation.VERTICAL, self.x + 1, self.y) + def get_neighbour(self, cardinal: Cardinal) -> "CellCoord": + return next( + filter( + lambda e: e != self, self.get_wall(cardinal).neighbour_cells() + ) + ) + def tile_coords(self) -> IVec2: return IVec2(self.x * 2 + 1, self.y * 2 + 1) @@ -178,6 +189,4 @@ class CellCoord(IVec2): yield CellCoord(x, y) def neighbours_unchecked(self) -> Iterable["CellCoord"]: - return map( - self.offset, [IVec2(-1, 0), IVec2(1, 0), IVec2(0, -1), IVec2(0, 1)] - ) + return map(self.get_neighbour, Cardinal.all()) diff --git a/example.conf b/example.conf index 04227c4..c00a50a 100644 --- a/example.conf +++ b/example.conf @@ -1,7 +1,7 @@ WIDTH=20 HEIGHT=20 -ENTRY=2,5 -#EXIT=100,100 +ENTRY=5,5 +EXIT=10,10 OUTPUT_FILE=test PERFECT=False SEED=111 @@ -18,6 +18,7 @@ TILEMAP_BACKGROUND="{1000,1000,1000:0,0,0}## " TILEMAP_BACKGROUND="{1000,1000,1000:0,0,0}###### " TILEMAP_BACKGROUND="{1000,1000,1000:0,0,0} ## " TILEMAP_BACKGROUND="{1000,1000,1000:0,0,0}## ## " + #MAZE_PATTERN=" # # " #MAZE_PATTERN=" # # " #MAZE_PATTERN=" # " @@ -26,11 +27,11 @@ TILEMAP_BACKGROUND="{1000,1000,1000:0,0,0}## ## " #MAZE_PATTERN=" " #MAZE_PATTERN="# # #" #MAZE_PATTERN=" ## ## " -MAZE_PATTERN="#######" -MAZE_PATTERN="# # # #" +MAZE_PATTERN=" ### " +MAZE_PATTERN=" # # # " MAZE_PATTERN="# # #" MAZE_PATTERN="# #" -MAZE_PATTERN="## ####" -MAZE_PATTERN="# #" +MAZE_PATTERN="## # " MAZE_PATTERN="# # #" -MAZE_PATTERN="#######" +MAZE_PATTERN=" # # " +MAZE_PATTERN=" ### "