#!/usr/bin/env python3 """Mint `scout-arena.oramap` — a larger open arena for the hard tier of action-sequenced-execution (and any scenario wanting real fog scouting across dispersed enemy bases). rush-hour-arena is 128x40 (124x36 playable) — too cramped for multiple dispersed enemy bases discovered by scouting. scout-arena is 176x80 (168x72 playable, ~3.3x the area) so several enemy bases can sit far apart in fog and a coordinate-blind agent must genuinely scout to find its ordered waypoints. Byte-format identical to tools/build_rush_hour_map.py in the training repo (map.bin v2 column-major, miniYAML map.yaml, raw map.png terrain) so the Rust engine's generic .oramap loader (task #12) parses it like any shipped map. Written into the training maps dir so the bench's resolve_map_path() finds it by logical id, exactly like rush-hour-arena. Usage: python scripts/build_scout_arena_map.py """ import io import os import struct import zipfile from pathlib import Path WIDTH = 176 HEIGHT = 80 BOUNDS_X = 4 BOUNDS_Y = 4 PLAY_W = WIDTH - 2 * BOUNDS_X # 168 PLAY_H = HEIGHT - 2 * BOUNDS_Y # 72 CLEAR = 255 # passable grass WATER = 1 # impassable water # Four corner spawn references (mpspawn) — gives scenarios up to 4 # dispersed staging corners and seed-driven spawn variation. SPAWNS = [(8, 8), (WIDTH - 9, 8), (8, HEIGHT - 9), (WIDTH - 9, HEIGHT - 9)] OUT_DIRS = [ Path.home() / "Projects/OpenRA-RL-Training/scenarios/maps", Path.home() / "Projects/openra-rl/maps", ] def build_terrain(): """Open grass interior with a water cordon (matches rush-hour's BOUNDS_X/Y so the playable rect is exactly PLAY_W x PLAY_H).""" grid = [[CLEAR] * WIDTH for _ in range(HEIGHT)] for y in range(HEIGHT): for x in range(WIDTH): if ( x < BOUNDS_X or x >= WIDTH - BOUNDS_X or y < BOUNDS_Y or y >= HEIGHT - BOUNDS_Y ): grid[y][x] = WATER return grid def create_map_bin(grid): height = len(grid) width = len(grid[0]) buf = bytearray() buf.append(2) # format version buf.extend(struct.pack("