feat: Cards writings and balancing (M8)

This commit is contained in:
gauvainboiche
2026-10-25 18:30:43 +01:00
parent 04193e2013
commit c2103c32e7
43 changed files with 25930 additions and 397 deletions
+10 -5
View File
@@ -13,12 +13,17 @@ export const METRIC_IDS = [
const mean = (xs) => (xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : 0);
// Averages over the whole term, plus the final debt ratio.
function termAverages(state) {
const AVERAGED = ["order", "stability", "civilRights", "opinion", "economy", "hardPower", "softPower", "unrest", "armyLoyalty", "growth", "unemployment", "inflation"];
// Averages over the whole term, plus the final debt ratio. With `lastYearShare` the average
// leans on the last 52 weekly samples: the historian judges what you leave behind, so a
// boom bought on credit does not pay for itself.
function termAverages(state, lastYearShare = 0) {
const s = state.history.series;
const m = {};
for (const id of ["order", "stability", "civilRights", "opinion", "economy", "hardPower", "softPower", "unrest", "armyLoyalty", "growth", "unemployment", "inflation"]) {
m[id] = mean(s[id] ?? []);
for (const id of AVERAGED) {
const all = s[id] ?? [];
m[id] = lastYearShare > 0 ? (1 - lastYearShare) * mean(all) + lastYearShare * mean(all.slice(-52)) : mean(all);
}
m.debt = s.debtRatio?.at(-1) ?? 0;
m.years = state.day / 365;
@@ -76,7 +81,7 @@ function meets(entry, m) {
// endgame: the parsed data/endgame.json (its `titles` list is in priority order).
export function buildReview(state, bal, cards, endgame) {
const metrics = termAverages(state);
let score = computeScore(metrics, bal);
let score = computeScore(termAverages(state, bal.score.lastYearShare ?? 0), bal);
if (state.over && state.over.type !== "term") score = Math.min(score, bal.score.overCap);
metrics.score = score;