Bounded JavaScript tactics, resource planning, and measured evolution
The offline trainers now include bounded approach credit based on navigable route distance, not Euclidean proximity. See the current plan for deployment state, checks and limitations. tools/ai/approach.mjs samples a swept-disc route graph once per simulated second, using the same active trail segments as collision. It credits the AI's own progress toward a frozen target, checks that the opponent is still reachable, and excludes passive closing and disconnected regions. A per-pair progress high-water mark limits repeated approach/retreat credit; initial enemy-pair normalization prevents team-size/death artifacts. The maximum approach bonus remains 0.15. Fitness version 2 now assigns one base point plus up to one early-confirmation point per eliminated enemy, shared between direct wall owners and successful trappers. Unfinished confinements no longer earn fitness. See the current plan for the bounded evolution results and limitations.
This is offline instrumentation only: it does not add pathfinding to the live controller or change the deployed policy. The 2.4 m graph is a conservative route estimate; it can miss narrow passages and does not predict future trails or enforce heading/turn dynamics. No Euclidean fallback is used. Training outputs record the reward configuration. All 583 unit tests and a four-seat tournament smoke pass; a subsequent two-generation run and fresh-seed comparison are recorded in the current plan. Its candidate improved trap assists and combined fitness but not direct kills, and remains unpromoted.
The first bounded controller is implemented and enabled by default for multiplayer and the initially unbreached standalone arena. It is plain shared JavaScript: no service requests, inference library or background training. The previous controller remains available with race.aiMode = 'classic'; exterior/open-arena behavior stays on the existing controller unless explicitly overridden for development. No production deployment is part of this implementation request.
Implemented behavior:
__tron.configureCycleAI({mode:'bounded', measure:true}) and __tron.cycleAI diagnostics. The latter includes decision/guard counts and cumulative AI milliseconds. Multiplayer AI remains authority-owned; the client panel cannot edit it. Settings apply to the current local arena, persist across its rounds, and are not saved globally.Reference machine: Apple M2 Max, macOS, Node v22.22.0; headless Chrome 155 at 1280×800. These measurements are not server-runtime or low-end-device guarantees.
| Check | Result |
|---|---|
node tools/ai/benchmark.mjs classic 3 180 | Existing full-tick p99 approximately 1.80–1.82 ms across seeds 1982–1984; matches ended in 35–69 simulated seconds |
| Initial all-bounded full matches | Full-tick p99 approximately 0.38–0.57 ms; several matches reached the 180-second horizon, so stalling/endgame variety still needs play review |
node tools/ai/stress.mjs | Twelve bots and 2,048 changing segments: AI p95 0.262 ms, p99 0.493 ms, max 0.867 ms; no index overflow |
node tools/ai/stress.mjs --crowded | Same history with twelve nearby threats: AI p95 0.399 ms, p99 0.487 ms, max 0.871 ms |
node tools/ai/compare.mjs 3 | New team won 9/12 matches against three classic teams, rotating through all four spawn teams for seeds 2200–2202. No draws. A small correlated sample, not a statistically established general win-rate gain |
node tests/browser/cycle-ai.mjs | Local arena/tuning work without page errors; dense browser AI p99 0.4 ms. Actual AI work accumulated per rendered frame: p99 0.4 ms across 481 frames; max 0.7 ms. The rendered test has five AI cycles; the separate dense test has twelve |
npm run build / npm run worker:check | Production build/asset audit and Worker dry run pass; no deployment |
node tests/multiplayer-browser.mjs | Two rendered clients, twelve-cycle arena, fourteen connections, queue and restart/lifecycle checks passed |
node tools/ai/evolve.mjs --smoke and --smoke --neural | Linear and neural candidate tournament pipelines run and emit a review artifact; short 15-second smoke matches all timed out. No claimed learning improvement or policy promotion |
npm test | 550 tests pass, including collision/expiration/overflow, deterministic decisions, human isolation, policy bounds, neural safety mask, speed/resource forecast, turbo cutoff, brake/yield, turn cooldown and containment fixtures |
Run node tools/ai/evolve.mjs for the full offline linear experiment, or append --neural for the optional network experiment. It writes test-results/cycle-ai-candidate.json, never edits the shipped policy and never trains during play. Full runs intentionally cost more than the smoke check: multiple generations, spawn rotations and a held-out suite. Inspect performance and match results, run scenario checks and human review before importing artifact.policy through the development helper or changing the default policy in source. The reported Wilson interval is exploratory: spawn rotations share seeds and are correlated; it is not a sufficient promotion test by itself.
Remaining release-quality evidence: slower devices, actual deployed authority CPU/tick debt, long dense-history full-collision matches, larger held-out tournaments, and real-player impressions of aggression and endgame pacing. CPU timings below the gate do not prove that every overload fallback is strategically good. Geometry saturation stays conservative and can cost a bot an escape. No automated check establishes that the bots are already compelling to human players.
The staged design below remains the longer-term target; unchecked advanced stages are not represented as completed by this first controller.
Design a plain-JavaScript arena AI that wins through positioning, timing and resource use. Runtime performance is the first priority. Add intelligence only when it fits the measured budget. The implementation status above distinguishes completed work from the remaining design; this page does not authorize deployment.
Priority order:
Optional progression: evolve a compact parameter set using controlled win-rate experiments. Trial a tiny neural scorer only if it improves play under the same performance and safety gates. No JEV calls, model downloads, GPU inference or training in the game loop. JEV for tanks/Recognizers is outside this change.
The authoritative movement and AI currently meet in shared/simulation/light-cycles.js. chooseCycleDirection compares forward/left/right using clearance, bounded flood-fill space, nearby cycles, a bias toward opponents' forward lanes, optional jevGoal, and small random score noise. Turbo/brake decisions then use clearance thresholds. AI decisions run on sampled reaction intervals; movement is continuous with bounded 120 Hz steps. The planning occupancy grid has 4.8 m cells; it is not the continuous collision authority.
Reuse the movement, speed response, resource accounting, trail trimming/damage/lifetime and swept collision rules in shared/simulation/. Avoid maintaining an approximate second ruleset that can approve a path the real simulation rejects. Extract small shared pure helpers where needed, with parity tests before switching controllers.
Multiplayer runs at 120 Hz with at most twelve cycles and a configured 2,048-trail limit (shared/multiplayer/config.js). A tick is about 8.33 ms; that is the budget for the entire authority, not an allowance for each AI. Normal speed is 38.4 m/s, maximum turbo target is 96 m/s, brake target is half normal speed. Turbo/brake each have five seconds of full-charge use and sixty seconds of recharge; acceleration/deceleration are gradual. Trail rewards can change available charge. Read all of these from configuration rather than copy constants into the planner.
Scope the first release to the closed arena in single-player and multiplayer. Preserve the existing exterior-road controller and explicit transitions to/from it. Apply the new controller only to AI-owned cycles, never human seats. Remove cycle-specific JEV goal influence and scheduling only when the replacement passes its gates.
The following are provisional acceptance targets, not measurements. Stage 1 must establish them on a named reference desktop/browser and the actual server runtime. Include a slower browser/device profile; do not judge speed solely on this development machine.
| Quantity | Initial ceiling or target |
|---|---|
| All AI work per authority tick, twelve bots | p95 ≤ 0.5 ms; p99 ≤ 1 ms, including geometry-index maintenance |
| Whole authority tick | p99 < 8.33 ms; no growing tick debt in sustained worst-case matches |
| Browser frame cost attributable to AI | p99 ≤ 1 ms at 60 Hz, including multiple fixed steps per frame; no AI-caused long tasks |
| Tactical planning | At most 2 bots per tick; each bot eligible every 12 ticks (10 Hz), stable ID-based staggering |
| Strategic/target refresh | Every 60 ticks (2 Hz), also staggered |
| Maneuver candidates | At most 12 per tactical decision |
| Detailed candidates/opponent replies | Best 3 candidates; at most 3 plausible replies for the selected threat |
| Local space estimate | At most 256 visited cells per bot decision, shared across candidates |
| Emergency guard | Every simulation tick, short bounded queries for each live bot |
Define additional explicit ceilings for segment tests, rollout steps and index updates in Stage 1. Count work for the entire tick, not merely per candidate. Profile a full 180-second match, dense intersections, repeated tight turns, trail retirement, deaths and catch-up bursts. Test the current trail cap and the maximum supported single-player arena history. Report p50/p95/p99/max, decision age, segment-test counts, allocations/GC, frame tails and server tick debt. Measure snapshot/serialization work as well as AI.
Use operation-count limits to choose behavior; wall-clock timing is telemetry, not the normal search termination rule. This makes replays independent of machine speed. If a budget is exhausted, retain a still-valid plan or select a bounded defensive fallback. Never interpret unfinished searches as proof that a corridor is safe. Safety work has reserved capacity; tactics cannot consume it. If even the guard cannot complete its required checks, release turbo and choose the best verified alternative, recording the overload. No fallback can guarantee survival once every route is lost.
Do not run a full flood fill or recursive search every tick. Use reusable typed arrays, generation stamps instead of clearing whole maps, and fixed-capacity candidate/rollout buffers. Avoid per-bot copies of the full race, trail list or occupancy grid. Maintain one shared trail spatial index incrementally; account for active endpoints, removals, damage and death fading. Bound index queries in dense buckets too. Overflow produces conservative uncertainty, never silently missing a barrier. A Web Worker is a later measured option, not the baseline: snapshot copying and delayed answers could erase its benefit.
Keep a few focused modules under a proposed shared/simulation/cycle-ai/ directory:
| Module | Responsibility |
|---|---|
controller.js | Per-bot plan state, fixed scheduling, emergency guard and legal turn/control output |
geometry.js | Shared local queries, bounded space estimates and index maintenance |
maneuvers.js | Generate a small set of attack, escape and resource-control candidates |
evaluate.js | Safety filtering, short rollouts, features and utility scoring |
config.js | Named units, immutable runtime limits and versioned tunable behavior weights |
A candidate is a compact sequence of at most two turns with trigger ticks/positions, a short turbo/brake/coast schedule, target ID, expected exit and expiration. Internally use meters and seconds, converting at the adapter to existing cell-coordinate state. Execute only the next committed control, then reassess. Do not expose future AI plans as public opponent intent.
All bots planning on a tick read the same pre-command observation; apply controls afterward. Use stable ID ordering for tie resolution so array order does not create an accidental advantage. Bots may observe arena geometry and public cycle pose/control/resource information. They must not inspect human pending inputs, future AI commands or hidden private intent. For fair difficulty, record perception/reaction cadence explicitly; the emergency guard is a bounded reflex, not a license to react to unseen commands. Keep turn cooldown and speed/resource limits equal to the relevant player rules.
Split cheap danger handling from planning. Each tick checks the current short swept corridor and plan validity. It can cancel turbo, brake when that actually helps, or execute a previously validated escape. Tactical planning selects the next maneuver. Strategic planning picks a useful opponent/region and, later, complementary team roles. Keep target and maneuver hysteresis so tiny score changes do not cause aimless turn oscillations.
Generate candidates from geometry rather than random action trees:
For each attack, compare arrival times under the real acceleration and reserve rules. Check when the emitted trail actually occupies the crossing, continuous body clearance and a safety margin for opponent response. Evaluate a small reply set: continued motion, a legal escape turn, and a relevant speed response. Select replies from nearby threats, using conservative motion envelopes for others. A full twelve-agent minimax search is explicitly out of scope.
Use a coarse occupancy/region estimate to rank promising routes, followed by continuous swept checks for finalists and the executed prefix. Include the attacker's newly emitted trail in rollouts: a two-turn maneuver can cut off its own exit. Model known trail expiration, shortening and damage; never count a barrier as already gone just because it is visually fading. A confirmed opponent turn invalidates its old motion forecast immediately, while expensive replanning remains scheduled and bounded.
Score opponent escape loss and territory advantage alongside personal survival, remaining exits and charge. Use a hard safety filter before scoring, rather than letting a large aggression bonus outweigh a predicted collision. When no safe candidate remains, choose the best survival opportunity and record the failure. Short-horizon verification is not a proof against every future opponent action.
Team coordination is a second-stage feature: assign at most one closer and one exit-denier to a target, with brief reservations for their intended corridors. Teammates stay collision hazards. Penalize redundant pursuit and blocking an ally's escape. Do not assume a human teammate follows the plan, and do not require perfect teammate cooperation for the attacker's own safety.
Evaluate turn and resource choices together. Candidate schedules are short pulses followed by release, not simply “turbo whenever clear.” Integrate actual speed response and charge to compare arrival times; braking reduces speed, it does not instantly stop the cycle.
Spend turbo only when it creates a robust lead, reaches an exit before closure, or materially expands safe territory. Stop boosting once the required lead is achieved. Spend brake to yield a dangerous crossing, avoid entering a closing corridor or change an opponent's cutoff timing; reject braking that only delays an unavoidable impact while sacrificing the escape.
Price reserve use by context. Charge has higher value with nearby threats or few exits, and lower value when an immediate advantageous cutoff is available. Keep a configurable reserve floor for ordinary attacks, overridable for a verified escape or a sufficiently strong finishing opportunity. Test exhausted reserves and rewards; releasing a request matters because recharge depends on requested controls. Apply switching hysteresis to avoid turbo/brake flicker.
Remove independent noise that can promote an inferior unsafe move. First reject unsafe and clearly dominated candidates. Then choose among alternatives within a small normalized utility tolerance of the best, provided each meets the same clearance, exit and reserve constraints. With only one strong move, take it deterministically.
Sample modest personality preferences once per round: cutoff preference, target stickiness, resource conservation, desired open space and preferred side in symmetric situations. Keep safety margins and computational ceilings outside this variation. Maintain commitment until invalidation or a materially better option appears; do not resample every frame.
Use an independent seeded PRNG stream per bot, round and policy version. A different bot's death must not consume this bot's random sequence. Replay the same seed, policy and observed inputs identically on the same supported runtime. Cross-engine bit-identical floating-point behavior is a separate test requirement, not a promise. Multiplayer remains server-authoritative; clients do not need to reproduce AI decisions to render them smoothly.
Begin with approximately 8–12 bounded parameters: cutoff reward, containment reward, space value, reserve price, attack reserve floor, timing margin above the hard minimum, target-switch cost, commitment duration and near-best selection tolerance. Separate these from non-evolvable safety minima, reaction rules and runtime ceilings. Store a versioned JSON policy with parameter bounds, training seeds, benchmark results and parent policy ID.
Run a plain Node.js headless tournament outside live matches. Mutate a small population around the champion, evaluate cheaply to reject poor candidates, then spend more trials on promising challengers. Use paired seeds with swapped spawn locations, team colors and teammates. Compare against the frozen current bot, several historical champions, defensive and aggressive opponents, plus mixed-policy teams. Separate duel and six/nine/twelve-cycle results. Rotate a held-out seed pool and keep the final promotion suite unseen during optimization.
Rank performance lexicographically: runtime gate, safety regression gate, then combined aggression-and-win fitness, then team win rate. Record draws/timeouts explicitly, treat the whole match as the statistical unit, and report sample counts and uncertainty. Do not promote on a handful of wins or repeated testing against the same seeds. Require a prespecified statistically supported improvement on held-out matches and no material regression in scenario failures, resource efficiency or performance tails. Keep diverse historical opponents to discourage cyclic overfitting. Human play review remains necessary: higher win rate can still mean dull stalling.
Public win rates are useful monitoring data, but depend on human skill, seats and teammate composition. Do not directly update weights after each public win/loss. Collect policy-tagged results, use them to identify weaknesses, validate a challenger offline, and activate a frozen approved version between matches with rollback available. Never mutate behavior midway through a match. Keep training opt-in and off the browser/server simulation loop.
A small network is appropriate to rank validated candidates, not to replace collision checking or invent arbitrary controls. First establish the linear weighted scorer and evolutionary tuning baseline. Only keep the network if a controlled comparison earns its extra complexity under the same total decision budget.
Initial experiment: 32 normalized candidate features → 16 ReLU hidden units → 1 utility output. This is 528 weighted multiply-adds and 17 biases per candidate, or 545 float32 parameters (2,180 raw weight bytes). With twelve candidates it requires 6,336 weighted multiply-adds per decision. These are operation counts, not timing claims; feature extraction, geometric queries and rollouts can cost more than inference.
Implement inference with fixed typed arrays and ordinary JavaScript loops. No tensor framework, WebGPU, WASM runtime or additional download is required. Clamp/validate inputs and outputs; a non-finite score falls back to the linear scorer. Keep candidate generation, safety masks, resource rules, scheduling and deterministic PRNG outside the network.
Features should describe the candidate rather than a raw arena image: verified clearance/time-to-impact, own exit count, bounded reachable space, target escape reduction, crossing arrival margin, nearby threat distances/headings, current and predicted reserves, speed-control cost, ally interference and plan-switch cost. Include truncation/uncertainty flags so a capped space estimate is not treated as complete information. Features must use only permitted observations and have documented scales. The compressed view can miss global traps; the neural scorer does not remove that limitation.
Train and evaluate outside live play. A first experiment can use bounded weight mutation and tournament selection; compare its sample cost with evolving the smaller linear parameter set. Another option is offline supervised fitting to stronger bounded-search labels, followed by actual match evaluation. A score trained from match outcomes is not automatically a calibrated win probability. Do not call improved imitation loss improved gameplay without tournament evidence.
Version features, architecture and weights together. Benchmark linear and neural scorers with identical candidate sets, seeds and runtime ceilings; measure complete AI cost, not inference alone. Keep the linear policy if neural gains are inconclusive. The hybrid idea has precedent in Stockfish's neural evaluation; its results and specialized NNUE architecture are not evidence that a network will improve TRON.
Validation status: implementation measurements and completed checks are recorded above. Unchecked stages remain outstanding, especially cross-device/server benchmarking, advanced coordination, training promotion and human play review.
The authority now tracks coarse reachable space on a 40×40 graph. One cycle is sampled every 0.1 seconds, at most three opposing wall owners are tested per sample, geometry is capped at 2,048 segments, and all floods in one update share a 16,000-node visit budget. This is attribution only, never a replacement for swept collision. A new enemy wall must reduce reachable space substantially: the remaining area is at most 40% of the arena, and removing its newly added barriers restores at least 80 coarse cells and 1.5× the area. Mere proximity and following do not earn credit.
A detected trap remembers the original walls and region. New walls laid inside that region—including the victim filling it with a spiral—do not erase attribution. Before awarding an assist, the authority checks that the victim remains inside the original region and that surviving original barriers still enclose it. Removing the attacker's wall must restore meaningful escape space. There is no timeout. A direct hit on that same attacker's wall remains a direct kill, not an additional assist. Multiple attackers share at most one assist reward per victim. Hollow victim-colored roster dots show assists; filled dots remain direct wall eliminations. Compact snapshots carry assists, but not graph/history state.
Conservative limitations: this graph cannot prove every narrow passage or every driving maneuver is viable. Breaches expand to coarse cells and deny uncertain credit. Trail damage, trimming or retirement invalidate pending attribution rather than risk keeping credit across a sub-grid opening; this can miss valid traps, including when an unrelated trail changes. Budget exhaustion cannot award an assist. A trap completed between scans can be missed. Large-region partitions and non-cardinal road joins are deliberately excluded. Human attribution review and slower-hardware/Worker profiling remain outstanding.
Offline tournament fitness now awards 1 point per team win, 0.5 per direct enemy wall elimination, 0.35 per trap assist, and 0.1 per newly created confinement. Confinement and assist rewards are separately capped to one shared reward per victim per match. Runtime compliance ranks first; combined fitness ranks next, with win rate breaking ties. Thus aggression is a primary objective, not merely a tie-breaker for equally winning passive policies. Artifacts retain raw wins, draws, direct kills, assists and confinements. Promotion remains manual, with held-out checks and human gameplay review; no evolved weights have been deployed.
Validation on Apple M2 Max, Node 22.22.0 and Chrome: 561 unit tests pass, including persistent 90-second trapping with self-fill, escape/opening invalidation, duplicate/direct/friendly exclusions, and shared reward ranking. Chrome roster checks pass; hollow assist dots visually inspected. A 12-cycle/2,048-trail stress fixture (node tools/ai/trap-stress.mjs) measures scheduled attribution work at p95 0.152 ms, p99 0.187 ms and max 0.191 ms. One 180-second bounded-AI match produces one trap assist despite zero direct wall kills, with total simulation tick p99 0.660 ms; the match times out, so this is not evidence of improved winning or entertainment. Evolution smoke pipeline and production build pass. Implementation is local, not deployed.
Completed node tools/ai/train.mjs: four policies × two generations × four training seeds × four spawn rotations (128 training matches), then eight fresh seeds × four rotations for both the selected candidate and baseline (64 evaluation matches). Each match allows 180 seconds. Mutations are seeded (44123); historical opponents remain in training. Three worker threads execute simulation matches without timing instrumentation. Serial, uncontended performance checks gate each generation winner and the final candidate. The neural scorer remains disabled.
Selected policy: aggression-1-0. Full weights, training scores, per-match held-out results, configuration and serial timing are retained in the experiment artifact. No automatic policy promotion or deployment occurred.
| Fresh-seed results (32 matches each) | Baseline | Candidate |
|---|---|---|
| Direct enemy wall eliminations | 3 | 5 |
| Trap assists (shared credits) | 9 | 10 |
| Confinements (shared credits) | 42 | 44.17 |
| Wins | 4 | 5 |
| Timeouts/draws | 16 | 13 |
| Losses | 12 | 14 |
| Mean combined fitness | 0.4016 | 0.4818 |
This is a modest exploratory gain, not established superiority. Candidate fitness is better on five seed groups, worse on two and tied on one; the approximate paired t interval across eight independent seed groups for the mean fitness difference is −0.301 to +0.461 (95%), spanning no improvement. Four spawn rotations within a seed are correlated. More losses and still many timeouts warrant gameplay review. These tournaments use closed arenas; they do not establish the same result under multiplayer wall-breach rules.
Serial M2 Max/Node 22.22 timing for the candidate: AI p99 0.186 ms, full tick p99 0.598 ms, maximum full tick 2.528 ms. Chrome 155 on macOS verifies the exact selected weights, no page errors, and a rendered frame AI p99 of 0.300 ms; the isolated 12-cycle/2,048-trail browser planner fixture gives p99 0.400 ms. Captured and inspected the arena rendering. Sixteen focused AI/fitness tests and the production build pass. Visual rendering does not establish that the opponent feels more fun.
To play locally, open http://127.0.0.1:5173/?cycleAITrial=1 and choose LIGHT CYCLES. This development-only route loads test-results/cycle-ai-trained.json, validates the policy and requires its serial runtime check to have passed. The normal URL retains the baseline, and multiplayer authority is unchanged. Neither the loader nor the training artifact URL appears in production bundles. To reproduce the saved trial without retraining, copy the experiment JSON above to test-results/cycle-ai-trained.json. Browser check: node tests/browser/cycle-ai.mjs --trial.
At the user's request after playing the trial, aggression-1-0 is now the shared default in shared/simulation/cycle-ai/policies/aggression-v1.js. Both solo arena bots and the multiplayer authority use these frozen weights. Solo LIGHT CYCLES keeps bounded AI enabled after a breach. Human controls and road mode remain unchanged. Training artifacts cannot replace this gameplay policy automatically; further evolution is separate. The original bounded-v1 weights remain available as BASELINE_POLICY for reproducible offline comparisons.
The earlier trial-only restriction no longer applies to these weights: normal local solo and MP games use them without a query parameter. This is a local source change, not a production deployment. Focused authority/AI tests verify both paths select the same policy; two-client Chrome MP lifecycle checks and the Worker dry run pass.
node tools/ai/evolve-until-plateau.mjs completed four generations and stopped after three consecutive generations without a qualifying validation improvement. This is a plateau for this mutation/search setup, not proof that no better policy exists. The validation winner plateau-0-0 scored 0.4484 mean fitness on 32 fresh matches, versus 0.4664 for the playtested aggression-1-0 and 0.3781 for bounded-v1. The challenger had 5 wins, 24 draws and 3 losses; the playtested policy had 4 wins, 14 draws and 14 losses. More survival did not produce better combined aggression fitness. Neither the trial artifact nor gameplay default was replaced.
Full results: plateau experiment. Serial M2 Max Node timing passed: AI p99 0.252 ms and full simulation tick p99 0.661 ms. Closed-arena evaluation and small seed count remain limitations. Shared default integration passes 562 unit tests, Chrome AI and two-client multiplayer checks, and the Worker dry run; production remains unchanged.
Offline evaluation now adds fastWinBonusPoints × max(0, 1 − seconds / matchLimitSeconds) only for the winning team. AI_FITNESS.fastWinBonusPoints defaults to 0.5, in addition to the base win point: a 90-second win in a 180-second evaluation earns 1.25 before aggression rewards. A deadline win earns 1.0. Losses and timeouts earn no speed bonus, while earned wall, assist and confinement credit remains. Missing or invalid timing earns no bonus. Confinement credit is already recorded when a trap is detected and is not discounted by time spent filling the trapped region.
Match results carry their configured limit, and tournament worker rows include the speed contribution. Fitness weights are retained in new training artifacts. Earlier artifacts retain their original scoring and must not be compared directly with new scores. Four fitness tests and the offline evolution smoke pass. No live simulation work or gameplay-policy change is introduced; a new training comparison is still required to establish behavioral improvement.
Original sources suggest several useful directions:
ThinkCloseCombat uses relative opponent position, direction and speed, reaction allowance, wall sensing and explicit cutoff comparisons, with emergency survival checks. This is a useful real-time interception reference, not evidence of learned turbo overtaking.Proposed next experiment, not implemented: keep bounded geometry/safety work, expose opponent-relative motion and speed reserves to a small policy controlling turn/turbo/brake jointly, and train against diverse historical opponents with explicit overtake/interception scenarios. Evaluate aggressive wins and successful confinement rather than survival time alone. A modest time penalty needs testing against suicide/recklessness. Maintain runtime as the first gate; use expensive search offline if it helps produce training examples. Our variable-speed, multi-cycle arena requires its own validation.
Ran node tools/ai/evolve-until-plateau.mjs --fast-wins using Node 22.22.0 on Apple M2 Max. Start from frozen aggression-1-0; mutation seed 882913, training seeds beginning at 220000, validation 240000–240003, final 300000–300007. Each seed has four team-position rotations, with 180-second match limits. Runtime measurements run serially after parallel match evaluation.
All three generations failed the predeclared improvement criterion (fitness gain at least 0.02, improvements in at least three of four validation seed groups, and runtime pass). Training-selected challengers had validation fitness deltas −0.1560, −0.3443 and −0.2188; only the first improved any seed group (one). Stop after three consecutive failures. This establishes a plateau for this bounded weight-mutation experiment, not absence of better policies. No neural policy or new action repertoire was trained.
The run executed 352 matches: 16 initial validation, 192 training, 48 challenger validation and 96 final evaluations. Because the champion stayed unchanged, two final 32-match evaluations use the same policy and seeds and produce identical results; they are a reproducibility check, not independent evidence.
| Fresh evaluation | Retained playtested policy | Original baseline |
|---|---|---|
| Wins / draws / losses | 5 / 19 / 8 | 5 / 12 / 15 |
| Mean winning duration, seconds | 147.46 | 151.20 |
| Direct wall eliminations | 6 | 6 |
| Trap assist credits | 9 | 12 |
| Confinement credits | 52.5 | 50 |
| Total faster-win bonus | 0.4519 | 0.4000 |
| Mean combined fitness | 0.5266 | 0.5500 |
Only five wins per policy contribute to mean winning duration, and they need not be the same scenarios. Eight independent seeds with correlated spawn rotations are insufficient to claim a reliable speed advantage. The retained policy has more draws and slightly worse combined fitness than the original baseline here. Neither this comparison nor unsuccessful mutations demonstrate that the new reward reduced spiraling. Trial and gameplay weights remain unchanged.
Serial runtime passes the existing gate: AI p99 0.235 ms and full tick p99 0.478 ms; maximum full tick 10.860 ms exceeds one 120 Hz tick budget, so the p99 result is not a guarantee of no overruns. Closed-arena fixtures do not establish performance with MP breaches or on slower/server hardware. Four fitness unit checks pass; script syntax and generated-document checks pass. No browser test or deployment was needed for this offline experiment.
Preserved full weights, rows, configuration, validation and timing. Further work should change the training situations or available decision structure rather than claiming more repetitions of this search have found a better AI.