import { describe, expect, it } from 'vitest'; import { deserializeState, serializeState } from '@core/rules/GameState'; import { apply, createGame, currentActor, legalActions } from '@core/rules/DurakRules'; describe('state serialization', () => { it('round-trips a fresh game through JSON', () => { const { state } = createGame({ players: ['you', 'bot'], seed: 4242 }); const restored = deserializeState(JSON.parse(JSON.stringify(serializeState(state)))); expect(serializeState(restored)).toEqual(serializeState(state)); }); it('round-trips a game in the middle of a turn', () => { let { state } = createGame({ players: ['you', 'bot'], seed: 99 }); for (let i = 0; i < 5; i++) { const actor = currentActor(state); if (!actor) break; state = apply(state, legalActions(state, actor)[0]).state; } const restored = deserializeState(JSON.parse(JSON.stringify(serializeState(state)))); expect(serializeState(restored)).toEqual(serializeState(state)); expect(currentActor(restored)).toBe(currentActor(state)); }); it('restores cards as the same flyweight instances', () => { const { state } = createGame({ players: ['you', 'bot'], seed: 7 }); const restored = deserializeState(serializeState(state)); expect(restored.players[0].hand[0]).toBe(state.players[0].hand[0]); expect(restored.trumpCard).toBe(state.trumpCard); }); it('replays identically from a restored state', () => { const { state } = createGame({ players: ['you', 'bot'], seed: 2001 }); const restored = deserializeState(serializeState(state)); // The same action object works on both, because cards are flyweights and // an action carries no reference to the state it was generated from. const actor = currentActor(state) as string; const action = legalActions(state, actor)[0]; expect(serializeState(apply(restored, action).state)) .toEqual(serializeState(apply(state, action).state)); }); });