Draw freight on the card, and teach the bot to build a railroad
This commit is contained in:
@@ -9,11 +9,44 @@ Ordered within each section by how much it is currently costing us.
|
||||
|
||||
## Next
|
||||
|
||||
- [ ] **Find out why switching work does not become Revenue.** The crew now drops 11 cars a game and
|
||||
couples 8 (was 3.3 and ~0.4), at about 4 Moves per productive act — real railroading. Revenue
|
||||
did not move (3.9 → 3.2). Either the freight it is now shuffling is not the freight the
|
||||
industries want, or the loads finish too late in the Day to be worked, or the Revenue is going
|
||||
somewhere and being lost again. Measure the freight chain end to end before changing anything.
|
||||
- [ ] **Measure with error bars from now on.** Revenue has a standard deviation of ~9, so a
|
||||
100-game run carries about ±1.0 of noise — every single-change revenue claim in the changelog
|
||||
before the Interlocking work is inside that. Use paired per-seed comparison (the harness deals
|
||||
the same seeds either way) and 400+ games before calling a heuristic change good or bad. The
|
||||
first attempt at the Running Track straight was read as a 0.6 REGRESSION on 100 games and is
|
||||
a 0.7 improvement on 400.
|
||||
- [ ] **Confirm the Classification Yard rule against the source.** Cars now return to the Division
|
||||
Yard at the Day boundary — an ASSUMPTION, not a recovered rule. Gap 2c says everything but
|
||||
cabooses goes to Classification and never says how it empties. It is worth +2.32 revenue a
|
||||
game, so if the real rule differs the balance numbers move with it.
|
||||
- [x] ~~**Enhancements are placed but mostly do nothing.**~~ Measured: forbidding every Enhancement
|
||||
except Interlocking is worth **-0.01 ± 0.41 (t = -0.04)** over 400 paired seeds. They neither
|
||||
pay nor cost. Left alone. Unlocking the Running Track straight put
|
||||
nine kinds on the board (telegraph 0.73, waterColumn 0.57 …), but only Interlocking has a
|
||||
measured effect. The Telegraph/Telephone/Radio chain adds to the other train's number when
|
||||
dispatching facing trains, which may be worth nothing in solitaire; Water Column removes a
|
||||
Watertower; Facing Point Locks prevents Derail, which is multiplayer-only. Worth measuring
|
||||
what each is actually worth before the bot spends actions on them.
|
||||
- [ ] **The marginal Local Operations action is worth ~0, and that is the real ceiling.** Three
|
||||
separate attempts to spend the 60 actions better — capping the draw, pairing the two halves of
|
||||
a load, restricting Enhancements — each measured within noise of zero over 400 paired seeds.
|
||||
76% of the time an outbound industry has neither a stocked green box nor a spotted car, and
|
||||
only 5% of Stages have a single workable facility anywhere, yet redirecting actions at that
|
||||
does nothing. Something upstream limits how much work exists to do at all; find out what
|
||||
before spending more effort on the option mix.
|
||||
- [ ] **Freight was stuck at ~2.7 loads a game and three fixes have not moved it.** Sidings,
|
||||
facility placement, car selection and the discarded-load leak all raised revenue (3.2 → 6.5)
|
||||
without raising `loadStarted` past 2.7. The chain is not leaking and the cars are arriving
|
||||
correctly (57% of drops land on a facility that wants them, 0% on one that does not). The
|
||||
binding constraint is now upstream of routing: 60 Local Operations actions a game, and a load
|
||||
needs a stocked green box AND a spotted car AND a free Laborer to line up in the same Stage.
|
||||
Measure how many Stages have all three before changing any heuristic — the answer may be that
|
||||
the economy, not the bot, is what caps freight.
|
||||
- [ ] **`stats.ts` undercounts freight.** `rev.freightUnload` is assigned `eventCounts['unloadBegan']`
|
||||
— unloads *begun*, not revenue *earned* — and `grossFreight` uses `freightLoad` alone, so
|
||||
`freightShare` omits unload revenue entirely. The comment justifying it ("an unload scores
|
||||
through the same event as a load completion") is wrong: `apply.ts:947` emits a distinct
|
||||
`freightUnload` reason. This is why freight was recorded at 13–18% of gross.
|
||||
|
||||
---
|
||||
|
||||
@@ -45,13 +78,16 @@ target is settled and freight carries its intended share.
|
||||
of an unwinnable opening deal. Blunt: it lifts the whole ladder and dilutes every other
|
||||
category. The better answer may be fewer Terminals, a cheaper first upgrade, or more A/D
|
||||
capacity at the Whistle Post itself.
|
||||
- [ ] **Industry density** (9 → 27, Gap 12). Restored roughly the prototype ratio; freight still only
|
||||
13–18% of gross revenue.
|
||||
- [ ] **Industry density** (9 → 27, Gap 12). Restored roughly the prototype ratio. The "freight is
|
||||
only 13–18% of gross" figure that motivated this was partly a measurement bug (see the
|
||||
`stats.ts` item) and partly the car-selection bug; freight now runs at 37%. Worth re-deciding
|
||||
whether 27 is still the right number now that the industries are actually served.
|
||||
- [ ] **Train density.** Left alone by decision, but noted: 22 train cards in 140 are drawn less often
|
||||
than 22 in 115 were, and trains scheduled fell 2.9 → 2.1 as a side effect of the other density
|
||||
changes.
|
||||
- [ ] **The victory target itself** (20 over 5 Days). Still only 1 win in 100. Worth revisiting once
|
||||
the bot exploits sidings, since that is a known unclaimed gain.
|
||||
- [ ] **The victory target itself** (20 over 5 Days). 5 wins in 100, up from 1, and the bot now does
|
||||
exploit sidings — so that unclaimed gain has been claimed and the target is still missed by a
|
||||
wide margin (mean 6.0 against 20). This is the next real balance question.
|
||||
|
||||
---
|
||||
|
||||
@@ -84,6 +120,42 @@ target is settled and freight carries its intended share.
|
||||
|
||||
## Done, kept for the reasoning
|
||||
|
||||
- [x] **Put rolling stock back into circulation.** The Classification Yard was write-only — seven
|
||||
writers, no readers — so 37% of all rolling stock left the game by Day 5. Returning it at the
|
||||
Day boundary is **+2.32 ± 0.52 (t = 8.79)**, the largest single change measured on this bot,
|
||||
and it was ranked THIRD and predicted not to matter because the Division Yard never runs dry.
|
||||
The aggregate was the wrong measure; having the right commodity at the right moment is what
|
||||
counts.
|
||||
- [x] **Make Enhancements reachable at all.** The bot never laid a straight on the Running Track
|
||||
(0.00 in 100 games) because two-arc run-arounds do not need one — so 13 of the 18 Enhancement
|
||||
cards had nowhere to go, including Interlocking, the only cure for the only penalty in the
|
||||
game (`no free A/D track`, 27% of gross). One scored straight fixed it: enhancements placed
|
||||
0.64 → 3.01, collision cost 2.70 → 1.91, worst game −47 → −24. Revenue +0.70 ± 0.74 paired
|
||||
over 400 seeds — real but not significant alone; the variance reduction is the clearer win.
|
||||
- [x] **Stop the bot discarding its own freight.** `canStockProductively` did not check the Division
|
||||
Yard while the engine's `stockOutbound` does, so Freight Agent was chosen when nothing could be
|
||||
stocked and the follow-through fell through to an unjam that threw a waiting load out of the
|
||||
green box — 3.10 a game against 2.71 started. Now 0.00. Revenue 6.0 → 6.5, wins 5 → 8 in 100.
|
||||
Also confirmed **routing was never the problem**: 0% of drops land on a facility that does not
|
||||
want the car.
|
||||
- [x] **Why switching work did not become Revenue.** Answered: it was the freight the crew shuffled,
|
||||
not the shuffling. The chain never leaked — 95% of started loads finished — it was barely
|
||||
entered, because a load needs a matching empty car spotted and half the industries never asked
|
||||
for one. Three fixes later (sidings, facility placement, car selection) revenue is 3.2 → 6.0
|
||||
and freight 26% → 37% of gross.
|
||||
- [x] **Fix car selection.** Three of six industries were invisible to `wantedCars` — a hand-written
|
||||
industry→car map naming two industries that do not exist and omitting three that do — so tank
|
||||
cars were dropped **0 times in 100 games**. Derived from `INDUSTRY_PROFILES` now, and the
|
||||
second commodity of the two-commodity industries is reachable. Revenue 5.0 → 6.0, freight
|
||||
share 25% → 37%, wins 1 → 5 in 100.
|
||||
- [x] **Put the industries on the run-around.** Facility placement was unscored — the first legal
|
||||
square — so 0.00 facilities a game sat on a loop; now 1.08. The instructive part was the
|
||||
second bug: scoring facilities onto the siding row dropped run-arounds 91→36, because the
|
||||
anchor test asked a card's KIND rather than its PORTS and an industry in the line read as a
|
||||
dead end. Revenue 4.1 → 5.0. Freight did **not** follow, which is the item above.
|
||||
- [x] **Make the bot build sidings that are sidings.** 0 run-arounds in 100 games → 91. Three bugs,
|
||||
all scoring on local shape without checking it reached anything; the decisive one was that
|
||||
`bestTrackLay` never declined a piece, so it spent the track supply on whatever was legal.
|
||||
- [x] **Teach the bot what a siding is for.** Nose coupling (§A.3) implemented, so approach direction
|
||||
decides which car is droppable; the bot runs around rather than setting out, when the drop can
|
||||
follow. Switching activity transformed, revenue unchanged.
|
||||
|
||||
Reference in New Issue
Block a user