Files
Battle-for-Tismo/tests/central_bank_fx_test.js
adrien 71dad18e8d Let central banks work their reserves and cleared the landlocked famines
Central banks now redeem the national money foreign banks hold, sell reserves to defend a weak rate, and cover part of strategic imports from reserves. Five repeatable technologies raise each commodity's output per unit of energy. Hostile troops on a road or sea lane sever trade, power and unit supply. Middlemen buy food to resell to neighbours at a markup, and starving regions buy before those topping up their buffers, which clears the landlocked famines. The economic map's trade graph gains a colour legend.
2026-09-22 15:28:11 +02:00

93 lines
3.8 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { smallState, cityOf } from "./framework/helpers.js";
import { MONEY } from "../shared/data.js";
// Gives both central banks a symmetric reserve of each other's currency and the
// matching issued-currency debt, so the FX desk has something to work.
function bookReserves(state, amount = 1000) {
const a = state.currencyOf(0).code;
const b = state.currencyOf(1).code;
state._addReserve(1, a, amount);
state._addReserve(0, b, amount);
state._addCentralBankDebt(0, a, amount);
state._addCentralBankDebt(1, b, amount);
return { a, b };
}
export class CentralBankFxTest extends TestCase {
test_redeeming_own_currency_retires_it_from_the_foreign_bank() {
const state = smallState();
const { a, b } = bookReserves(state, 1000);
const redeemed = state._redeemOwnCurrency(0, 500);
this.assertApprox(redeemed, 500);
// Britain hands back the francs it held; France hands back the pounds.
this.assertApprox(state.getCentralBankReserves(1).get(a), 500);
this.assertApprox(state.getCentralBankReserves(0).get(b), 500);
// Both issued-currency liabilities shrink with the money retired.
this.assertApprox(state.getCentralBankDebt(0).get(a), 500);
this.assertApprox(state.getCentralBankDebt(1).get(b), 500);
// The bid for francs and the offer of pounds register as currency demand.
this.assertGreater(state._currencyDemand.get(0) || 0, 0);
this.assertLess(state._currencyDemand.get(1) || 0, 0);
}
test_a_weak_rate_sells_more_reserves_than_a_strong_one() {
const strong = smallState();
bookReserves(strong, 1_000_000);
strong.setCurrencyValue(0, 1);
const ordinary = strong._settleCentralBankFx(0);
const weak = smallState();
bookReserves(weak, 1_000_000);
weak.setCurrencyValue(0, 0.9);
const defended = weak._settleCentralBankFx(0);
this.assertGreater(ordinary, 0, "the bank redeems even when the rate is calm");
this.assertGreater(defended, ordinary, "a weak rate is defended harder");
}
test_the_bank_leaves_its_reserves_alone_without_money_held_abroad() {
const state = smallState();
const b = state.currencyOf(1).code;
state._addReserve(0, b, 1_000_000);
this.assertApprox(state._settleCentralBankFx(0), 0);
}
test_the_import_subsidy_draws_on_its_own_currency_reserves() {
const state = smallState();
const buyer = cityOf(state, 0);
const a = state.currencyOf(0).code;
const b = state.currencyOf(1).code;
state._addReserve(0, b, 1_000_000);
const before = state.getRegionCash(buyer).get(a) || 0;
const acquired = state._regionAcquireCurrency(buyer, 1, 1000, null, true, 400);
this.assertApprox(acquired.subsidised, 400, 1e-6, "the bank covered its share");
this.assertApprox(acquired.amount, 1000, 1e-6, "the seller is paid in full");
this.assertApprox(
state.getCentralBankReserves(0).get(b), 999_600, 1e-6,
"the subsidy came out of reserves"
);
const after = state.getRegionCash(buyer).get(a) || 0;
this.assertApprox(before - after, 600, 1e-6, "the buyer paid only the rest");
}
test_the_import_subsidy_budget_is_capped_for_the_day() {
const state = smallState();
const b = state.currencyOf(1).code;
state._addReserve(0, b, 1_000_000);
state._fxSubsidySpent = new Map();
const budget = 1_000_000 * MONEY.fx.importSubsidyPerDay;
const first = state._centralBankImportSubsidy(0, "food", 1_000_000);
this.assertApprox(first, budget, 1e-6);
state._recordImportSubsidy(0, first);
this.assertApprox(state._centralBankImportSubsidy(0, "food", 1_000_000), 0);
}
test_no_subsidy_for_a_resource_the_bank_does_not_back() {
const state = smallState();
const b = state.currencyOf(1).code;
state._addReserve(0, b, 1_000_000);
this.assertEqual(state._centralBankImportSubsidy(0, "luxury", 1_000_000), 0);
}
}