fix tracks to all be EW. no more NS tracks
This commit is contained in:
@@ -10,6 +10,87 @@ The target is 20 Revenue over 5 Days.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### The track is 45° geometry, drawn from the printed cards
|
||||
|
||||
The prototype designer's feedback: **there are no north–south tracks.** Straight runs are always
|
||||
east–west, the east–west line sits dead centre on the card rather than biased to the top, and a
|
||||
turnout is an east–west through track plus a curved leg meeting the north or south edge at 45°, which
|
||||
must line up with the corresponding leg on the card it abuts.
|
||||
|
||||
Measured off `docs/tracks.png` rather than inferred. Card grid lines at y = 15/164/314/464/614/764/
|
||||
914/1064/1213 on a 2136×1397 sheet; rail centres at 89.5/236/–/–/689.5/839/989/1135.5/1288.5 — the
|
||||
card's exact vertical middle, within a pixel, on every one of the nine rows. Cards are 259×150
|
||||
(aspect ≈ 1.73). Every leg crosses the middle of its edge. Four shapes exist: turnout with the leg
|
||||
off the west end, turnout with the leg off the east end, curve west↔south, curve east↔south, plus the
|
||||
plain straight. Depot, Station, Terminal, Refinery, Freighthouse, Coal Tipple, Manufacturing and Town
|
||||
are all plain east–west straights with **no diverging leg at all**.
|
||||
|
||||
**Slope is now part of adjacency.** Name the two diagonals after the pair of arcs that mate across a
|
||||
horizontal card edge: `ne_sw` (port pairs {n,e} and {s,w}) and `nw_se` ({n,w} and {s,e}). An `sw` card
|
||||
above an `ne` card is one unbroken rail; `sw` above `nw` is a V — both cards have the port, both legs
|
||||
meet the same point on the edge, and they still do not connect. `joins(a, p, b)` in
|
||||
`src/engine/track.ts` is the single adjacency test, and every `hasPort(nb, opposite(p))` in the
|
||||
engine, the bot and the tests now goes through it. Leaving one behind reintroduces the V.
|
||||
|
||||
**Handedness is that diagonal.** A printed card has a back: it turns 180° but never flips. So a
|
||||
straight has ONE orientation, and a curve or turnout has two — 0° sends the 45° leg south, 180° sends
|
||||
it north, and neither changes diagonal. Left-hand reaches `sw`/`ne`, right-hand `se`/`nw`. That is
|
||||
what makes the 4-left/4-right split of the curve and turnout supply mean something: a run-around needs
|
||||
one card of each hand — a left turnout down, its matching left curve, straights along, a right curve
|
||||
back up into a right turnout. `variantsFor` takes a `hand` argument for this reason.
|
||||
|
||||
**What went, and what opened.** `TrackAxis` and every `axis` field are deleted outright — there is
|
||||
one axis now, and a one-valued field invites the old branching back; deleting it turned `tsc` into
|
||||
the migration checklist. The Office's `e-s`/`w-s` stubs are gone, as are north–south facility
|
||||
placements. Q7's "a district hangs below the Running Track" is lifted: a turnout turned 180° reaches
|
||||
north, so `placementCandidates` and `adjacentFacilityCoord` no longer reject the rows above, and §9's
|
||||
"nine nearby spots" really is nine. `legalIntents` offered six variants per placement per card; the
|
||||
widest set is now two.
|
||||
|
||||
**The renderer draws the card rather than approximating it.** `RAIL` moves from 30 to `H/2`, and the
|
||||
card widens from 132×96 to 166×96 to match the sheet's 1.73 — the aspect is not decoration, since the
|
||||
frog where a 45° leg meets the through track sits `H/2` from the centre and a squarer card pushes it
|
||||
almost to the edge. The fixed elbow at `(W/2, RAIL + (H-RAIL)/2)` is replaced by the real frog at
|
||||
`(W/2 ± H/2, H/2)` and a segment at exactly 45° to the edge midpoint. That elbow sat *below* the rail
|
||||
on the assumption everything diverged downward, so a leg reaching north was drawn as a hook that
|
||||
dropped past the rail and came back up. Four tests in `test/web.test.ts` now measure the emitted SVG:
|
||||
the through rail level and centred and spanning the full card, every leg at 45°, `ne`/`sw` on one
|
||||
diagonal and `nw`/`se` on the other, and the leg crossing the edge at its midpoint. The enhancement
|
||||
label moved above the rail, where it used to print along it.
|
||||
|
||||
**Measured, 100 solitaire Standard games, against the same run before the change:**
|
||||
|
||||
| | before | after |
|
||||
| --- | ---: | ---: |
|
||||
| mismatched 45° joints on finished boards | — | **0** |
|
||||
| district size | 25.4 cards | 28.5 |
|
||||
| mean max depth off the main | 2.38 rows | 1.45 |
|
||||
| built above the Running Track | 0/100 games | 93/100 |
|
||||
| straights laid | 1.01/game | 3.44 |
|
||||
| districts with a run-around | 99/100 | 70/100 |
|
||||
| facilities on a run-around | 0.82/game | 0.51 |
|
||||
| revenue | 7.34 mean | 5.80 |
|
||||
|
||||
The shallower districts are intrinsic: no card joins north to south, so descending a row costs at
|
||||
least two cards — the leg out, then a curve turning the run back east–west. Districts are now wide
|
||||
and shallow, which is what the printed sheet and a real yard both look like, and the run along the
|
||||
siding is straights, which is why the bot lays three times as many (13 of the 18 enhancement cards
|
||||
need one).
|
||||
|
||||
**The revenue and run-around drops are honest, not a regression to chase.** A run-around costs more
|
||||
pieces than it did, and the Office no longer offers a free way back up onto the main — it used to
|
||||
carry `e-s`/`w-s` stubs, so every district had one guaranteed climbing point. Two bot heuristics were
|
||||
tried against it and both rejected on measurement: preferring one side of the main changed nothing at
|
||||
−4 and made things worse at −100 (62/100 run-arounds), and paying more for the second turnout that
|
||||
closes a siding bought 86/100 run-arounds and 1.08 facilities on a loop but cost 9% of revenue
|
||||
(5.80 → 5.25). Revenue is the game's own measure, and both structural floors in `test/sim.test.ts`
|
||||
still pass, so neither shipped.
|
||||
|
||||
The bot is otherwise rewritten around the new geometry: `descendFrom`/`waysOff`/`reachableOffMain`/
|
||||
`runAroundCells` take a side rather than assuming "below", the arc score asks `joins` instead of
|
||||
reading the arc name, and `arcsLeft` is asked per hand — a left-hand turnout's leg can only be
|
||||
continued by a left-hand curve, and a supply full of right-hand ones is no help to it.
|
||||
|
||||
### Q13 — a train that catches the one ahead runs into it
|
||||
|
||||
Answered, and implemented as option B: **collide on catching up**, which is the version that rewards
|
||||
|
||||
Reference in New Issue
Block a user