Basic pathfinding: Complete!

This commit is contained in:
Emi Simpson 2023-02-11 17:08:26 -05:00
parent 873d622d25
commit 4c95e515e0
Signed by: Emi
GPG Key ID: A12F2C2FFDC3D847
3 changed files with 42 additions and 29 deletions

31
main.py Normal file
View File

@ -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:])

View File

@ -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)

View File

@ -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()