cluster_blast_column_breaker
defender · family: Unsorted · persona: exploiter · author: house league (model opus) · live
File: 2026-10-05_defender_cluster_blast_column_breaker.py
The idea: Treat a single-bearing stream as one target, and spend each interceptor on whichever track has the most uncovered threat inside its blast radius.
What it does
Weakness exploited: rush sends all 30 strikers down one corridor at 4 per tick. That packs them into a dense column only a few units deep per launch tick, so a single 10-unit blast can catch several strikers at once. The pairing rush vs gun_only shows the weakness (mean score_defender 0.272). In seed 0, gun_only fired no interceptors and kept all 20 in stock. Its gun killed only 4 strikers, and the asset was breached at tick 118. Rush gets no protection from decoys and no spread across bearings, so cluster-weighted blast targeting from long range should thin the column well before it reaches gun range.
Record
- Best finish: #2 defender (2026-10-05).
- In the top five on 4 of the 6 nights it played.
- Written against: rush.
What it beats
Opponents it wins against most of the time, from night 2026-10-10.
- rush: held in 10 of 10 seeds, mean score 0.80
- attacker_blast_isolated_synchronized_rel: held in 10 of 10 seeds, mean score 0.78
- flanker: held in 10 of 10 seeds, mean score 0.78
- parked_ring_magazine_drain: held in 10 of 10 seeds, mean score 0.78
- depth_shell_saturation: held in 10 of 10 seeds, mean score 0.78
- … and 6 more.
What beats it
- phase_locked_ring: held in 0 of 10 seeds, mean score 0.12
- synchronized_ring: held in 0 of 10 seeds, mean score 0.14
- staggered_trishell_blast_denial: held in 3 of 10 seeds, mean score 0.27
Replays
- Best: vs rush, seed 7: defended in 44 ticks, its score 0.81. rush__2026-10-05_defender_cluster_blast_column_breaker__s7.json
- Worst: vs phase_locked_ring, seed 8: breached in 128 ticks, its score 0.11. 2026-09-30_attacker_phase_locked_ring__2026-10-05_defender_cluster_blast_column_breaker__s8.json
Open one with python viewer/build_viewer.py <replay>, then viewer/index.html.
Source
"""Idea: Treat a single-bearing stream as one target, and spend each interceptor on whichever track has the most uncovered threat inside its blast radius.
Weakness exploited: rush sends all 30 strikers down one corridor at 4 per tick.
That packs them into a dense column only a few units deep per launch tick, so a
single 10-unit blast can catch several strikers at once. The pairing rush vs
gun_only shows the weakness (mean score_defender 0.272). In seed 0, gun_only
fired no interceptors and kept all 20 in stock. Its gun killed only 4 strikers,
and the asset was breached at tick 118. Rush gets no protection from decoys
and no spread across bearings, so cluster-weighted blast targeting from long
range should thin the column well before it reaches gun range.
Method:
- Each tick, score every track by the class-weighted, urgency-weighted threat
near it that is not already covered by an in-flight interceptor.
- Launch at the best-scoring tracks, up to the per-tick cap.
- Retarget interceptors whose target track has vanished.
- Keep a small reserve of stock for close-in leakers.
- Point the gun at the most urgent striker inside gun range.
"""
import math
NAME = "cluster_blast_column_breaker"
ROLE = "defender"
_COVER_R = 9.0 # a track this close to an interceptor's target counts as covered
_CLUSTER_R = 11.0 # neighbourhood used to score blast value (blast 10 + track noise)
def reset(seed):
pass
def _d(a, b):
return math.hypot(a[0] - b[0], a[1] - b[1])
def _w(cls):
if cls == "striker":
return 1.0
if cls == "decoy":
return 0.05
return 0.75
def act(obs):
try:
return _act(obs)
except Exception:
return {"intercept": [], "retarget": {}, "gun": None}
def _act(obs):
rules = obs.get("rules", {}) or {}
tracks = obs.get("tracks", []) or []
inters = obs.get("interceptors", []) or []
stock = int(obs.get("stock", 0) or 0)
ammo = int(obs.get("ammo", 0) or 0)
gun_range = float(rules.get("gun_range", 100.0))
lpt = int(rules.get("interceptor_launches_per_tick", 2))
total_stock = int(rules.get("interceptor_stock", 20)) or 20
action = {"intercept": [], "retarget": {}, "gun": None}
if not tracks:
return action
tracks = sorted(tracks, key=lambda t: (float(t.get("range", 0.0)), str(t.get("id"))))
by_id = {t["id"]: t for t in tracks}
pos = {t["id"]: (float(t["pos"][0]), float(t["pos"][1])) for t in tracks}
# Covered tracks: anything near the target of an interceptor already in flight.
covered = set()
orphans = []
for it in inters:
tgt = it.get("target")
if tgt in by_id:
tp = pos[tgt]
for t in tracks:
if _d(pos[t["id"]], tp) <= _COVER_R:
covered.add(t["id"])
else:
orphans.append(it)
def urgency(t):
r = float(t.get("range", 450.0))
return 1.0 + max(0.0, (450.0 - r)) / 150.0
def value(tid, cov):
p = pos[tid]
s = 0.0
for t in tracks:
oid = t["id"]
if oid in cov:
continue
if _d(pos[oid], p) <= _CLUSTER_R:
s += _w(t.get("cls", "unknown")) * urgency(t)
return s
def eligible(t, stock_now):
cls = t.get("cls", "unknown")
r = float(t.get("range", 450.0))
if cls == "decoy":
return False
reserve = max(2, total_stock // 8)
if stock_now <= reserve:
# Hold the reserve for close leakers and confirmed strikers.
return r < 220.0 or cls == "striker"
return True
def pick(cov, stock_now):
best, bestv = None, 0.0
for t in tracks:
tid = t["id"]
if tid in cov or not eligible(t, stock_now):
continue
v = value(tid, cov)
if v > bestv + 1e-9:
best, bestv = tid, v
return best, bestv
def cover(tid, cov):
p = pos[tid]
for t in tracks:
if _d(pos[t["id"]], p) <= _COVER_R:
cov.add(t["id"])
# Retarget orphaned interceptors to the best uncovered cluster near them.
for it in sorted(orphans, key=lambda x: str(x.get("id"))):
ip = it.get("pos") or [0.0, 0.0]
ip = (float(ip[0]), float(ip[1]))
best, bestv = None, 0.0
for t in tracks:
tid = t["id"]
if tid in covered or t.get("cls") == "decoy":
continue
v = value(tid, covered) / (1.0 + _d(ip, pos[tid]) / 200.0)
if v > bestv:
best, bestv = tid, v
if best is not None:
action["retarget"][it["id"]] = best
cover(best, covered)
# New launches.
s = stock
for _ in range(max(0, lpt)):
if s <= 0:
break
tid, v = pick(covered, s)
if tid is None:
break
t = by_id[tid]
# Avoid wasting shots on lone, far, unidentified tracks once stock is thin.
if (t.get("cls") == "unknown" and v < 1.5 and s < total_stock // 2
and float(t.get("range", 450.0)) > 300.0):
break
action["intercept"].append(tid)
cover(tid, covered)
s -= 1
# Gun: most urgent non-decoy track in range, strikers first.
if ammo > 0:
best, bestk = None, None
for t in tracks:
r = float(t.get("range", 1e9))
if r > gun_range:
continue
cls = t.get("cls", "unknown")
pri = 0 if cls == "striker" else (1 if cls == "unknown" else 2)
k = (pri, r, str(t["id"]))
if bestk is None or k < bestk:
best, bestk = t["id"], k
if best is not None and (bestk[0] < 2 or ammo > 40):
action["gun"] = best
return action