How to read this document
This project builds an economic model of the board game Catan from simulated games. It started as a rules-exact engine with six rule-based bots, then grew a playable hidden-information version and two rounds of strategy research.
Each chapter covers one change to the approach, the strategy or the tooling, in the order it happened. Every chapter links its own spreadsheet with the same tabs, so you can compare chapters side by side:
| Tab | What it holds |
|---|---|
| Bot weights | The ~35 weights of every bot that played in that chapter |
| Win rates | Win rate per bot (with 95% confidence interval), by seat where measured |
| Game stats | Game length, victory points, builds, trades and other per-game figures |
| Chapter extras | Results specific to that chapter (prices, scenario tables, validation) |
All numbers come from the project's own data in the project data folder. A 95% confidence interval (CI) is given wherever a difference matters. A gap is only treated as real when its CI excludes zero.
1Initial setup: engine, simulation and bots
The project began as a rules-exact engine for base Catan, played by six styles of one rule-based bot. Across 100,000 simulated games, balanced won most often: 32.5% against a 25% fair share.
Workbook: ch1_initial_setup.xlsx
The rules engine
- Game: base Catan for 3 or 4 players, 10 VP to win, checked only on your own turn.
- Boards: the printed beginner board, the official spiral setup, fully random, and random with no adjacent 6/8. Ports are shuffled over 9 coastal slots.
- Rules:
- snake-order setup, with the second settlement paying its resources
- discard half on a 7 when holding more than 7
- the robber must move
- one dev card per turn, never on the turn it was bought
- a bank shortage pays nobody
- piece limits
- Longest Road (5+, held on ties) and Largest Army (3+)
- Trading: bank trades at 4:1, 3:1 or 2:1. Negotiated player trades run propose → accept / reject / counter → confirm, at most 3 proposals per turn.
- Checks: 39 rule tests and a 100,000-game fuzz run with conservation invariants after every action.
Simulation style
- Perfect information: bots see every player's exact hand. Chapter 2 removes this simplification.
- Reproducible: every game is fixed by its seed, so any recorded game replays action for action.
- Parallel: the runner played about 79 games a second on 12 workers. It writes 12 Parquet tables: games, players, turns, production, trades, trade responses, bank trades, builds, dev cards, robber, discards and awards.
- Analysis: an analysis layer turns those tables into resource prices, the win value of each starting pip, strategy and seat comparisons, losses, and award effects.
The bots
All six styles are the same bot with different weights. It scores each possible build (city, settlement, expansion, Longest Road, dev card) in victory-point terms and discounts it by how many turns away it is. Every build, trade, discard and card play compares that score before and after. About 34 weights set the style:
| Style | Plan in one line | Distinctive weights |
|---|---|---|
| balanced | Default: no strong bias | all defaults |
| ore_wheat_city | Cities first | ore 1.6, wheat 1.5, city priority 1.5 |
| expansion | Roads and settlements, Longest Road | wood/brick 1.6, settlement 1.5, road 1.3 |
| dev_army | Dev cards and Largest Army | dev priority 1.8, army 1.3, knight eagerness 0.8 |
| port_trader | Ports and heavy trading | specific port 3.5, generic port 2.5, trades at zero margin |
| hoarder | Barely trades | accept greed 0.2, embargoes anyone at 7 VP |
In the dataset each game draws its four seats from these styles. Every weight gets random noise (jitter 0.15), so the data covers a continuum of play styles. An evolutionary tuner was also built. It only had a 3-generation pipeline test (32.5% on 200 validation games), not a full run.
Baseline dataset: 100,000 games
- A typical game: 73 turns (about 19 rounds), 48 trade offers of which 15.5 go through, and 20 bank trades.
- Prices: ore (1.15) and wheat (1.13) trade above the average price of 1.0. Wood (0.85) and brick (0.92) trade below it.
- Start: starting pips matter most. Win rate rises from 4% (12 pips or fewer) to 38% (25–28 pips).
- Seat: turn order matters a little, from 25.9% (1st) to 24.0% (4th).
2Live play with hidden information
The game became playable in a browser against three bots of your choice. Nobody, bot or human, can see another player's cards any more. Replaying 20,000 baseline games this way changed no style's win rate by more than 1 point, so chapter 1's results hold under real-game information.
Workbook: ch2_hidden_information.xlsx
What changed
- Playable game: python cli.py play-human opens a browser game on 127.0.0.1:8765. You pick your seat, three bots, the board type and a seed. The rules engine and bots are chapter 1's.
- Bots count cards instead of seeing hands:
- Each bot follows only the events it could observe. Two things are private: a steal's resource (seen by the thief and the victim) and a bought dev card's type (seen by the buyer).
- It keeps every combination of opponent hands still consistent with what it saw. In 30 test games, these always included the true hands.
- It decides on its own copy of the game: opponents hold the most likely hands, unseen dev cards are sampled, and the dice are reshuffled.
- The browser only ever receives your own cards plus public information, and every hand is revealed when the game ends.
- Rule change for hidden hands: a counter-offer is checked only against the responder's own cards. The proposer can only accept counters it can pay.
- Robustness:
- Bots think outside the server lock with a 5-second limit.
- A bot that crashes or overruns plays a safe move.
- Every problem is saved as a replayable report.
This fixed a "bot stuck deciding" freeze in live play.
- Measurement: the first 20,000 baseline games were replayed with hidden hands, using the same seeds, so each game has the same board, lineup and bot weights.
Results: the same 20,000 games, with and without hidden hands
| Style | Perfect information | Hidden hands | Change (95% CI ±) |
|---|---|---|---|
| balanced | 32.3% | 31.9% | −0.5 pts (±1.1) |
| dev army | 28.5% | 28.6% | 0.0 pts (±1.1) |
| ore/wheat city | 25.8% | 26.6% | +0.8 pts (±1.1) |
| hoarder | 24.7% | 25.0% | +0.3 pts (±1.0) |
| expansion | 20.0% | 19.8% | −0.2 pts (±1.0) |
| port trader | 18.5% | 18.1% | −0.4 pts (±0.9) |
- Same game: game length is unchanged (73.34 vs 73.36 turns), and resource prices move by less than 0.005.
- Trading is slightly less efficient: bots make a few more offers (49.1 vs 48.3 per game) and complete slightly fewer trades (15.4 vs 15.5), because they can't see who is able to accept.
- Fast enough to play against: a bot decision takes about 0.3–2 ms.
3Reactive strategy, stage 1: pick a style before setup
Choosing a style before placement, from the board and the seat, did not beat simply playing balanced. On fresh boards the reactive bot gained +0.4 points (95% CI −0.7 to +1.4), and with hidden hands it lost −1.0 points (−3.0 to +0.8).
Workbook: ch3_reactive_stage1.xlsx
What changed
- Question: does the best style depend on the scenario, meaning the board's resource scarcity, which resources sit on 6 and 8, port placement, and seat?
- Method: a controlled experiment, the strategy lab. A scenario is a board, a seat and three opponents. Every style plays that same seat with the same dice and opponents (common random numbers), 6 times. That's 4,000 scenarios and 144,000 games, all with perfect information for speed.
- New bot: the reactive bot. One regression per style predicts its win chance from 22 board-and-seat features. The bot picks the best style before placing and plays it all game.
- Validation: the bot was tested on fresh boards, against all six styles in the same seat: 84,000 games with perfect information and 28,000 with hidden hands.
Results
| Measure | Reactive | Balanced | Difference (95% CI) |
|---|---|---|---|
| Held-out scenarios from the lab | 35.9% | 35.7% | +0.1 pts (−0.5 to +0.8) |
| Fresh boards, perfect information | 35.9% | 35.5% | +0.4 pts (−0.7 to +1.4) |
| Fresh boards, hidden hands | 34.7% | 35.7% | −1.0 pts (−3.0 to +0.8) |
- Balanced wins everywhere: 34–37% in every seat, scarcity, 6/8 and port bucket. The ranking matched chapter 1: balanced 35.5%, dev army 30.9%, ore/wheat city 28.3%, hoarder 26.5%, expansion 21.4%, port trader 20.1%.
- Board context shifts the specialists by about 3 points, never enough to overtake balanced:
- Plentiful ore lifts dev army from 29.8% to 32.9% and drops expansion from 23.4% to 20.0%.
- Plentiful brick does the opposite.
- Seat matters a little for every style: the 4th seat loses 1.5–4 points.
- So the policy plays balanced about 90% of the time, and dev army most of the rest.
What it pointed to
The scenario edge is real but not where we looked:
- Real signal exists. About 15% of the scenario-to-scenario differences repeat between halves of a scenario's games.
- Our features miss it. Board-wide features explain only about 1.5% of those differences.
- Placement drives it. Each pip of starting production is worth about 2.6–3.6 points of win rate:
- Port trader usually settles about 3.8 pips poorer than balanced, and then loses by 17 points.
- In the 9% of scenarios where it picked the same spots as balanced, it won by 2.1 points.
That finding set up chapter 4.
4Reactive strategy, stage 2: re-plan after setup
Placing like balanced and then switching to port trader's trading style beats balanced: +2.0 points on fresh boards (95% CI +1.3 to +2.7), and +1.5 with hidden hands (+0.2 to +2.8). It is the first bot to clearly beat balanced.
Workbook: ch4_reactive_stage2.xlsx
What changed
- Question: once a player's actual starting position is known, which style should play the rest of the game?
- Placement fixed: everyone places as balanced, the best placer in chapter 3.
- Method: a fork experiment. Setup is played once, then the game is copied. Each style continues from the identical position, with identical opponents and dice, over 4 dice continuations. That's 6,000 positions and 144,000 games.
- Models: two models predict each style's gain over balanced from about 40 position features:
- production and ports
- the share of each resource the player controls
- opponents' production
- room to expand
- seat
The models are a ridge regression and gradient-boosted trees. They're chosen by cross-validation on win rate, and the policy only switches style when the predicted gain clears a threshold.
- New bot: the re-plan bot places exactly like balanced, then re-chooses its style on its first decision after setup.
- Validation: it played balanced on fresh boards in the same seat: 48,000 games with perfect information and 16,000 with hidden hands.
Results
| After the same balanced setup, continue as | Win rate | Edge over balanced (95% CI) |
|---|---|---|
| port trader | 36.7% | +1.3 pts (±0.8) |
| balanced | 35.4% | — |
| expansion | 30.7% | −4.6 pts |
| dev army | 28.4% | −7.0 pts |
| ore/wheat city | 27.7% | −7.6 pts |
| hoarder | 26.9% | −8.4 pts |
| Validation on fresh boards | Re-plan bot | Balanced | Difference (95% CI) |
|---|---|---|---|
| Perfect information (24,000 paired games) | 37.2% | 35.2% | +2.0 pts (+1.3 to +2.7) |
| Hidden hands (8,000 paired games) | 37.6% | 36.1% | +1.5 pts (+0.2 to +2.8) |
- Port trader's play is good; its placement was bad. It came last in chapters 1 and 3 only because it settles for ports over production. With balanced placement, its eager trading is the best continuation in almost every kind of position.
- Staying balanced is better with a 2:1 sheep or wheat port, a 3:1 port, or the 3rd-richest start.
- Once placement is fixed, the position barely matters. Only 0–5% of the position-to-position differences repeat, against about 15% in chapter 3. The true spread of dev army's edge fell from about 11 points to 0.2.
- The models confirm it: neither found anything beyond "switch to port trader" on held-out positions (R² about 0).
- So the re-plan bot switches to port trader about 94% of the time.
The lesson: a style's result is mostly decided by where it settles, and much less by how it plays afterwards.
5Reactive strategy, stage 3: hybrid tuning
Placing like balanced and then playing with evolved weights wins about 45% of games against the usual field. That is +9.6 points over balanced with hidden hands (95% CI +8.3 to +10.8) and +9.2 with perfect information (+7.9 to +10.6), several times chapter 4's gain.
Workbook: ch5_hybrid_tuning.xlsx
What changed
- Question: chapter 4 showed the gains are in how a bot plays after setup. How much more is there if the play weights are tuned directly instead of borrowed from a preset?
- New bot: the hybrid bot places with balanced's weights, then switches to its own play weights on its first decision after setup.
- Method: the evolutionary tuner changed the play weights only. 20 candidates × 480 games × 25 generations = 240,000 hidden-hand games against the same jittered six-preset field as chapters 3 and 4. The start population was port trader (the stage-2 winner), the other presets and mutated copies.
- Selection: the last generation's top 4 were re-tested on 4,000 fresh games each. The best (45.1%) became "tuned".
- Validation: on 2,000 fresh scenarios × 4 repeats, balanced, the stage-2 bot (balanced setup, port trader play) and tuned played the same seat with the same dice. That's 24,000 games with perfect information and 24,000 with hidden hands.
Results
| Validation on fresh boards | Balanced | Stage 2 (balanced → port trader) | Tuned | Tuned − balanced (95% CI) | Tuned − stage 2 (95% CI) |
|---|---|---|---|---|---|
| Perfect information (24,000 games) | 35.6% | 36.9% | 44.8% | +9.2 pts (+7.9 to +10.6) | +7.9 pts (+6.6 to +9.4) |
| Hidden hands (24,000 games) | 35.5% | 35.6% | 45.1% | +9.6 pts (+8.3 to +10.8) | +9.4 pts (+8.1 to +10.8) |
- The gain is real, not tuner luck. The median candidate rose from 29.4% in generation 0 to 45.0% in generation 24, and fresh seeds give the same 45%.
- It holds with and without hidden hands. The tuner trained only on hidden-hand games, and the edge carries over to perfect information almost unchanged.
- The tuned bot wins faster: 70.7 turns against 72.2 for balanced, and 8.38 VP on average against 7.95.
- Stage 2 replicated weaker. On these fresh seeds the stage-2 bot gained +1.3 pts (−0.1 to +2.6) with perfect information and +0.1 (−1.1 to +1.4) with hidden hands, against +2.0 and +1.5 in chapter 4. Its true edge is probably about 1 point.
What the tuner changed
It kept port trader's eager trading and made it an eager builder: every build priority roughly doubled, and it stopped valuing cards held in hand.
| Weight | Port trader | Tuned | What it means |
|---|---|---|---|
| City priority | 1.00 | 1.99 | Values building a city twice as much |
| Settlement priority | 1.00 | 1.91 | Same for settlements |
| Road priority | 0.80 | 1.58 | Same for expanding by road |
| Dev card priority | 0.80 | 1.50 | Buys development cards more readily |
| Production weight | 1.00 | 1.75 | Credits a build more for its future income |
| Horizon | 20 turns | 9 turns | Counts income over a shorter future |
| Patience (tau) | 3.0 | 2.0 | Discounts builds it can't afford soon more steeply |
| Card value | 0.03 | 0.00 | Cards in hand are worth nothing in themselves |
| Diversity weight | 0.5 | 1.4 | Prefers new spots that add resources it lacks |
| Bank/port trade minimum gain | −0.01 | +0.06 | Trades with the bank only for a real gain |
| Monopoly minimum | 4 cards | 7 cards | Saves Monopoly for a big haul |
| Longest Road drive | 0.50 | 0.20 | Chases Longest Road less |
| 2:1 port weight | 3.5 | 2.0 | Values new 2:1 ports less |
Player trading stayed at port trader's settings or got slightly more generous (it still tries a trade every turn and counters 99% of the time).
One caveat: the tuned bot was trained and tested against the six presets. It has not yet been tested against copies of itself, so part of its edge may come from exploiting how the presets play. Chapter 6 tests this.
6Robustness test: the tuned bot against other fields
The tuned bot's edge is not an exploit of the presets. Against copies of itself it still beats balanced by +8.0 points (95% CI +6.8 to +9.2), and it gains 8–10 points in every field tested.
Workbook: ch6_tuned_robustness.xlsx
What changed
- Question: chapter 5's bot was trained and tested only against the six presets. Does its edge hold against other opponents, above all against itself?
- Method: the same three bots as chapter 5 (balanced, the stage-2 bot, tuned) played the same seat of fresh scenarios with the same dice, against three new opponent fields. Each field is 2,000 scenarios × 4 repeats × 3 bots = 24,000 hidden-hand games, 72,000 in all.
- Fields: three copies of the tuned bot (self-play); three balanced bots; and a mix where each opponent is the tuned bot half the time, otherwise one of the six presets. Opponents get the usual 15% weight jitter.
- Tooling: the strategy lab now accepts any bot as an opponent. A jittered hybrid bot jitters only its play weights, so it still places exactly like balanced.
Results
| Opponent field (hidden hands) | Balanced | Stage 2 | Tuned | Tuned − balanced (95% CI) | Tuned − stage 2 (95% CI) |
|---|---|---|---|---|---|
| Six presets (chapter 5) | 35.5% | 35.6% | 45.1% | +9.6 pts (+8.3 to +10.8) | +9.4 pts (+8.1 to +10.8) |
| All tuned (self-play) | 19.0% | 20.4% | 26.9% | +8.0 pts (+6.8 to +9.2) | +6.6 pts (+5.4 to +7.8) |
| All balanced | 28.0% | 29.3% | 38.2% | +10.2 pts (+8.8 to +11.6) | +8.9 pts (+7.6 to +10.2) |
| Half tuned, half presets | 25.7% | 27.4% | 34.1% | +8.5 pts (+7.2 to +9.7) | +6.8 pts (+5.5 to +8.1) |
- Self-play is the key test, and it passes. Against three tuned opponents, balanced falls to 19.0%, well under the 25% fair share, while the tuned bot wins 26.9%. A strategy that only exploited the presets would lose this edge in self-play.
- The edge shrinks a little as the field gets stronger: about +10 points against balanced bots, +8 against tuned bots.
- Stage 2's gain is real but small. It beat balanced in all three new fields, by +1.3 to +1.7 points, each CI above zero.
7MCTS bot
Adding search on top of the tuned bot has not beaten it yet. The best version ties it with hidden hands (43.3% each, difference +0.0 points, 95% CI −4.7 to +4.8). The first version lost 6.5 points because its simulations assumed every opponent plays like the tuned bot.
Workbook: ch7_mcts_bot.xlsx
What changed
- New bot: the MCTS bot places, trades, discards and moves the robber exactly like the tuned bot. In the main phase it searches over the tuned bot's move, ending the turn, every affordable city and settlement, buying a dev card, the tuned bot's target roads and playable dev cards.
- Search: each candidate is scored by short simulations (rollouts) in which everyone plays the tuned weights, then a value model estimates who wins. Candidates are compared on the same dice and dev-card draws, and the bot leaves the tuned move only when the best candidate beats it by a margin.
- Value model: a conditional logit on 22 features per player (VP, income per resource, buildings, dev cards, cards in hand, expansion spots, turn order). It was fitted on 706,000 positions from 20,000 games. On held-out games it picks the eventual winner 54% of the time, against 45% for VP alone.
- Speed: a game with one MCTS bot takes 20 s (version 1) to 90 s (version 2) on one core, against 0.1 s for the tuned bot.
Results
| Run (hidden hands unless noted) | Search settings | Tuned | MCTS | MCTS − tuned (95% CI) |
|---|---|---|---|---|
| Version 1, perfect information (600 pairs) | opponents modelled as tuned; 8-turn rollouts, 48 per decision | 43.2% | 39.0% | −4.2 pts (−8.8 to +0.7) |
| Version 1 (600 pairs) | same | 42.3% | 35.8% | −6.5 pts (−11.5 to −1.8) |
| Version 2 (600 pairs) | opponents drawn from the six presets; 16-turn rollouts, 96 per decision | 43.3% | 43.3% | +0.0 pts (−4.7 to +4.8) |
- The opponent model was the main problem. An audit replayed each decision where the search overrode the tuned move, using 150 full games against the opponents' real weights. With opponents modelled as tuned, the overrides cost 1.1 win points each, about 12 times a game. Drawing opponents from the six presets brought this to −0.1.
- More and longer rollouts helped: with 16-turn rollouts and 96 per decision, the audit put the overrides at +1.0 point each. That gain did not show up in the paired games, whose CI is still ±4.8 points.
- Ending the turn is the riskiest override. Turning down a trade offer or a road to end the turn was negative in almost every audit.
8MCTS override guards
Requiring an override to be statistically significant turned the MCTS bot from a tie into the best bot so far: it beats tuned by 11.8 points (CI +7.3 to +16.5) with hidden hands.
Workbook: ch8_mcts_guards.xlsx
What changed
- Profiling first: a rollout takes about 32 ms, more than 99% of it the bots' own play. Player trading is about two-thirds of that time, and rebuilding each player's profile about 43%. The value model and copying the state cost almost nothing.
- Guard 1, skip trade steps: when the tuned bot wants to propose a trade or trade with the bank, the MCTS bot plays it without searching. The build decision that follows is still searched.
- Guard 2, significance test (z ≥ 2): the bot leaves the tuned bot's move only if the paired gain is at least 2 standard errors above zero, not just above the 0.02 margin. The tuned bot's move now stays in the search to the end, so the test sees every rollout.
- Same setup as version 2 otherwise: 96 rollouts of 16 turns per decision, opponents drawn from the six presets, the same seed, boards and field as the version 2 run. Both guards are off by default, so earlier runs reproduce exactly.
- Second machine: the 2,400 games ran on a 16-thread desktop (Python 3.14) in 63 minutes. Its 600 tuned games match the laptop's version 2 run game for game, so the two runs can be paired.
Results
| Bot (600 pairs each, hidden hands) | Guards | Win rate | − tuned (95% CI) | − version 2 (95% CI) |
|---|---|---|---|---|
| Tuned | — | 43.3% | — | — |
| Version 2 (chapter 7) | none | 43.3% | +0.0 pts (−4.7 to +4.8) | — |
| Skip trade steps | 1 | 48.2% | +4.8 pts (+0.2 to +9.3) | +4.8 pts (+0.2 to +9.5) |
| Significance test | 2 | 55.2% | +11.8 pts (+7.3 to +16.5) | +11.8 pts (+7.5 to +16.7) |
| Both | 1 + 2 | 50.0% | +6.7 pts (+2.5 to +10.8) | +6.7 pts (+2.0 to +11.7) |
- Most of version 2's overrides were noise. With a fixed 0.02 margin, about 11 overrides a game went through on a handful of paired rollouts. Demanding significance keeps only the clear ones, and that alone is worth about 12 points.
- Skipping trade steps helps alone but hurts with the test. The significance test beats both guards together by 5.2 points (CI +0.5 to +9.8). Once noise is filtered, some trade-step overrides seem to be real gains. Which ones is not yet known; an override audit of the significance-test bot would show it.
- VP moves the same way: the significance-test bot scores 0.28 VP more than tuned per game (CI +0.14 to +0.43); version 2 scored 0.20 less.
- Caveat: five bots and ten comparisons were looked at, so the narrow differences (+0.2 and +0.5 at the CI edge) are the least certain. The +11.8 points against tuned holds well beyond that.
9What makes tuned beat balanced
Tuned's edge is built in the early and mid game from a few habits: building roads instead of ending the turn, proposing more player trades, and holding monopoly cards for a bigger payoff. Two are general rules that pay every time: build the road rather than end the turn, and propose a trade rather than end the turn. The others depend on the moment. Only monopoly can be predicted, by a 7-card threshold.
Workbook: ch9_decision_attribution.xlsx
What changed
- New analysis tool, no new bot: python cli.py attribute plays tuned in the focal seat. At every decision it also asks a shadow balanced bot what it would do. Where they disagree, both moves are scored by 32 full-game rollouts each, on the same dice, with balanced playing on.
- The scores add up to the edge: summed per game, the decision values give +10.1 pts (CI +5.8 to +14.5), matching tuned's measured +9.2 with full information. So the breakdown accounts for the whole edge.
- Noise handled: a single decision's value is very noisy, so each decision's rollouts are split into two independent halves. Ranking on one half and measuring on the other gives honest concentration numbers.
- Scale: 600 games, 23,911 scored decisions (40 disagreements out of 131 decisions per game), about 1.5 million rollouts. It ran on the second machine in 49 minutes.
Results
| Balanced would … → tuned does … | Times per game | Edge (pts per game) | Value each time | Tuned's move better | Linked tuned weight |
|---|---|---|---|---|---|
| End the turn → build a road | 1.3 | +3.3 | +2.6 | 87% | road priority ×2.0 |
| End the turn → propose a trade | 8.6 | +2.9 | +0.3 | 57% | offers trades slightly in the partner's favour; counters ×2 |
| Trade with the bank → propose a trade | 2.4 | +2.0 | +0.8 | 59% | same |
| Play monopoly → end the turn | 0.7 | +1.9 | +2.5 | 65% | plays monopoly only for ≥7 cards, not ≥4 |
| Propose a trade → build a road | 1.0 | +1.3 | +1.3 | 57% | road priority ×2.0 |
| End the turn → trade with the bank | 0.9 | +1.2 | +1.3 | 59% | — |
- The clearest general rule: building the road instead of ending the turn is better about 87% of the time, and its value is spread evenly across games. That is a habit, not a lucky moment.
- Most of the rest depends on the moment. The bank-trade, road-versus-trade and monopoly choices are better only 57–65% of the time (proposing a trade instead of ending the turn turned out to be a small general rule; see below). Their small average hides a wide spread: one instance can be worth ±7 pts.
- Big decisions go both ways. The 10% of decisions that look best carry +11.5 pts per game; the worst 10% cost −6.5. Tuned makes real mistakes too, mostly in the same kinds of decisions as its best moves. The middle 80% add a steady +7.2.
- Built early, not at the finish. The early game (≤4 VP) gives +6.6 pts and the mid game +4.1. The late game (≥8 VP) gives −0.6, so tuned does not win at the critical endgame decisions.
- When isn't predictable from basic features. Within each kind, VP, hand size, income, turn and buildings left don't predict which instances pay off (held-out correlation about 0). The richer features are below.
General rule or the moment? (richer features)
About half of tuned's edge comes from two general rules and half from decisions whose value depends on the moment. Among the moment-dependent ones, only the monopoly choice can be predicted, by how many cards it would take.
Replaying the 600 games added 77 features per decision: hand by resource, what the hand affords, expansion room, the road and army races, the robber, and what each move does (whether a trade completes a build, whether a road opens settlement room, the cards a monopoly would take). Every replayed move matched the stored one.
| Kind (balanced → tuned) | Edge (pts per game) | Type | Features explain |
|---|---|---|---|
| End the turn → build a road | +3.3 | General: +2.6 every time | — |
| End the turn → propose a trade | +2.9 | General: small (+0.3) but every time | — |
| Trade with the bank → propose a trade | +2.0 | Situational | 0% |
| Play monopoly → hold it | +1.9 | Situational | 10% |
| Propose a trade → build a road | +1.3 | Situational | 0% |
| End the turn → trade with the bank | +1.2 | Situational | 0% |
| Choose a different trade partner | −0.4 | Situational | 3% |
- General means no detectable difference in value from one instance to the next. Situational means the value really varies, measured by whether the two independent halves of rollouts agree.
- Monopoly has a clear threshold. Holding it is worth +3.1 to +3.6 pts when it would take 6 cards or fewer, and playing it is right at 7 or more. That is exactly tuned's monopoly_min of 7, against balanced's 4.
- Completing a build matters across all kinds of decision. When tuned's move (a trade, bank trade or partner choice) completes a build and balanced's doesn't, it gains +0.5 pts per decision (CI +0.2 to +0.8). In the reverse case it loses −0.3.
- Building a VP piece or opening settlement room also pays across kinds: +3.0 and +2.0 pts per decision.
- The other situational kinds stay unexplained. For the trading choices, which offer to make and whether to trade with a player or the bank, none of the 77 features (and no nonlinear model of them) predicts the value. Their value likely depends on what the opponents do next, which isn't in the state at decision time.
Next: the same analysis on the MCTS significance-test bot against tuned, to see whether the search finds the moments the habits miss. Then parameter ablations (tuned with one weight set back to balanced) to confirm which weights cause each habit.
Across all chapters
Eight changes and about 987,000 simulated games later, the best bot places like balanced and then plays with evolved weights. It beats balanced by about 9 points with or without hidden hands, and by 8 points against copies of itself. An MCTS search on top of it, which overrides the tuned move only when the gain is significant, beats it by another 12 points. Borrowing port trader's play (chapter 4) gained 1–2 points, and reacting to the board before placement did not help.
| Chapter | What changed | Games simulated | Headline result |
|---|---|---|---|
| 1 Initial setup | Engine, six bot styles, perfect-information dataset | 100,000 | Balanced wins 32.5% (fair share 25%) |
| 2 Hidden information | Browser play; bots count cards instead of seeing hands | 20,000 | No style moves more than 1 pt |
| 3 Reactive, stage 1 | Pick a style before setup from board and seat | 256,000 | +0.4 pts, not significant |
| 4 Reactive, stage 2 | Balanced placement, re-plan after setup | 208,000 | +2.0 pts (CI +1.3 to +2.7) |
| 5 Reactive, stage 3 | Balanced placement, evolved play weights | 304,000 | +9.6 pts hidden hands (CI +8.3 to +10.8) |
| 6 Robustness test | Tuned bot against self-play, balanced and mixed fields | 72,000 | +8.0 pts in self-play (CI +6.8 to +9.2) |
| 7 MCTS bot | Root search with rollouts and a learned value model, on top of the tuned bot | 24,200 (+ search rollouts) | Ties tuned: +0.0 pts (CI −4.7 to +4.8) |
| 8 MCTS override guards | Override only on a significant gain; optionally skip trade steps | 2,400 (+ search rollouts) | +11.8 pts vs tuned (CI +7.3 to +16.5) |
| 9 Decision attribution | Analysis: which decisions make tuned beat balanced | 600 (+ 1.5M rollouts) | Edge built early; only the road habit is a general rule |
Win rates inside chapters 3 to 5 run higher than in chapters 1 and 2: the tested bot plays exact weights against jittered opponents. So compare bots within a chapter, not across chapters.
Next step: run the chapter 9 attribution on the MCTS significance-test bot against tuned, and run parameter ablations to confirm which weights cause each habit.
Every chapter keeps a spreadsheet with the same tabs (bot weights, win rates, game stats, chapter extras). The workbooks are not online yet; ask for them by name.