diff --git a/main.py b/main.py new file mode 100644 index 0000000..1f8cbd2 --- /dev/null +++ b/main.py @@ -0,0 +1,31 @@ +from emis_funky_funktions import * + +from sys import argv +from operator import eq + +from a_star import pathfind +from read_in import load_world_from_paths +from world import Point, World + +def pathfind_world(world: World, start: Point, end: Point) -> Option[Tuple[List[Point], int]]: + "Given a `World` with a start and finish point embedded, find the best route" + return pathfind( + world.neighbors, + p(world.heuristic, end), + p(eq, end), + start + ) + +def main(terrain_path: str, elevation_path: str, path_output: str, image_output: str): + print( + pathfind_world( + unwrap_r( + load_world_from_paths(terrain_path, elevation_path) + ), + Point(200, 475), + Point(200, 200) + ) + ) + +if __name__ == '__main__': + main(*argv[1:]) \ No newline at end of file diff --git a/read_in.py b/read_in.py index 09c223f..f65b4a0 100644 --- a/read_in.py +++ b/read_in.py @@ -1,6 +1,6 @@ from emis_funky_funktions import * -from shared import Terrain +from world import Terrain, World from PIL import Image @@ -202,7 +202,7 @@ def load_elevations(path: str) -> Result[Iterator[int], UnparsableElevation]: with open(path) as file: return read_elevations(file) -def load_world_from_paths(map_path: str, elevation_path: str) -> Result[Iterable[Tuple[Terrain, int]], UnparsableElevation | UnrecognizedColor]: +def load_world_from_paths(map_path: str, elevation_path: str) -> Result[World, UnparsableElevation | UnrecognizedColor]: """ Read world information (terrain and elevation) from file paths. @@ -214,7 +214,7 @@ def load_world_from_paths(map_path: str, elevation_path: str) -> Result[Iterable return bind_res( lambda terrain_data: map_res( - p(zip, terrain_data), + lambda elevation_data: World((*zip(terrain_data, elevation_data),)), load_elevations(elevation_path) ), load_image(map_path) diff --git a/world.py b/world.py index 2ae17d4..08e58de 100644 --- a/world.py +++ b/world.py @@ -62,12 +62,6 @@ class World: the elevation in millimeters at that point. """ - start: Point - "Where routing should start" - - finish: Point - "Where routing should finish" - width: int "The number of pixels wide the map is" @@ -82,15 +76,11 @@ class World: def __init__(self, tiles: Sequence[Tuple[Terrain, int]], - start: Point, - finish: Point, width: int = 395, lon_scale: int = 10_290, lat_scale: int = 7_550 ): self.tiles = tiles - self.start = start - self.finish = finish self.width = width self.lon_scale = lon_scale self.lat_scale = lat_scale @@ -107,7 +97,7 @@ class World: This does not take into account the presence, value, or elevation of tiles represented on these points. - >>> world = World([], None, None, lon_scale=10_290, lat_scale=7_550) + >>> world = World([], lon_scale=10_290, lat_scale=7_550) >>> world._adjacency(Point(13, 12)) #doctest: +NORMALIZE_WHITESPACE [((12, 11), 12762), ((13, 11), 7550), @@ -141,7 +131,7 @@ class World: Points do not need to be adjacent! - >>> world = World([(Terrain.BRUSH, 1_000), (Terrain.BRUSH, 1_100)], None, None) + >>> world = World([(Terrain.BRUSH, 1_000), (Terrain.BRUSH, 1_100)]) >>> world.elevation_difference(Point(0, 0), Point(1, 0)) 100 """ @@ -175,8 +165,6 @@ class World: ... [ (Terrain.OPEN_LAND, 1_000), (Terrain.OOB, 950) ... , (Terrain.ROUGH_MEADOW, 1_080), (Terrain.EASY_FOREST, 1_010) ... ], - ... None, # We're not interested in a start state - ... None, # nor an end state ... width = 2, # Our simple world is only two tiles wide ... lon_scale = 500, # Pick an easy number for example ... lat_scale = 400 # and remember that these are in millimeters! @@ -261,9 +249,9 @@ class World: and self[adj_point][0] != Terrain.OOB ] - def heuristic(self, p: Point) -> int: + def heuristic(self, a: Point, b: Point) -> int: """ - Estimate the time it will take to travel between a point and the finish + Estimate the time it will take to travel between two points The following assumptions are made to speed up the process, at the cost of accuracy: @@ -279,14 +267,14 @@ class World: access world data at all, and the results of the computation depend exclusively on the start point, the finish point, and the longitudinal/latitudinal scales. - >>> world = World(None, None, Point(3, 5), lon_scale = 500, lat_scale = 400) - >>> world.heuristic(Point(0, 0)) + >>> world = World([], lon_scale = 500, lat_scale = 400) + >>> world.heuristic(Point(0, 0), Point(3, 5)) 1632000 """ # Taxicab distance in each direction - lon_tiles_raw = abs(p.x - self.finish.x) - lat_tiles_raw = abs(p.y - self.finish.y) + lon_tiles_raw = abs(a.x - b.x) + lat_tiles_raw = abs(a.y - b.y) # The number of moves necessary, allowing diagonal moves lon_moves_real = max(0, lon_tiles_raw - lat_tiles_raw) @@ -306,12 +294,6 @@ class World: return estimated_speed * total_flat_distance - def goal(self, p: Point) -> bool: - """ - Equivalent to `p == world.finish` - """ - return p == self.finish - if __name__ == '__main__': import doctest doctest.testmod() \ No newline at end of file