Files

79 lines
3.4 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Balance sim</title>
<style>
body { font: 13px/1.4 "Courier New", monospace; margin: 24px; background: #1d1a15; color: #e8dfc8; }
h1, h2 { font-weight: normal; }
label { margin-right: 16px; }
input, select, button { font: inherit; background: #2b261e; color: inherit; border: 1px solid #6b5a3e; padding: 3px 6px; }
button { cursor: pointer; }
table { border-collapse: collapse; margin: 12px 0 28px; }
th, td { border: 1px solid #4a4030; padding: 2px 8px; text-align: right; }
th:first-child, td:first-child { text-align: left; }
th { background: #2b261e; }
.bad { color: #ff8a6b; }
</style>
</head>
<body>
<h1>Balance sim</h1>
<p>
<label>Years <input id="years" type="number" min="1" max="5" value="1" style="width:4em"></label>
<label>Seed <input id="seed" type="number" value="1" style="width:6em"></label>
<label>Detail <select id="detail"></select></label>
<button id="run">Run</button>
</p>
<h2>Final state per strategy</h2>
<div id="summary"></div>
<h2>Timeline</h2>
<div id="timeline"></div>
<script type="module">
import { runSim, STRATEGIES } from "./sim-core.js";
const getJson = (u) => fetch(u).then((r) => r.json());
const [balance, scenario, cardIndex] = await Promise.all([
getJson("../data/balance.json"),
getJson("../data/scenarios/default.json"),
getJson("../data/cards/index.json"),
]);
const cards = (await Promise.all(cardIndex.files.map((f) => getJson(`../data/cards/${f}`)))).flat();
const $ = (id) => document.getElementById(id);
const detail = $("detail");
for (const [k, s] of Object.entries(STRATEGIES)) detail.add(new Option(s.label, k));
const COLS = [
["day", "day", 0], ["growth", "growth %", 2], ["unemployment", "unempl %", 1], ["inflation", "infl %", 1],
["debtRatio", "debt %GDP", 1], ["deficit", "deficit %GDP", 2], ["interestRate", "rate %", 2],
["order", "order", 0], ["stability", "stab", 0], ["civilRights", "civil", 0], ["opinion", "opinion", 0],
["economy", "econ", 0], ["hardPower", "hard", 0], ["softPower", "soft", 0], ["unrest", "unrest", 0], ["armyLoyalty", "army", 0],
];
const val = (row, k) => (k in row ? row[k] : row.indicators[k]);
function table(rows, firstCol) {
const head = `<tr><th>${firstCol}</th>${COLS.map((c) => `<th>${c[1]}</th>`).join("")}</tr>`;
const body = rows.map(([name, row]) =>
`<tr><td>${name}</td>${COLS.map((c) => `<td>${val(row, c[0]).toFixed(c[2])}</td>`).join("")}</tr>`).join("");
return `<table>${head}${body}</table>`;
}
function run() {
const years = Number($("years").value);
const seed = Number($("seed").value);
const results = {};
for (const k of Object.keys(STRATEGIES)) results[k] = runSim({ scenario, balance, cards, strategy: k, years, seed });
const ended = (r) => (r.over && r.over.type !== "term" ? ` ← ${r.over.type}, day ${r.over.day}` : "");
$("summary").innerHTML = table(Object.entries(results).map(([k, r]) => [STRATEGIES[k].label + ended(r), r.final]), "strategy");
const d = results[detail.value];
$("timeline").innerHTML = table(d.rows.map((row) => [`d${row.day}`, row]), "day");
}
$("run").addEventListener("click", run);
detail.addEventListener("change", run);
run();
</script>
</body>
</html>