|
| 1 | +"""Tests for incremental pathfinding.""" |
| 2 | + |
| 3 | +import numpy as np |
| 4 | +import pytest |
| 5 | + |
| 6 | +import tcod.path |
| 7 | + |
| 8 | + |
| 9 | +@pytest.mark.parametrize("shape", [(4, 7), (3, 4, 7)]) |
| 10 | +@pytest.mark.parametrize("order", ["C", "F"]) |
| 11 | +@pytest.mark.parametrize("value", [-3, 0, 3]) |
| 12 | +def test_add_root_after_resolve(shape: tuple[int, ...], order: str, value: int) -> None: |
| 13 | + graph = tcod.path.CustomGraph(shape, order=order) |
| 14 | + cost = np.ones(shape, dtype=np.int8) |
| 15 | + for axis in range(len(shape)): |
| 16 | + for direction in (-1, 1): |
| 17 | + edge = [0] * len(shape) |
| 18 | + edge[axis] = direction |
| 19 | + graph.add_edge(tuple(edge), cost=cost) |
| 20 | + |
| 21 | + pathfinder = tcod.path.Pathfinder(graph) |
| 22 | + origin = (0,) * len(shape) |
| 23 | + new_root = tuple(size - 1 for size in shape) |
| 24 | + pathfinder.add_root(origin) |
| 25 | + pathfinder.resolve() |
| 26 | + assert tuple(pathfinder.path_from(new_root)[-1]) == origin |
| 27 | + |
| 28 | + pathfinder.add_root(new_root, value=value) |
| 29 | + pathfinder.resolve() |
| 30 | + np.testing.assert_array_equal(pathfinder.path_from(new_root), [new_root]) |
| 31 | + coordinates = np.indices(shape) |
| 32 | + expected = np.minimum( |
| 33 | + coordinates.sum(axis=0), |
| 34 | + sum(size - 1 - coordinates[axis] for axis, size in enumerate(shape)) + value, |
| 35 | + ) |
| 36 | + np.testing.assert_array_equal(pathfinder.distance, expected) |
| 37 | + for index in np.ndindex(shape): |
| 38 | + path = pathfinder.path_from(index) |
| 39 | + root = tuple(path[-1]) |
| 40 | + assert root in (origin, new_root) |
| 41 | + root_value = value if root == new_root else 0 |
| 42 | + assert len(path) - 1 + root_value == expected[index] |
| 43 | + |
| 44 | + |
| 45 | +@pytest.mark.parametrize("shape", [(4, 7), (3, 4, 7)]) |
| 46 | +@pytest.mark.parametrize("order", ["C", "F"]) |
| 47 | +@pytest.mark.parametrize("first_value", [-5, 3]) |
| 48 | +@pytest.mark.parametrize("relative_value", [-1, 0, 1, 20]) |
| 49 | +@pytest.mark.parametrize("partial", [False, True]) |
| 50 | +def test_add_root_preserves_better_distances( |
| 51 | + shape: tuple[int, ...], order: str, first_value: int, relative_value: int, partial: bool |
| 52 | +) -> None: |
| 53 | + graph = tcod.path.CustomGraph(shape, order=order) |
| 54 | + cost = np.ones(shape, dtype=np.int8) |
| 55 | + for axis in range(len(shape)): |
| 56 | + for direction in (-1, 1): |
| 57 | + edge = [0] * len(shape) |
| 58 | + edge[axis] = direction |
| 59 | + graph.add_edge(tuple(edge), cost=cost) |
| 60 | + pathfinder = tcod.path.Pathfinder(graph) |
| 61 | + origin = (0,) * len(shape) |
| 62 | + new_root = tuple(size // 2 for size in shape) |
| 63 | + pathfinder.add_root(origin, value=first_value) |
| 64 | + pathfinder.resolve(new_root if partial else None) |
| 65 | + old_path = pathfinder.path_from(new_root).copy() |
| 66 | + old_distances = pathfinder.distance.copy() |
| 67 | + old_traversal = pathfinder.traversal.copy() |
| 68 | + value = int(old_distances[new_root]) + relative_value |
| 69 | + pathfinder.add_root(new_root, value=value) |
| 70 | + if relative_value >= 0: |
| 71 | + np.testing.assert_array_equal(pathfinder.distance, old_distances) |
| 72 | + np.testing.assert_array_equal(pathfinder.traversal, old_traversal) |
| 73 | + np.testing.assert_array_equal(pathfinder.path_from(new_root), old_path) |
| 74 | + else: |
| 75 | + assert pathfinder.distance[new_root] == value |
| 76 | + np.testing.assert_array_equal(pathfinder.path_from(new_root), [new_root]) |
| 77 | + pathfinder.resolve() |
| 78 | + coordinates = np.indices(shape) |
| 79 | + expected = np.minimum( |
| 80 | + first_value + coordinates.sum(axis=0), |
| 81 | + value + sum(abs(new_root[axis] - coordinates[axis]) for axis in range(len(shape))), |
| 82 | + ) |
| 83 | + np.testing.assert_array_equal(pathfinder.distance, expected) |
0 commit comments