import { describe, expect, it } from 'vitest'; import { historyGrid, type HistoryCell } from './history'; import type { MoveRecord } from './model'; function play(player: number, words: string[], score: number): MoveRecord { return { player, action: 'play', dir: 'H', mainRow: 7, mainCol: 7, tiles: [], words, count: words.length, score, total: 0 }; } function action(player: number, act: 'pass' | 'exchange' | 'resign' | 'timeout'): MoveRecord { return { player, action: act, dir: '', mainRow: 0, mainCol: 0, tiles: [], words: [], count: 0, score: 0, total: 0 }; } function kinds(grid: HistoryCell[][]): string[][] { return grid.map((row) => row.map((c) => c.kind)); } describe('historyGrid', () => { it('lays moves into per-seat columns and marks the awaited opponent as thinking', () => { const moves = [play(0, ['ДОМ'], 12), action(1, 'pass'), play(0, ['ОСА', 'ОМ'], 12)]; const grid = historyGrid(moves, 2, 1); // seat 1 is to move expect(kinds(grid)).toEqual([ ['play', 'action'], ['play', 'thinking'], ]); expect(grid[0][0]).toMatchObject({ kind: 'play', words: ['ДОМ'], score: 12 }); expect(grid[1][0]).toMatchObject({ kind: 'play', words: ['ОСА', 'ОМ'], score: 12 }); expect(grid[0][1]).toMatchObject({ kind: 'action', action: 'pass' }); expect(grid[1][1]).toMatchObject({ kind: 'thinking', player: 1 }); }); it('renders no thinking cell when thinkingSeat is null (game over / own turn)', () => { const moves = [play(0, ['ДОМ'], 12), action(1, 'pass'), play(0, ['ОСА'], 6)]; const grid = historyGrid(moves, 2, null); expect(kinds(grid)).toEqual([ ['play', 'action'], ['play', 'empty'], ]); }); it('fills ragged columns with empty cells (a seat that stopped moving)', () => { const moves = [ play(0, ['ДОМ'], 12), play(1, ['КОТ'], 10), action(2, 'resign'), play(0, ['ОСА'], 6), play(1, ['ЛИС'], 8), ]; const grid = historyGrid(moves, 3, null); expect(kinds(grid)).toEqual([ ['play', 'play', 'action'], ['play', 'play', 'empty'], ]); expect(grid[0][2]).toMatchObject({ kind: 'action', action: 'resign' }); }); it('shows a lone thinking cell for the first mover on an empty journal', () => { expect(kinds(historyGrid([], 2, 0))).toEqual([['thinking', 'empty']]); }); it('produces an empty grid for an empty journal with no awaited mover', () => { expect(historyGrid([], 2, null)).toEqual([]); }); it('ignores moves with an out-of-range seat', () => { const grid = historyGrid([play(5, ['X'], 1), play(0, ['ДОМ'], 12)], 2, null); expect(kinds(grid)).toEqual([['play', 'empty']]); expect(grid[0][0]).toMatchObject({ words: ['ДОМ'] }); }); });