You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fromcambcimport*classPlayer:
def__init__(self):
pass# per-unit state; persists across rounds, not shared between unitsdefrun(self, c: Controller) ->None:
pass# called once per round per unit
One Player instance per unit — state does not cross unit boundaries
Use c.get_entity_type() to branch on what kind of unit you are
Use markers for inter-unit communication
2ms CPU time limit per unit per round (+ 5% refilling buffer). If exceeded, execution is interrupted and run() is called fresh next round — the bot does not resume mid-function
1 GB memory limit per bot process. Only Python standard library modules available — no numpy, scipy, etc.
Units take their turns in spawn order each round. Resource distribution happens after all units have moved
Debugging
print("msg") is captured by the engine and visible per-unit in the replay visualiser
import sys; print("msg", file=sys.stderr) prints to console in real time during local runs
c.draw_indicator_line() and c.draw_indicator_dot() draw overlays saved to the replay
Use cambc run for local testing (no time limits enforced). Use cambc test-run to test on the same AWS Graviton3 hardware as ladder matches
2. Controller API
The Controller (c) is the sole interface to the game engine. Passed to run() every round.
Unit Info
Method
Returns
Description
get_team(id=None)
Team
Team of entity id, or this unit
get_position(id=None)
Position
Position of entity id, or this unit
get_id()
int
This unit's entity id
get_action_cooldown()
int
Current action cooldown; actions require 0
get_move_cooldown()
int
Current move cooldown; movement requires 0
get_hp(id=None)
int
Current HP of entity id, or this unit
get_max_hp(id=None)
int
Max HP of entity id, or this unit
get_entity_type(id=None)
EntityType
EntityType of entity id, or this unit
get_direction(id=None)
Direction
Facing direction of a conveyor/splitter/armoured conveyor/turret. Raises GameError if entity has no direction
get_vision_radius_sq(id=None)
int
Vision radius² of entity id, or this unit
Turret Info
Method
Returns
Description
get_ammo_amount()
int
Amount of ammo this turret holds
get_ammo_type()
ResourceType | None
Resource type loaded as ammo, or None if empty
get_gunner_target()
Position | None
Closest non-empty tile in gunner's facing direction (including markers), or None. Markers are targetable but do not shield occupied tiles behind them — gunners shoot past them
Building Info
Method
Returns
Description
get_bridge_target(id: int)
Position
Output target of a bridge. Raises GameError if not a bridge
get_stored_resource(id=None)
ResourceType | None
Resource in a conveyor/splitter/armoured conveyor/bridge/foundry. Raises GameError if entity has no storage
Tile Queries
Method
Returns
Description
get_tile_env(pos)
Environment
Environment type at pos (empty, wall, ore)
get_tile_building_id(pos)
int | None
Id of building at pos, or None
get_tile_builder_bot_id(pos)
int | None
Id of builder bot at pos, or None
is_tile_empty(pos)
bool
True if no building and not a wall
is_tile_passable(pos)
bool
True if a friendly builder bot could stand here (conveyor, road, or allied core; no other bot)
is_in_vision(pos)
bool
True if pos is within this unit's vision radius
Nearby Queries
dist_sq defaults to vision radius; must not exceed it.
Method
Returns
Description
get_nearby_tiles(dist_sq=None)
list[Position]
All in-bounds positions within dist_sq
get_nearby_entities(dist_sq=None)
list[int]
Ids of all entities within dist_sq
get_nearby_buildings(dist_sq=None)
list[int]
Ids of all buildings within dist_sq
get_nearby_units(dist_sq=None)
list[int]
Ids of all units within dist_sq
Map & Game State
Method
Returns
Description
get_map_width()
int
Map width in tiles
get_map_height()
int
Map height in tiles
get_current_round()
int
Current round number (starts at 1)
get_global_resources()
tuple[int, int]
(titanium, axionite) in team's resource pool
get_scale_percent()
float
Current cost scale as % (100.0 = base cost)
get_unit_count()
int
Number of living units on your team, including the core
All build actions require action cooldown == 0 and sufficient resources. can_build_* returns bool; build_* returns the new entity's int id, or raises GameError if not legal. can_build_* for units also accounts for the global unit cap.
Directional — take (pos: Position, direction: Direction):
Heal all friendly entities on the bot's own tile by 4 HP. If a building and a bot share the tile, both are healed. Costs one action cooldown and 1 Ti. Position must equal this bot's current position
can_heal(position)
bool
True if heal is legal this round. Requires cooldown == 0, sufficient titanium, and at least one damaged friendly entity on the tile. Position must equal this bot's current position
attack(position)
None
Builder bot only. Deal 2 damage to the building on the bot's current tile. Costs one action cooldown and 2 Ti. Uses fire() in the API — see Combat section
can_attack(position)
bool
True if builder bot attack is legal this round
destroy(building_pos)
None
Destroy an allied building. Does not cost action cooldown
can_destroy(building_pos)
bool
True if destroy is legal
self_destruct()
None
Destroy this unit. Builder bots deal no damage. Execution terminates immediately — no code after this call runs
resign()
None
Forfeit the game immediately. Destroys your core. Execution terminates immediately — no code after this call runs
Markers
No action cooldown cost. Max one placement per round. Used for inter-unit communication.
Method
Returns
Description
place_marker(position, value: int)
None
Place marker with u32 value
can_place_marker(position)
bool
True if placement is legal
get_marker_value(id: int)
int
u32 value stored in friendly marker
Combat
Method
Returns
Description
fire(target)
None
Fire this turret at target. Also used for the builder bot's own-tile attack (2 Ti, 2 damage to building on current tile). Use launch() for launchers
can_fire(target)
bool
True if fire/attack is legal this round
launch(bot_pos, target)
None
Pick up builder bot at bot_pos and throw to target
can_launch(bot_pos, target)
bool
True if launch is legal
Core
Method
Returns
Description
spawn_builder(position)
int
Spawn a builder bot on one of the 9 core tiles. Costs one action cooldown. Returns new entity id. Requires room under the global unit cap
can_spawn(position)
bool
True if spawn is legal this round, including unit-cap check
Global unit cap per team (includes the core, so max 49 additional units)
MAP_MIN_SIZE
20
Minimum map dimension (both width and height)
MAP_MAX_SIZE
50
Maximum map dimension (both width and height)
Radii (squared)
Constant
Value
Description
ACTION_RADIUS_SQ
2
Default action radius
CORE_ACTION_RADIUS_SQ
8
Core action radius (from centre)
CORE_SPAWNING_RADIUS_SQ
2
Core spawning radius
CORE_VISION_RADIUS_SQ
36
Core vision
BUILDER_BOT_VISION_RADIUS_SQ
20
Builder bot vision
GUNNER_VISION_RADIUS_SQ
13
Gunner vision
SENTINEL_VISION_RADIUS_SQ
32
Sentinel vision
BREACH_VISION_RADIUS_SQ
13
Breach vision
BREACH_ATTACK_RADIUS_SQ
5
Breach attack cone
LAUNCHER_VISION_RADIUS_SQ
26
Launcher vision + throw range
BRIDGE_TARGET_RADIUS_SQ
9
Max bridge output distance²
Base Costs (titanium, axionite)
Constant
Value
BUILDER_BOT_BASE_COST
(50, 0)
CONVEYOR_BASE_COST
(3, 0)
SPLITTER_BASE_COST
(6, 0)
BRIDGE_BASE_COST
(20, 0)
ARMOURED_CONVEYOR_BASE_COST
(10, 5)
HARVESTER_BASE_COST
(80, 0)
ROAD_BASE_COST
(1, 0)
BARRIER_BASE_COST
(3, 0)
FOUNDRY_BASE_COST
(120, 0)
GUNNER_BASE_COST
(10, 0)
SENTINEL_BASE_COST
(15, 0)
BREACH_BASE_COST
(30, 10)
LAUNCHER_BASE_COST
(20, 0)
Max HP
Constant
Value
CORE_MAX_HP
500
BUILDER_BOT_MAX_HP
30
CONVEYOR_MAX_HP
20
SPLITTER_MAX_HP
20
BRIDGE_MAX_HP
20
ARMOURED_CONVEYOR_MAX_HP
50
HARVESTER_MAX_HP
30
ROAD_MAX_HP
10
BARRIER_MAX_HP
30
FOUNDRY_MAX_HP
50
MARKER_MAX_HP
1
GUNNER_MAX_HP
40
SENTINEL_MAX_HP
30
BREACH_MAX_HP
60
LAUNCHER_MAX_HP
30
Combat Constants
Constant
Value
Description
BUILDER_BOT_SELF_DESTRUCT_DAMAGE
0
Self-destruct no longer deals damage
BUILDER_BOT_ATTACK_DAMAGE
2
Damage dealt by builder bot attack (own tile only)
BUILDER_BOT_ATTACK_COST
2
Titanium cost per builder bot attack
HEAL_AMOUNT
4
HP restored per heal action
HEAL_COST
1
Titanium cost per heal action
GUNNER_DAMAGE
10
Damage per shot
GUNNER_FIRE_COOLDOWN
1
Turns between shots
GUNNER_AMMO_COST
2
Resources per shot
SENTINEL_DAMAGE
10
Damage per shot
SENTINEL_FIRE_COOLDOWN
2
Turns between shots
SENTINEL_AMMO_COST
5
Resources per shot
SENTINEL_AXIONITE_STUN
2
Rounds stunned when hit by sentinel axionite ammo
BREACH_DAMAGE
40
Direct hit damage
BREACH_SPLASH_DAMAGE
20
Splash damage
BREACH_FIRE_COOLDOWN
1
Turns between shots
BREACH_AMMO_COST
5
Refined axionite per shot
LAUNCHER_FIRE_COOLDOWN
1
Turns between throws
Scaling Contributions
Entity
Scaling Added
Builder Bot
+20%
Sentinel
+20%
Bridge
+5%
All others
unchanged
5. Entity Quick Reference
Units
Entity
HP
Cost (Ti, Ax)
Vision R²
Notes
Core
500
—
36
Spawns builder bots; loss = game over. Counts toward the 50-unit cap (so max 49 other units)
Builder Bot
30
(50, 0)
20
Only mobile unit; builds all structures. Can attack own tile (2 Ti, 2 dmg). Heal costs 1 Ti for 4 HP. Self-destruct deals no damage. Adds +20% scaling. Global cap: 50 units/team
Turrets
Entity
HP
Cost (Ti, Ax)
Vision R²
Damage
Cooldown
Ammo Cost
Notes
Gunner
40
(10, 0)
13
10
1
2
Fires in facing direction; shoots past markers
Sentinel
30
(15, 0)
32
10
2
5
High vision; axionite ammo stuns for 2 rounds. Adds +20% scaling
Breach
60
(30, 10)
13
40 / 20 splash
1
5 refined axionite
Splash damage; vision now matches attack range
Launcher
30
(20, 0)
26
—
1
—
Throws builder bots
Infrastructure
Entity
HP
Cost (Ti, Ax)
Directional
Notes
Conveyor
20
(3, 0)
Yes
Moves resources along network
Splitter
20
(6, 0)
Yes
Splits resource flow
Armoured Conveyor
50
(10, 5)
Yes
Higher HP; harder to destroy
Bridge
20
(20, 0)
No (target)
Teleports resources; target within dist²=9. Adds +5% scaling per bridge
Harvester
30
(80, 0)
No
Must be placed on an ore tile
Foundry
50
(120, 0)
No
Refines raw axionite → refined axionite. Required — raw axionite delivered directly to core or turrets is destroyed
Road
10
(1, 0)
No
Passable tile for builder bots
Barrier
30
(3, 0)
No
Blocks movement
Marker
1
—
No
Stores u32; used for inter-unit comms. Gunners can target markers but fire through them to hit occupied tiles behind
Resources
Resource
Description
Titanium
Primary currency; mined from ORE_TITANIUM tiles via harvesters
Raw Axionite
Mined from ORE_AXIONITE tiles; must be processed by a Foundry. Delivering raw axionite directly to the core or turrets destroys it
Refined Axionite
Output of Foundry; required for armoured conveyors, breach ammo, and advanced builds
6. Match & Ladder Rules
Match Format
Each ladder match = 5 games, each on a different map with a different seed. The team that wins more games wins the match.
Win Conditions per Game
Priority
Condition
Description
1
Core destroyed
One team's core reaches 0 HP — opponent wins immediately
2
Refined axionite delivered
After 2000 rounds: most total refined axionite delivered to core
3
Titanium delivered
Total titanium delivered to core
4
Harvesters alive
Number of harvesters currently alive
5
Axionite stored
Total axionite currently in storage
6
Titanium stored
Total titanium currently in storage
7
Coinflip
Random tiebreaker
Ladder & Rating
Ranked by Glicko-2; new teams seeded at 1500
Scheduler runs every 10 minutes: pairs each team with a similarly-rated opponent (greedy nearest-rating with jitter), avoids rematches from the last hour
Ratings use fractional scoring — a 5-0 win counts more than a 3-2 win