Moteur de simulation (plan 1/2) #1
No files matched your search
@@ -0,0 +1,74 @@
|
||||
import { GameDate, START_DATE } from './calendar';
|
||||
import { STARTING_CASH_CENTS } from './economy';
|
||||
import { createInventory, Inventory, ItemRef, itemKey } from './inventory';
|
||||
import { createLoyaltyState, LoyaltyState } from './loyalty';
|
||||
|
||||
export const DAY_START_MINUTES = 8 * 60;
|
||||
export const OPEN_MINUTES = 9 * 60;
|
||||
export const CLOSE_MINUTES = 19 * 60;
|
||||
export const SHELF_SLOT_COUNT = 12;
|
||||
|
||||
export interface DayStats {
|
||||
revenueCents: number;
|
||||
expensesCents: number;
|
||||
salesCount: number;
|
||||
lostRequests: number;
|
||||
buyBacks: number;
|
||||
trades: number;
|
||||
}
|
||||
|
||||
export interface PendingOrder {
|
||||
item: ItemRef;
|
||||
qty: number;
|
||||
}
|
||||
|
||||
export interface GameState {
|
||||
saveVersion: 1;
|
||||
date: GameDate;
|
||||
minutes: number;
|
||||
cash: number;
|
||||
reputation: number; // 0-100
|
||||
inventory: Inventory;
|
||||
prices: Record<string, number>;
|
||||
loyalty: LoyaltyState;
|
||||
pendingOrders: PendingOrder[];
|
||||
day: DayStats;
|
||||
negativeMonthEnds: number;
|
||||
bankrupt: boolean;
|
||||
rngState: number;
|
||||
nextCustomerId: number;
|
||||
customerAccumulator: number;
|
||||
}
|
||||
|
||||
export function emptyDayStats(): DayStats {
|
||||
return { revenueCents: 0, expensesCents: 0, salesCount: 0, lostRequests: 0, buyBacks: 0, trades: 0 };
|
||||
}
|
||||
|
||||
export function createNewGame(seed: number): GameState {
|
||||
return {
|
||||
saveVersion: 1,
|
||||
date: { ...START_DATE },
|
||||
minutes: DAY_START_MINUTES,
|
||||
cash: STARTING_CASH_CENTS,
|
||||
reputation: 20,
|
||||
inventory: createInventory(SHELF_SLOT_COUNT),
|
||||
prices: {},
|
||||
loyalty: createLoyaltyState(),
|
||||
pendingOrders: [],
|
||||
day: emptyDayStats(),
|
||||
negativeMonthEnds: 0,
|
||||
bankrupt: false,
|
||||
rngState: seed,
|
||||
nextCustomerId: 1,
|
||||
customerAccumulator: 0,
|
||||
};
|
||||
}
|
||||
|
||||
export function setPrice(state: GameState, item: ItemRef, cents: number): void {
|
||||
if (cents <= 0) throw new Error('Price must be positive');
|
||||
state.prices[itemKey(item)] = cents;
|
||||
}
|
||||
|
||||
export function adjustReputation(state: GameState, delta: number): void {
|
||||
state.reputation = Math.min(100, Math.max(0, state.reputation + delta));
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createNewGame, DAY_START_MINUTES, setPrice, SHELF_SLOT_COUNT } from '../../src/sim/state';
|
||||
import { START_DATE } from '../../src/sim/calendar';
|
||||
import { STARTING_CASH_CENTS } from '../../src/sim/economy';
|
||||
|
||||
describe('state', () => {
|
||||
it('creates a new game on 28/09/1990 at 8:00', () => {
|
||||
const s = createNewGame(123);
|
||||
expect(s.saveVersion).toBe(1);
|
||||
expect(s.date).toEqual(START_DATE);
|
||||
expect(s.minutes).toBe(DAY_START_MINUTES);
|
||||
expect(s.cash).toBe(STARTING_CASH_CENTS);
|
||||
expect(s.reputation).toBe(20);
|
||||
expect(s.inventory.slots).toHaveLength(SHELF_SLOT_COUNT);
|
||||
expect(s.rngState).toBe(123);
|
||||
expect(s.bankrupt).toBe(false);
|
||||
});
|
||||
|
||||
it('sets a positive price', () => {
|
||||
const s = createNewGame(1);
|
||||
setPrice(s, { gameId: 'tetris', condition: 'new' }, 2500);
|
||||
expect(s.prices['tetris|new']).toBe(2500);
|
||||
expect(() => setPrice(s, { gameId: 'tetris', condition: 'new' }, 0)).toThrow('Price must be positive');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user