import { describe, it, expect } from 'vitest'; import { DuplicateGame } from './game'; const START = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'; function placement(fen: string) { return fen.split(' ')[0]; } describe('DuplicateGame', () => { it('starts with four boards in the standard position, North to move', () => { const g = new DuplicateGame(); expect(g.ply).toBe(0); expect(g.currentPlayer).toBe('N'); for (const id of ['NW', 'NE', 'SW', 'SE'] as const) { expect(placement(g.boards[id].fen())).toBe(START); } }); it("applies a synchronized move to the current player's two boards only", () => { const g = new DuplicateGame(); g.applyMove({ from: 'e2', to: 'e4' }); // North expect(g.ply).toBe(1); expect(g.currentPlayer).toBe('S'); expect(placement(g.boards.NW.fen())).toContain('4P3'); // pawn advanced expect(placement(g.boards.NE.fen())).toContain('4P3'); expect(placement(g.boards.SW.fen())).toBe(START); // untouched expect(placement(g.boards.SE.fen())).toBe(START); }); it('cycles the current player N -> S -> E -> W -> N', () => { const g = new DuplicateGame(); g.applyMove({ from: 'e2', to: 'e4' }); // N g.applyMove({ from: 'e2', to: 'e4' }); // S g.applyMove({ from: 'e7', to: 'e5' }); // E g.applyMove({ from: 'e7', to: 'e5' }); // W expect(g.currentPlayer).toBe('N'); expect(g.ply).toBe(4); }); it("throws on a move not legal on both of the player's boards", () => { const g = new DuplicateGame(); expect(() => g.applyMove({ from: 'e2', to: 'e5' })).toThrow(); }); it('undo removes the last move and restores the position', () => { const g = new DuplicateGame(); g.applyMove({ from: 'e2', to: 'e4' }); g.undo(); expect(g.ply).toBe(0); expect(g.currentPlayer).toBe('N'); expect(placement(g.boards.NW.fen())).toBe(START); }); it('rebuilds from a history array passed to the constructor', () => { const g = new DuplicateGame([ { player: 'N', from: 'e2', to: 'e4' }, { player: 'S', from: 'e2', to: 'e4' }, ]); expect(g.ply).toBe(2); expect(g.currentPlayer).toBe('E'); }); it('resets the progress clock on a pawn move or capture', () => { const g = new DuplicateGame(); g.applyMove({ from: 'e2', to: 'e4' }); // pawn move -> clock stays 0 expect(g.pliesSinceProgress).toBe(0); g.applyMove({ from: 'e2', to: 'e4' }); // pawn move expect(g.pliesSinceProgress).toBe(0); g.applyMove({ from: 'g8', to: 'f6' }); // knight move -> clock increments expect(g.pliesSinceProgress).toBe(1); }); });