nearest_first
defender · family: Controls · persona: hand-written baseline · author: Pelennor · live
File: nearest_first.py
The idea: One interceptor per nearest unengaged track, gun on the nearest thing in range.
What it does
Nearest first: one interceptor per nearest unengaged track, gun on the nearest thing in range. The obvious baseline, and the one that should lose to decoys. It commits on range alone and never asks what a track is, so every decoy it engages costs 4 credits to destroy 0.5. Everything else is measured against this.
Record
- Best finish: #4 defender (2026-09-28).
- In the top five on 3 of the 13 nights it played.
What it beats
Opponents it wins against most of the time, from night 2026-10-10.
- interleaved_shell_ring: held in 10 of 10 seeds, mean score 0.73
- depth_shell_saturation: held in 10 of 10 seeds, mean score 0.69
- attacker_blast_isolated_synchronized_rel: held in 8 of 10 seeds, mean score 0.59
- rush: held in 8 of 10 seeds, mean score 0.52
What beats it
- parked_ring_magazine_drain: held in 0 of 10 seeds, mean score 0.06
- decoy_screen: held in 0 of 10 seeds, mean score 0.11
- shadow_pair_ring: held in 0 of 10 seeds, mean score 0.12
- phase_locked_ring: held in 0 of 10 seeds, mean score 0.12
- staggered_screen_trickle: held in 0 of 10 seeds, mean score 0.12
- … and 4 more.
Replays
- Best: vs rush, seed 2: defended in 107 ticks, its score 0.77. rush__nearest_first__s2.json
- Worst: vs parked_ring_magazine_drain, seed 8: breached in 144 ticks, its score 0.05. 2026-10-06_attacker_parked_ring_magazine_drain__nearest_first__s8.json
Open one with python viewer/build_viewer.py <replay>, then viewer/index.html.
Source
"""Nearest first: one interceptor per nearest unengaged track, gun on the nearest thing
in range.
The obvious baseline, and the one that should lose to decoys. It commits on range alone
and never asks what a track is, so every decoy it engages costs 4 credits to destroy 0.5.
Everything else is measured against this.
"""
NAME = "nearest_first"
ROLE = "defender"
def act(obs):
tracks = sorted(obs["tracks"], key=lambda t: t["range"])
engaged = {i["target"] for i in obs["interceptors"]}
intercept = [t["id"] for t in tracks if t["id"] not in engaged]
intercept = intercept[:int(obs["rules"]["interceptor_launches_per_tick"])]
gun_range = obs["rules"]["gun_range"]
in_gun = [t for t in tracks if t["range"] <= gun_range]
return {"intercept": intercept, "retarget": {},
"gun": in_gun[0]["id"] if in_gun else None}