feat: Cards writings and balancing (M8)
This commit is contained in:
+12
-3
@@ -169,7 +169,7 @@ A weighted score over the indicators averaged across the whole term (not just fi
|
||||
- **How a card is drawn** (`engine/cards.js`): start from all cards whose conditions are met and that haven't been used. Weight each one by `weight` × a category boost (a sector below quality 40 makes its category up to 2× likelier) × a novelty factor (0.4 per card of the same category among the last 3). Follow-ups that are due take priority over random draws. With no eligible card the week is simply empty and the game is not blocked.
|
||||
- **Fields beyond the schema above**: `once` defaults to true; `once: false` makes a card repeatable with `cooldownDays` (default 180); `followUpOnly: true` keeps a card out of random draws so it only appears through a `followUp`. Condition stats are any indicator, `growth`/`unemployment`/`inflation`, `debt` and `deficit` (% of GDP) and `q:<sector>` (sector quality). Options can also `clearFlags`. Every pending card is saved in `state.pendingCard`, so a reload shows the same card.
|
||||
- **Effect size guide** used for the first 64 cards: instant or spread shifts of 1–6 points on indicators, lasting `bias` effects of 1–5 over 180–730 days, sector quality shifts of 2–6 over 60–365 days, one-off costs of 0.1–1.5 % of GDP (negative = windfall), `extraSpending` of 0.1–1.0 % of GDP, tax rate changes of 2–4 points. Every option has a cost; there is no free choice.
|
||||
- **Target count per category** (about 920 in total): economy 100, social 70, health 60, education 60, police/security 70, army/defense 60, foreign/diplomacy 70, industry/energy 70, transport/infrastructure 60, housing 40, environment 50, justice/civil rights 60, culture/media 40, crises 50.
|
||||
- **Target count per category** (about 860 in total; the figures below add up to 860, not 920): economy 100, social 70, health 60, education 60, police/security 70, army/defense 60, foreign/diplomacy 70, industry/energy 70, transport/infrastructure 60, housing 40, environment 50, justice/civil rights 60, culture/media 40, crises 50.
|
||||
- **How the content gets written**: Sonnet writes it in batches of about 40 cards per category file, in English and French. After each batch, `go test ./server` checks the schema, that ids are unique, that both languages are present, that follow-up ids exist, and that effect stats are valid.
|
||||
|
||||
## Desk UI (Suzerain-like)
|
||||
@@ -205,8 +205,9 @@ A weighted score over the indicators averaged across the whole term (not just fi
|
||||
- [x] **M4 Cards**: draw engine, decision folder and stamps, follow-ups; first 60 cards (EN/FR) across all categories; `content_test.go`. 64 cards written (62 draw at random, 2 follow-up only), 14 categories, 20 senders.
|
||||
- [x] **M5 Crises and endings**: unrest and army loyalty, crisis telegrams, the 4 game overs, the 5-year review with historian titles. Also the pronoun question at the start of a game.
|
||||
- [x] **M6 Saves and menu**: auto-save, slots, export/import string and file, main menu, settings, language switch. Sound is not in the settings yet because the game has no sounds (M8, optional).
|
||||
- [ ] **M7 Content production**: grow the card pool to at least 800 cards in batches by category, plus 50 crisis cards and the follow-up chains.
|
||||
- [ ] **M8 Balance and polish**: sim.html runs 200 games per strategy (random, austerity, spendthrift, police state, balanced). Targets: random play fails about 40–60 % of runs, balanced play survives. Then animations, optional sounds, and a second scenario.
|
||||
- [x] **M7 Content production**: grow the card pool to at least 800 cards in batches by category, plus 50 crisis cards and the follow-up chains. Done: 864 cards, 117 of them follow-up-only, about 100 chains. Tools: `tools/add-cards.mjs`, `tools/card-stats.mjs`, `tools/cardfmt.mjs`, guide in `docs/CARD-WRITING.md`.
|
||||
- [x] **M8 Balance**: the difficulty is now measured and gated. Passive play is risky, a balanced plan wins, bold play pays up to a point and extremes end in a fall. Tools `tools/balance-check.mjs` (with `--check`), `balance-search.mjs`, `bal-edit.mjs`; guide in `docs/BALANCE.md`.
|
||||
- [ ] **M8b Polish (optional)**: animations, sounds (typewriter, stamp, telegraph; off by default), a second scenario, a repo README.
|
||||
|
||||
## Verification
|
||||
- `docker compose up --build` → open http://localhost:8080. Check that the menu loads, a new game starts, days advance at 10 s, and 4× speed works.
|
||||
@@ -245,3 +246,11 @@ A weighted score over the indicators averaged across the whole term (not just fi
|
||||
- 2026-10-25 (M6): The language button left the calendar (replaced by a Menu button); language lives in Settings, in the main menu and the pause menu, and is remembered. With no saved choice the browser language decides (French if it starts with fr). Time does not run while the menu is open. Space, 1-3 and Escape work in game; the menu has its own Escape (back, or resume).
|
||||
- 2026-10-25 (M6): The decision panel's keyboard listener leaked every time the panels were rebuilt (language change since M4); it is now removed when the panels are rebuilt. On load, `restoreState` also keeps the alert pause flag consistent with the alert queue.
|
||||
- 2026-10-25 (M6): New tests. `tools/engine-check.mjs` covers the codec (round trip, whitespace, CRC reference value, UTF-8, every kind of damage, versions and migrations), 23 kinds of invalid or tampered saves, repair of stale references, a restored game continuing identically, and storage (slots, settings, missing, throwing and full storage). `server/ui_content_test.go` checks that en.json and fr.json have identical keys and placeholders and that the scenario index matches the files. The menu was exercised in a real browser: new game, continue after reload with the same waiting card, slot save and overwrite, export, import (valid, tampered, garbage, empty), settings, load and delete with confirmation, and the game-over cleanup.
|
||||
- 2026-10-25 (M7): Pool is 864 cards: economy 100, social 73, health 60, education 60, security 70, defense 60, foreign 70, industry 70, transport 60, housing 41, environment 50, justice 60, culture 40, crises 50. 117 cards are follow-up-only (119 links, about one chain per 7 cards, several branch on yes/no), 29 are repeatable (mostly crises), 353 have a stat or quality condition. Availability by year: start 286, year 1 202, year 2 189, year 3 127, year 4+ 60. The plan's old "about 920" was an addition error; the per-category targets add up to 860. Seven writers worked in parallel from `docs/CARD-WRITING.md`; defense and foreign cards only use invented countries (Torvania, Marenia, Belmora, Kessaly, Draveth). Coin-flip averages (yes/no averaged) are near zero for opinion, stability, economy and cost; unrest runs about +0.24 because "no" answers lean toward unrest, which is fine for now (M8). Seven duplicate English titles were retitled.
|
||||
- 2026-10-25 (M7): Pool check, 120 random-answer runs (20 seeds x 6 strategies): no empty week, a run sees 205 distinct cards on average (min 39 on the early-ending starve runs, max 261), draws are spread over categories and years, and the endings match M5 (baseline, spendthrift, austerity and police-state random play reach the end; ruin ends in default; starve in revolution or coup). 9 cards were never drawn because of narrow conditions (coup attempt and its two follow-ups, police strike, strike wave, regional fund loan, industry rescue, drought pipeline, guildhall roof); they are rare-situation cards and are kept. `server/cards_test.go` now requires at least 800 cards and a minimum per category.
|
||||
- 2026-10-25 (M8): Starting point, measured with the new harness: every strategy except ruin, starve and tyrant survived 100 % of runs, random play scored 58 and a card-reading bot only 61, so decisions barely mattered. Causes: the start state was an equilibrium with nothing pushing back, sector effects were weak, and debt cost only about 10 score points at 150 % of GDP.
|
||||
- 2026-10-25 (M8): Engine changes (all tunable in balance.json). Indicator drift (opinion fades, order and stability erode, unrest creeps up, scaled by `driftScale` 1.1); sector needs grow yearly (`needGrowth`); a world business cycle with shocks (`world`, state version 2 with a migration that adds `world: {cycle: 0}`), receipts follow growth (`fiscal.growthSens`); `gain` 3.0 multiplies how much sector quality moves indicators; `excess` and `short` terms reward quality above 70 to 75 and punish neglect; interest premium coefficient 0.0008 (was 0.0003); default at 165 % (was 200, warning at 135); the score leans 50 % on the last year (`score.lastYearShare`); grades S 73, A 64, B 56, C 47, D 38; revolution zone is unrest above 62 and opinion below 28; coup also triggers from army loyalty under 18 alone, and from loyalty under 35 with stability under 50; zone chances grow 0.004 per day (was 0.015 and 0.02), so a warning leaves about a month.
|
||||
- 2026-10-25 (M8): Emergency session. A new danger warning (revolution, coup, impeachment, default) opens the budget ledger at once, at most once per `gameOver.emergencyCooldown` (45) days, with a stamped banner. Passive play with a sensible reaction survives about 95 % of runs against 79 % without it, and extremes still fall. `state.risk` gained `emergency` and `lastEmergency`; `restoreState` repairs saves without them.
|
||||
- 2026-10-25 (M8): Cards react to the player's choices. New condition keys `ratio:<sector>` and `tax:<id>` (engine, Go validator, guide). 50 new crisis cards: 34 backlash (`cri_bk_*`: police state, army excess or neglect, high and low taxes, debt and rating, starved services, waste) and 16 windfall (`cri_wf_*`: sustained high sector quality). The pool is 914 cards. Windfalls fire about 1.1 times per run for the balanced plan and 2.6 for the 1.5x plan; backlash fires 2 to 3 times per run for police state, tax hike and spendthrift and almost never for the milder versions.
|
||||
- 2026-10-25 (M8): Result, 24 seeds each, human-like card answers: random 79 % survive (grade D); planner 100 % and score 61 (A in 17 % of runs); the same plan at 1.5x boldness 100 % with A in 29 %; at 2x 63 % survive; at 3x default every time; ruin, starve, deep cuts, tyrant 0 %; spendthrift 33 %; mild versions of each idea 75 to 100 %. The best budget the search found scores about 63 to 65. `balance-check --check` encodes these bands. Soft spots: S is rare, unrest runs slightly positive in the card pool, blanket austerity is fatal.
|
||||
- 2026-10-25 (M8): Newspaper headlines for a global slump or boom. The ledger hint says needs grow yearly. Dev parameter `?untilAlert` stops a fast-forward at the first danger warning. Engine checks cover the world cycle, growing needs, the new condition keys, coup from neglect, the emergency session with its cooldown and the version 1 migration.
|
||||
|
||||
Reference in New Issue
Block a user