Wax seeps fix the economy flatline the arena telemetry exposed: both bots hit cash=0/stored=0 from tick 6250 with no way to recover. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
69 lines
2.6 KiB
Python
69 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Place a neutral `waxseed` actor at the centre of every wax blob on every map.
|
|
|
|
Reads the resource plane straight out of each map.bin, finds blob centroids by
|
|
flood fill, and appends the actors to map.yaml. Idempotent: strips previously
|
|
placed waxseed entries first.
|
|
"""
|
|
import os, re, struct, glob
|
|
|
|
MAPS = glob.glob(os.path.join(os.path.dirname(__file__), '..', 'mods', 'vinylgod', 'maps', '*'))
|
|
|
|
|
|
def resource_cells(path):
|
|
d = open(path, 'rb').read()
|
|
fmt, w, h = d[0], *struct.unpack_from('<HH', d, 1)
|
|
tiles_off, heights_off, res_off = struct.unpack_from('<III', d, 5)
|
|
assert fmt == 2 and heights_off == 0, path
|
|
cells = set()
|
|
for x in range(w):
|
|
for y in range(h):
|
|
if d[res_off + 2 * (x * h + y)] != 0:
|
|
cells.add((x, y))
|
|
return cells
|
|
|
|
|
|
def blobs(cells):
|
|
"""Flood-fill into connected blobs, return list of (cx, cy)."""
|
|
seen, out = set(), []
|
|
for start in sorted(cells):
|
|
if start in seen:
|
|
continue
|
|
stack, blob = [start], []
|
|
seen.add(start)
|
|
while stack:
|
|
x, y = stack.pop()
|
|
blob.append((x, y))
|
|
for n in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
|
|
if n in cells and n not in seen:
|
|
seen.add(n)
|
|
stack.append(n)
|
|
if len(blob) >= 6: # ignore specks
|
|
out.append((round(sum(p[0] for p in blob) / len(blob)),
|
|
round(sum(p[1] for p in blob) / len(blob))))
|
|
return out
|
|
|
|
|
|
for mapdir in sorted(MAPS):
|
|
my, mb = os.path.join(mapdir, 'map.yaml'), os.path.join(mapdir, 'map.bin')
|
|
if not (os.path.exists(my) and os.path.exists(mb)):
|
|
continue
|
|
centres = blobs(resource_cells(mb))
|
|
s = open(my).read()
|
|
s = re.sub(r'\n\twaxseed\d+: waxseed\n\t\tOwner: Neutral\n\t\tLocation: \d+,\d+', '', s)
|
|
if 'Actors:' not in s:
|
|
s = s.rstrip() + '\n\nActors:\n'
|
|
block = ''.join(f'\n\twaxseed{i}: waxseed\n\t\tOwner: Neutral\n\t\tLocation: {x},{y}'
|
|
for i, (x, y) in enumerate(centres))
|
|
# append to the Actors section (it is the last block in our generated maps)
|
|
head, _, tail = s.partition('Actors:')
|
|
lines = tail.split('\n')
|
|
cut = len(lines)
|
|
for i, ln in enumerate(lines):
|
|
if ln and not ln.startswith('\t') and i > 0: # next top-level key
|
|
cut = i
|
|
break
|
|
tail = '\n'.join(lines[:cut]).rstrip() + block + '\n' + '\n'.join(lines[cut:])
|
|
open(my, 'w').write(head + 'Actors:' + tail)
|
|
print(f'{os.path.basename(mapdir)}: {len(centres)} seep(s) at {centres}')
|