feat: economy with lazy stock advancement and price curve
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { priceOf, advancePlanet, marketView, applyTrade } from '../src/sim/economy.js';
|
||||
import { BASE_PRICE, GOODS, TYPICAL_STOCK } from '../src/sim/constants.js';
|
||||
|
||||
function makePlanet() {
|
||||
return {
|
||||
id: 0, systemId: 0, name: 'Test Prime',
|
||||
produces: { food: 10 }, consumes: { fuel: 5 },
|
||||
stock: { ore: 100, food: 100, fuel: 100, tech: 100, meds: 100, luxury: 100 },
|
||||
stockTime: 0,
|
||||
};
|
||||
}
|
||||
|
||||
describe('economy', () => {
|
||||
it('price falls as stock rises, clamped to [0.25x, 4x] base', () => {
|
||||
expect(priceOf('ore', TYPICAL_STOCK)).toBeCloseTo(BASE_PRICE.ore, 1);
|
||||
expect(priceOf('ore', 10)).toBeGreaterThan(priceOf('ore', 500));
|
||||
expect(priceOf('ore', 0)).toBe(BASE_PRICE.ore * 4);
|
||||
expect(priceOf('ore', 1e9)).toBe(BASE_PRICE.ore * 0.25);
|
||||
});
|
||||
|
||||
it('advancePlanet applies production/consumption over elapsed time', () => {
|
||||
const p = makePlanet();
|
||||
advancePlanet(p, 10);
|
||||
expect(p.stock.food).toBeCloseTo(200, 5); // +10/day
|
||||
expect(p.stock.fuel).toBeCloseTo(50, 5); // -5/day
|
||||
expect(p.stock.ore).toBeCloseTo(100, 5); // untouched
|
||||
expect(p.stockTime).toBe(10);
|
||||
});
|
||||
|
||||
it('advancePlanet never goes negative and is idempotent', () => {
|
||||
const p = makePlanet();
|
||||
advancePlanet(p, 100);
|
||||
expect(p.stock.fuel).toBe(0);
|
||||
const snapshot = { ...p.stock };
|
||||
advancePlanet(p, 100); // same time again: no change
|
||||
expect(p.stock).toEqual(snapshot);
|
||||
});
|
||||
|
||||
it('applyTrade returns pre-trade price and mutates stock', () => {
|
||||
const p = makePlanet();
|
||||
const price = applyTrade(p, 0, 'ore', -20); // a buyer removes 20
|
||||
expect(price).toBeCloseTo(priceOf('ore', 100), 5);
|
||||
expect(p.stock.ore).toBe(80);
|
||||
applyTrade(p, 0, 'ore', 50); // a seller delivers 50
|
||||
expect(p.stock.ore).toBe(130);
|
||||
});
|
||||
|
||||
it('marketView lists all goods with integer stock and price', () => {
|
||||
const p = makePlanet();
|
||||
const view = marketView(p, 5);
|
||||
expect(view.map((r) => r.good)).toEqual(GOODS);
|
||||
for (const row of view) {
|
||||
expect(Number.isInteger(row.stock)).toBe(true);
|
||||
expect(row.price).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user