ai-code-battle/bots/nomad/grid.py
jedarden 2df70c8ae0 feat(bot): add Nomad bot (Python) — constant relocation archetype
Mobile archetype that never camps. Picks a target region every ~20 turns
(random corner, opposite side, or enemy core), migrates all units toward
it, briefly engages enemies on arrival, then relocates again.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 16:48:12 -04:00

64 lines
1.7 KiB
Python

"""Grid utility functions for AI Code Battle.
Provides toroidal distance calculations, neighbor enumeration,
and BFS pathfinding on a wrapping grid.
"""
from collections import deque
def toroidal_manhattan(r1, c1, r2, c2, cols, rows):
"""Manhattan distance with wrap-around on a toroidal grid."""
dr = abs(r1 - r2)
dc = abs(c1 - c2)
dr = min(dr, rows - dr)
dc = min(dc, cols - dc)
return dr + dc
def toroidal_chebyshev(r1, c1, r2, c2, cols, rows):
"""Chebyshev distance with wrap-around on a toroidal grid."""
dr = abs(r1 - r2)
dc = abs(c1 - c2)
dr = min(dr, rows - dr)
dc = min(dc, cols - dc)
return max(dr, dc)
def neighbors(row, col, rows, cols):
"""Return 8-directional neighbors with wrap-around."""
offsets = [(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1)]
return [((row + dr) % rows, (col + dc) % cols) for dr, dc in offsets]
def bfs(start, goal, passable, rows, cols):
"""BFS pathfinding on a toroidal grid.
Args:
start: (row, col) tuple
goal: (row, col) tuple
passable: callable(row, col) -> bool
rows, cols: grid dimensions
Returns:
List of (row, col) from start to goal (exclusive of start),
or None if no path exists.
"""
if start == goal:
return []
queue = deque([(start, [])])
visited = {start}
while queue:
(r, c), path = queue.popleft()
for nr, nc in neighbors(r, c, rows, cols):
if (nr, nc) == goal:
return path + [(nr, nc)]
if (nr, nc) not in visited and passable(nr, nc):
visited.add((nr, nc))
queue.append(((nr, nc), path + [(nr, nc)]))
return None