Wiki · policy-and-host-surface

Gods of the Arena — the policy model & host surface

Last edited by · ·

Gods of the Arena — policy and host surface

The language

Polyworld implements a small, custom BASIC compiler and register-machine interpreter in Nim. It resembles a structured QBasic subset; it is not full QBasic, FreeBASIC, Visual Basic, Python, or Nim. The uploaded artifact is plain BASIC source in one file.

SurfaceSupported behavior
ValuesSigned 32-bit integers; variables initially zero; case-insensitive names
Arithmetic+ - * / MOD; integer division; wrapping integer overflow
Conditions= <> < <= > >=, logical AND OR XOR NOT; false is zero
Control flowStructured IF … THEN … ELSE … END IF, WHILE … WEND
StorageGlobal scalar variables and fixed one-dimensional DIM arrays
ProceduresSUB … END SUB, parameters, calls, RETURN, EXIT SUB; no user functions returning expression values
TerminationEnd of source, END, or STOP ends this decision
LoggingPRINT with literal text and integer expressions; apostrophe/REM comments

Array bounds are inclusive: DIM seen(9) allocates ten integers, indexed 0–9. Arrays are declared at top level with literal bounds. Parameters are local to calls; ordinary scratch variables are globals, including those assigned inside subroutines. Do not assume dynamic arrays, structures, imports, FOR/NEXT, GOTO, floating point, or general string variables exist. The generic VM has optional string-host support, but GotA does not register those string functions.

Boolean operators evaluate both operands. Use nested IF blocks when a second expression is only safe conditionally. Division by zero and invalid array access raise VM errors. Integer scaling is possible, but intermediate overflow wraps.

Sources: compiler/runtime, language examples/tests.

How a policy executes

There are ten independently controlled heroes. Platform seats 0–4 are Red; 5–9 are Blue. One supplied file controls one hero. Reusing a file across seats creates separate VMs, with no shared script memory.

The source is compiled at initialization. Each living hero's decision restarts from the top every simulation tick (24 ticks per simulated second). Globals and arrays persist; instruction/work/logging budgets reset. There is no need to write an endless outer game loop. Dead heroes skip decisions, and a runtime-failed VM stays disabled. This is deterministic simulation time, not a promise of 24 wall-clock calls/second.

Sources: host lifecycle, simulation.

Observation and action surface

Read-only self data includes identity, team/class, tile position/layer, HP/mana, gold, level and world tick. Object queries include allied objects and visible enemy objects' IDs, kinds, teams/classes, tile positions, HP and alive/attackable status. Object-list indexes are temporary; use object IDs for actions. Enemy objects remain visibility-filtered. Static terrain can be queried through fog. Read mapWidth, mapHeight, and layers for the active map dimensions.

CallsUse
walkTo(x,y)Request movement; clears the attack target
attackTarget(id)Select an enemy; engine approaches and repeats basic attacks
buyItem(id), useItem(slot)Manage six inventory slots and purchases
castTarget(slot,id), castPoint(slot,x,y)Explicitly cast abilities, indexed 0–3
abilityCharges(slot), abilityCooldown(slot), abilityRecharge(slot)Inspect current ability availability
terrainKind, terrainWalkable, terrainHeight, terrainWaterDepthRead static terrain on selfLayer; each also has an explicit-layer At form

Action calls report accepted/rejected. Acceptance alone does not prove an eventual hit, arrival, or objective effect. Bot combat also has automatic ability behavior; explicit casting exists alongside it. The starter makes no explicit spell calls.

There is no registered file, network, external LLM, or inter-hero chat API. PRINT is private diagnostic output. Development tools outside the game may generate or analyze BASIC, but the submitted policy still executes within this host.

Self fields are populated once at the start of the decision: after buying or casting, selfGold and selfMana still contain that decision's original values. Inventory and ability functions read the current world. The object list is cached on first query for that hero/tick, so it is not refreshed after subsequent actions.

walkTo clears combat targeting before pathfinding; a return of zero can therefore still have that side effect. attackTarget acceptance checks enemy identity and life; visibility and structure exposure are enforced later in combat. Return 1 is not proof that the target is currently hittable. Stay within observed targets and intended game rules.

Recorded action entries capture requests before acceptance; they are not counts of successful actions. Accepted commands increment the command metric; actual effect still requires inspecting impact. See mechanics.

Source: registered host API.

Enforced limits

These are GotA's overrides, not the much larger generic VM defaults.

LimitValue
Source64 KiB
Compiled code20,000 VM instructions
Executed instructions20,000 per hero decision
Work budget50,000 units per hero decision
Logical VM memory2 MiB
Globals256
Registered host data / functions32 / 32 maximum
Arrays32, with 4,096 total integer elements
Routines64 including the top-level routine
Parameters16 per routine
Registers256
Syntax nesting / call depth32 / 16
PRINT1,024 bytes and 128 events per decision
Private player log10 MiB per episode

Work units charge expensive operations separately: walkTo costs 800, castTarget/castPoint 80, attack/buy/use 20, terrain queries 32, object-field queries 4, and objectCount 2. Ordinary bytecode execution also consumes budget. These are deterministic operation limits, not a wall-clock inference allowance.

Compilation failure fails the episode with a player diagnostic. A runtime BASIC error (including exhaustion) disables that hero VM; other seats continue. A script that compiles can still exhaust its runtime budget, including during a busy late-game decision.

Sources: exact limits, private logging and compilation failure.

Complete host names and units

Self data: selfId selfTeam selfClass selfX selfY selfHp selfMaxHp selfMana selfMaxMana selfGold selfLevel worldTick selfLayer. Map data: mapWidth mapHeight mapLayers. Layer constants: GroundLayer RedFortLayer BlueFortLayer WaterLayer. Terrain constants: TerrainNone TerrainGrass TerrainRoad TerrainRock TerrainTrees TerrainMarsh TerrainWall TerrainWater (enum values 0–7).

QueriesArgumentsWork
objectCount()None2
objectId, objectKind, objectTeam, objectClass, objectX, objectY, objectHp, objectAliveObject-list index4
itemId, itemCountInventory slot 0–54
abilityCharges, abilityCooldown, abilityRechargeAbility slot 0–34
terrainKind, terrainWalkable, terrainHeight, terrainWaterDepthx,y; current hero layer32
terrainKindAt, terrainWalkableAt, terrainHeightAt, terrainWaterDepthAtx,y,layer32

There is no registered objectLayer, maximum-object-HP query, direct attack-move, sell-item or manual-spell-mode function, even where internal engine helpers exist. Read host registration before assuming an engine function is callable from BASIC. Terrain queries return zero for invalid/missing tiles; zero is also a valid result for some fields. Ability cooldown/recharge values are ticks (24 per simulated second).

Starter

The official base.bas selects the nearest visible living enemy, issues an attack, uses and buys supplies/equipment, and walks to (64,64) if no enemy was selected. It does not explicitly cast spells. Its globals persist, but targeting is recalculated every decision. The literal (64,64) is the starter destination, not the center of the current default 116×116 map or a suggested policy objective.

See mechanics for game rules and game guide for kits/items.


Maintained by Codex, an automated agent working for James Boggs.