You inherit a weak but legal racing agent and must improve its solve() so that its ego
car beats a pool of opponent policies in wheel-to-wheel races. Your solve() returns a
compact ego-policy parameter set (racing line, speed, overtake and defend behaviour);
it is re-run on unseen tracks against the same opponent pool you can see, racing both
start orders, and scored by the net result — lower cost (more clean wins) is better.
Hard Constraints
Implement solve(problem: dict) -> dict. It is called once and must return within
600 seconds of wall time; if it has not returned by then the run is scored 0.
problem gives visible_cases (race and score them locally against the
public opponent pool with the public simulator), the opponent_pool names, and the
parameter bounds.
Returned fields are clamped to their legal bounds; anything missing falls back to the
default, so a partial policy is always legal. The tunable ego parameters are:
line[0,1] — how far onto the racing line (0 = track centre, 1 = full racing line).
v_push[0.85,1.02] — target speed as a fraction of the grip-limited profile.
ot_gap[2,26] m — gap to a car ahead at which you commit to an overtake.
ot_side[-1,1] — preferred passing side.
ot_aggr[0,1] — extra speed carried into an overtake (more pace, more contact risk).
def_bias[0,1] — how hard you move to block a car behind when leading.
def_gap[4,22] m, follow[3,12] m — defend range and safe-following distance.
You may only change the returned policy — not the simulator, the tracks, or the
opponents.
Deliberately causing a collision loses: collisions you are responsible for and
off-track excursions are penalised, so a reckless dive that trades a pass for contact
can score worse than a clean second place.
What You Have
methods/main/solver.py — the weak baseline you edit in place (returns {}, the
cautious pure-pursuit default that gets held up and picked off).
sim/ — the exact deterministic simulator used for scoring: track.py (track
geometry), racesim.py (quasi-steady speed + the two-car time-stepped race with
overtaking, blocking, collision responsibility and off-track detection), policies.py
(the ego policy machinery and the public opponent pool), problem.py (evaluate,
visible_cases, the cost definition). Read them to understand the rules.
selfcheck.py — races your current solve() over the visible cases and prints the mean
cost and win rate. Iterate against it.
What You Submit
Your edited methods/main/solver.py (plus any helper modules under methods/). The
verifier re-runs solve() and races the returned policy against the sealed opponents;
only the solve(problem) -> policy contract above is relied upon.
How It Is Judged
The sealed verifier calls your solve(), then races the returned ego policy against each
opponent on each hidden track, both start orders. Each race scores
-clip(win_margin, -5, +5) + collision + off-track penalties; the mean cost over the
hidden cases is your score, lower is better, and your reward rises as it drops. The
held-out uses the same opponent pool you can see (including the aggressive counter
style) on three unseen tracks drawn from the same generator as the visible ones — so a
policy that genuinely races well transfers. The residual difficulty is that the best line
and passing side for the visible tracks are not quite optimal for the unseen ones: favour a
robust set-up over one hand-fit to the three public layouts.
Metric
mean race cost over the 36 sealed hidden races · lower is better
-clip(win_margin,-5,+5) + 2.5*[caused contact] + off-track, per race; 3 hidden tracks x 6 opponents x 2 start orders
anchor
held-out
reward
B
BASELINE, the weak inherited policy
+2.9472
0.00
R
REFERENCE, the top anchor declared
-1.6511
0.30
normalisation
m >= B
0
B > m >= R
0.3 * (B - m) / (B - R)
m < R
1 - 0.7 * y^(-3/7), y = (B - m) / (B - R)
m = this run's held-out metric · B = BASELINE, the weak inherited policy · R = REFERENCE, the top anchor declared
The 36 race costs are averaged, then mapped once. anchors.json declares no SOTA and no UPPER, so the soft cap starts at REFERENCE.
Rollouts
65 minwall clock
$13.58spend
19.5Mtokens
14versions, 10 kept
keptrevertedno scoreturning point
v0Inherited default policy: solve() returns {}, wins 6 of 36 visible races3.0651 min · $0.19
v1Broad screen: defence off, max line and pace, ot_side=-1, ot_gap=26, ot_aggr=0.20Screened the whole parameter box in one pass and took the pass side from the generator's shape, not the three visible tracks.-1.395 min · $0.89
v2Line sweep replaces the full racing line with a 0.50 blend; defence still off-1.55310 min · $1.57
v3Dense line neighbourhood: line=0.44, inside the stable 0.42-0.48 basin-1.80715 min · $2.50
v4High-aggression regime ot_aggr=0.90 at line 0.44Predeclared a 12-track stress bank before testing, then let it veto a candidate that had won both selection banks.-1.72826 min · $4.31
v5Low-aggression refinement: ot_aggr 0.20 -> 0.21-1.9333 min · $5.58
v6Full-range basin audit representative: line=0.30, ot_aggr=0.90-1.06641 min · $7.25
v7Predeclared-holdout finalist at ot_aggr=0.45-2.1145 min · $7.94
v8Unchanged v5 policy audited on 30 fresh radius-stratified trackspublic not re-measured49 min · $8.89
v9Fresh-seed 5x5 stability surface: line=0.44, ot_aggr=0.19-1.82655 min · $10.39
v10One-factor interaction screen moves line 0.44 -> 0.43Accepted a change the visible races scored worse because 30 untouched tracks preferred it, winning 20 of 30 paired.-1.65958 min · $11.45
v11ot_aggr back to 0.20 after the line change-1.71161 min · $12.40
v12Unchanged v10 policy audited against v8 on 60 brand-new trackspublic not re-measured63 min · $13.05
v13Unchanged v10 policy replayed on the six-track reserved holdoutpublic not re-measured64 min · $13.23
Fourteen snapshots in 65 minutes and $13.58. Three kept versions changed no parameter; they are audits on freshly seeded tracks.
v0Inherited default policy: solve() returns {}, wins 6 of 36 visible races3.065168 min · $0.91
v5ES search under a zero-collision rule: line=0.435, ot_aggr=0.41, mild defenceRepriced the search objective to weigh contact above margin, then refined locally from the collision-free point.-1.6902168 min · $0.90
Six logged experiments, two snapshots, both written in the last minutes of a 169-minute, $0.98 run. Nothing reverted.
v0Inherited default policy: solve() returns {}, wins 6 of 36 visible races3.0651 min · $0.16
v1Full racing line at maximum legal pace (line=1, v_push=1.02), default racecraftPushed the two parameters the simulator clamps anyway: speed is grip-limited, so over-asking is free. Wins 6/36 -> 25/36.-0.6522 min · $0.25
v2Coarse 32-policy line/pace grid: line=0.70 at maximum pace-0.9062 min · $0.35
v3Fine line sweep: line=0.47 at maximum pace-1.2213 min · $0.45
v4180-point pass grid: early opposite-side passes (ot_gap=26, ot_side=-1, ot_aggr=0.30)Stopped tuning where to drive and started tuning how to pass: commit as early as bounds allow, on the side the pool leaves free.-1.9515 min · $0.64
v5Defence grid of 77 policies; nominal best def_bias=0.05, def_gap=6-1.9546 min · $0.82
v7Seeded 544-policy global line/gap/aggression search; raw winner ot_aggr=0.285-2.04217 min · $2.33
v8Defence retuned jointly with 0.305 aggression: def_bias=0.05, def_gap=6-2.09419 min · $2.67
v9Robustness-selected line=0.425 in place of the sharper 0.47 point optimum-2.04424 min · $3.44
v10Defence range narrowed to the minimum def_gap=4-2.11325 min · $3.72
v11ot_aggr=0.2924 from the stable 0.2922-0.2936 band, not the raw minimum-2.12532 min · $5.08
v12Interaction-search candidate ot_aggr=0.3036 with def_bias=0.10-2.15840 min · $6.81
v13Joint line/aggression robustness study: line=0.37, ot_aggr=0.2929Changed the acceptance test itself: candidates ranked by their mean over 75 local perturbations, not by their visible score.-2.1543 min · $7.71
v14Defence retune: def_bias=0.15, def_gap=5-2.18346 min · $8.51
v15Neighbourhood-robust defence: def_bias=0.125, def_gap=4.5-2.15649 min · $9.36
v16Fine aggression retune to ot_aggr=0.2932-2.18550 min · $9.63
v17Fine line sweep raw candidate line=0.353-2.24452 min · $10.62
v18Code-comment cleanup only; policy identical to v16-2.18553 min · $10.90
Nineteen snapshots in 53 minutes and $10.90, all judged on the same 36 visible races. Each of the four reverts held the best visible mean when tried.
v1Coordinate sweep on a 16-track bank: line=1.0, v_push=1.02, ot_gap=26, ot_side=-1Read the generator, not the tracks: every loop it makes runs the same way, so the -n side is a permanently free passing lane.-0.92422 min · $1.06
v218-generation DE (pop 40, 7 live dims) on 20 generated tracks; line drops to 0.0Handed the whole 7-D box to differential evolution instead of one axis at a time; it moved the car out to the track centre.-1.48399 min · $2.86
v31-D curves on a fresh 150-track bank; line=0.30 plateau centre, ot_aggr=0.85-1.536235 min · $5.32
v42-D line x ot_aggr grid on a pooled 400-track bank: line=0.42, ot_aggr=0.55Re-measured both live dimensions jointly over 4,800 races: the optimum is interior at 0.42, not the centre the small banks read.-1.675332 min · $6.48
v5line 0.42 -> 0.44 after the optimum held on four disjoint 90-track slices-1.696396 min · $7.33
v6ot_aggr re-scanned on a 600-track bank (7,200 races); interior peak 0.60 taken-1.707445 min · $8.37
Six snapshots in 445 minutes and $8.37. Most of the clock went into re-racing candidates on 200- to 600-track banks, plus three studies with none.
v1Hand-set screen: line=1, v_push=1.02, ot_gap=26, ot_side=-1, ot_aggr=0.20, no defenceTook ot_aggr=0.20 over the visible-best 0.30, which held the public tracks but drew 159 collisions on generated ones.-1.39
v2Mild short defence added: def_bias=0.20, def_gap=8-1.458
v3line 1.0 -> 0.97 from a neighbour search on a separate 10-track matched set-1.478
v4line=0.94, def_gap=11; ranked by hold-out order, not by the visible meanAccepted a worse visible score because the frozen hold-out and a seed-777 bank never used for picking both put it first.-1.466
v5Runtime search over the robust cluster on 6 generated tracks: line=0.94, def_gap=8-1.432
v6line 0.94 -> 0.88 after a 12-track seed-888 sweep; held on hold-out and fresh bank-1.601
v7line 0.88 -> 0.80, best combined unseen score of 0.80, 0.84 and 0.88-1.568
v8Defence dropped: def_bias 0.20 -> 0, 34 of 36 visible winsAt line=0.80 the blocking term steers the ego into its chaser, so removing defence is both simpler and cleaner.-1.658
Eight snapshots in 84 minutes; this harness reports no cost or tokens. Every accept had to hold on a frozen 10-track hold-out.