222 lines
6.8 KiB
Python
222 lines
6.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test Dijkstra Pathfinding Implementation
|
|
========================================
|
|
|
|
Demonstrates:
|
|
1. Computing Dijkstra distance map from a root position
|
|
2. Getting distances to any position
|
|
3. Finding paths from any position back to the root
|
|
4. Multi-target pathfinding (flee/approach scenarios)
|
|
"""
|
|
|
|
import mcrfpy
|
|
from mcrfpy import libtcod
|
|
import sys
|
|
|
|
def create_test_grid():
|
|
"""Create a test grid with obstacles"""
|
|
mcrfpy.createScene("dijkstra_test")
|
|
|
|
# Create grid
|
|
grid = mcrfpy.Grid(grid_x=20, grid_y=20)
|
|
|
|
# Initialize all cells as walkable
|
|
for y in range(grid.grid_y):
|
|
for x in range(grid.grid_x):
|
|
cell = grid.at(x, y)
|
|
cell.walkable = True
|
|
cell.transparent = True
|
|
cell.tilesprite = 46 # . period
|
|
cell.color = mcrfpy.Color(50, 50, 50)
|
|
|
|
# Create some walls to make pathfinding interesting
|
|
# Vertical wall
|
|
for y in range(5, 15):
|
|
cell = grid.at(10, y)
|
|
cell.walkable = False
|
|
cell.transparent = False
|
|
cell.tilesprite = 219 # Block
|
|
cell.color = mcrfpy.Color(100, 100, 100)
|
|
|
|
# Horizontal wall
|
|
for x in range(5, 15):
|
|
if x != 10: # Leave a gap
|
|
cell = grid.at(x, 10)
|
|
cell.walkable = False
|
|
cell.transparent = False
|
|
cell.tilesprite = 219
|
|
cell.color = mcrfpy.Color(100, 100, 100)
|
|
|
|
return grid
|
|
|
|
def test_basic_dijkstra():
|
|
"""Test basic Dijkstra functionality"""
|
|
print("\n=== Testing Basic Dijkstra ===")
|
|
|
|
grid = create_test_grid()
|
|
|
|
# Compute Dijkstra map from position (5, 5)
|
|
root_x, root_y = 5, 5
|
|
print(f"Computing Dijkstra map from root ({root_x}, {root_y})")
|
|
grid.compute_dijkstra(root_x, root_y)
|
|
|
|
# Test getting distances to various points
|
|
test_points = [
|
|
(5, 5), # Root position (should be 0)
|
|
(6, 5), # Adjacent (should be 1)
|
|
(7, 5), # Two steps away
|
|
(15, 15), # Far corner
|
|
(10, 10), # On a wall (should be unreachable)
|
|
]
|
|
|
|
print("\nDistances from root:")
|
|
for x, y in test_points:
|
|
distance = grid.get_dijkstra_distance(x, y)
|
|
if distance is None:
|
|
print(f" ({x:2}, {y:2}): UNREACHABLE")
|
|
else:
|
|
print(f" ({x:2}, {y:2}): {distance:.1f}")
|
|
|
|
# Test getting paths
|
|
print("\nPaths to root:")
|
|
for x, y in [(15, 5), (15, 15), (5, 15)]:
|
|
path = grid.get_dijkstra_path(x, y)
|
|
if path:
|
|
print(f" From ({x}, {y}): {len(path)} steps")
|
|
# Show first few steps
|
|
for i, (px, py) in enumerate(path[:3]):
|
|
print(f" Step {i+1}: ({px}, {py})")
|
|
if len(path) > 3:
|
|
print(f" ... {len(path)-3} more steps")
|
|
else:
|
|
print(f" From ({x}, {y}): No path found")
|
|
|
|
def test_libtcod_interface():
|
|
"""Test the libtcod module interface"""
|
|
print("\n=== Testing libtcod Interface ===")
|
|
|
|
grid = create_test_grid()
|
|
|
|
# Use libtcod functions
|
|
print("Using libtcod.dijkstra_* functions:")
|
|
|
|
# Create dijkstra context (returns grid)
|
|
dijkstra = libtcod.dijkstra_new(grid)
|
|
print(f"Created Dijkstra context: {type(dijkstra)}")
|
|
|
|
# Compute from a position
|
|
libtcod.dijkstra_compute(grid, 10, 2)
|
|
print("Computed Dijkstra map from (10, 2)")
|
|
|
|
# Get distance using libtcod
|
|
distance = libtcod.dijkstra_get_distance(grid, 10, 17)
|
|
print(f"Distance to (10, 17): {distance}")
|
|
|
|
# Get path using libtcod
|
|
path = libtcod.dijkstra_path_to(grid, 10, 17)
|
|
print(f"Path from (10, 17) to root: {len(path) if path else 0} steps")
|
|
|
|
def test_multi_target_scenario():
|
|
"""Test fleeing/approaching multiple targets"""
|
|
print("\n=== Testing Multi-Target Scenario ===")
|
|
|
|
grid = create_test_grid()
|
|
|
|
# Place three "threats" and compute their Dijkstra maps
|
|
threats = [(3, 3), (17, 3), (10, 17)]
|
|
|
|
print("Computing threat distances...")
|
|
threat_distances = []
|
|
|
|
for i, (tx, ty) in enumerate(threats):
|
|
# Mark threat position
|
|
cell = grid.at(tx, ty)
|
|
cell.tilesprite = 84 # T for threat
|
|
cell.color = mcrfpy.Color(255, 0, 0)
|
|
|
|
# Compute Dijkstra from this threat
|
|
grid.compute_dijkstra(tx, ty)
|
|
|
|
# Store distances for all cells
|
|
distances = {}
|
|
for y in range(grid.grid_y):
|
|
for x in range(grid.grid_x):
|
|
d = grid.get_dijkstra_distance(x, y)
|
|
if d is not None:
|
|
distances[(x, y)] = d
|
|
|
|
threat_distances.append(distances)
|
|
print(f" Threat {i+1} at ({tx}, {ty}): {len(distances)} reachable cells")
|
|
|
|
# Find safest position (farthest from all threats)
|
|
print("\nFinding safest position...")
|
|
best_pos = None
|
|
best_min_dist = 0
|
|
|
|
for y in range(grid.grid_y):
|
|
for x in range(grid.grid_x):
|
|
# Skip if not walkable
|
|
if not grid.at(x, y).walkable:
|
|
continue
|
|
|
|
# Get minimum distance to any threat
|
|
min_dist = float('inf')
|
|
for threat_dist in threat_distances:
|
|
if (x, y) in threat_dist:
|
|
min_dist = min(min_dist, threat_dist[(x, y)])
|
|
|
|
# Track best position
|
|
if min_dist > best_min_dist and min_dist != float('inf'):
|
|
best_min_dist = min_dist
|
|
best_pos = (x, y)
|
|
|
|
if best_pos:
|
|
print(f"Safest position: {best_pos} (min distance to threats: {best_min_dist:.1f})")
|
|
# Mark safe position
|
|
cell = grid.at(best_pos[0], best_pos[1])
|
|
cell.tilesprite = 83 # S for safe
|
|
cell.color = mcrfpy.Color(0, 255, 0)
|
|
|
|
def run_test(runtime):
|
|
"""Timer callback to run tests after scene loads"""
|
|
test_basic_dijkstra()
|
|
test_libtcod_interface()
|
|
test_multi_target_scenario()
|
|
|
|
print("\n=== Dijkstra Implementation Test Complete ===")
|
|
print("✓ Basic Dijkstra computation works")
|
|
print("✓ Distance queries work")
|
|
print("✓ Path finding works")
|
|
print("✓ libtcod interface works")
|
|
print("✓ Multi-target scenarios work")
|
|
|
|
# Take screenshot
|
|
try:
|
|
from mcrfpy import automation
|
|
automation.screenshot("dijkstra_test.png")
|
|
print("\nScreenshot saved: dijkstra_test.png")
|
|
except:
|
|
pass
|
|
|
|
sys.exit(0)
|
|
|
|
# Main execution
|
|
print("McRogueFace Dijkstra Pathfinding Test")
|
|
print("=====================================")
|
|
|
|
# Set up scene
|
|
grid = create_test_grid()
|
|
ui = mcrfpy.sceneUI("dijkstra_test")
|
|
ui.append(grid)
|
|
|
|
# Add title
|
|
title = mcrfpy.Caption("Dijkstra Pathfinding Test", 10, 10)
|
|
title.fill_color = mcrfpy.Color(255, 255, 255)
|
|
ui.append(title)
|
|
|
|
# Set timer to run tests
|
|
mcrfpy.setTimer("test", run_test, 100)
|
|
|
|
# Show scene
|
|
mcrfpy.setScene("dijkstra_test") |