256a613134
Adds conversation_games table type + game_make_move RPC to db-types, GamePayload variant and parseMessagePayload branch to shared/attachments, games.ts with createGame/getGame/makeGameMove wrappers plus pure tttWinningLine/c4WinningCells/c4DropRow/isBoardFull helpers, 11 tests covering all winner helpers, and re-export from chat/index.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
80 lines
2.1 KiB
TypeScript
80 lines
2.1 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import {
|
|
c4DropRow,
|
|
c4WinningCells,
|
|
emptyC4Board,
|
|
emptyTttBoard,
|
|
isBoardFull,
|
|
tttWinningLine,
|
|
type Cell,
|
|
} from './games';
|
|
|
|
describe('tttWinningLine', () => {
|
|
it('detects a row win', () => {
|
|
const b: Cell[] = [0, 0, 0, null, null, null, null, null, null];
|
|
expect(tttWinningLine(b)).toEqual([0, 1, 2]);
|
|
});
|
|
|
|
it('detects a diagonal win', () => {
|
|
const b: Cell[] = [1, null, null, null, 1, null, null, null, 1];
|
|
expect(tttWinningLine(b)).toEqual([0, 4, 8]);
|
|
});
|
|
|
|
it('returns null when no winner', () => {
|
|
expect(tttWinningLine(emptyTttBoard())).toBeNull();
|
|
const mixed: Cell[] = [0, 1, 0, 1, 0, 1, 1, 0, 1];
|
|
expect(tttWinningLine(mixed)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('c4WinningCells', () => {
|
|
it('detects a horizontal win', () => {
|
|
const b = emptyC4Board();
|
|
b[35] = 1; b[36] = 1; b[37] = 1; b[38] = 1;
|
|
expect(c4WinningCells(b)).toEqual([35, 36, 37, 38]);
|
|
});
|
|
|
|
it('detects a vertical win', () => {
|
|
const b = emptyC4Board();
|
|
b[14] = 0; b[21] = 0; b[28] = 0; b[35] = 0;
|
|
expect(c4WinningCells(b)).toEqual([14, 21, 28, 35]);
|
|
});
|
|
|
|
it('detects a diagonal ↘ win', () => {
|
|
const b = emptyC4Board();
|
|
b[14] = 1; b[22] = 1; b[30] = 1; b[38] = 1;
|
|
expect(c4WinningCells(b)).toEqual([14, 22, 30, 38]);
|
|
});
|
|
|
|
it('returns null when no winner', () => {
|
|
expect(c4WinningCells(emptyC4Board())).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('c4DropRow', () => {
|
|
it('returns the bottom row on an empty column', () => {
|
|
expect(c4DropRow(emptyC4Board(), 0)).toBe(5);
|
|
});
|
|
|
|
it('stacks on top of an existing piece', () => {
|
|
const b = emptyC4Board();
|
|
b[35] = 0;
|
|
expect(c4DropRow(b, 0)).toBe(4);
|
|
});
|
|
|
|
it('returns -1 when the column is full', () => {
|
|
const b = emptyC4Board();
|
|
for (let r = 0; r < 6; r++) b[r * 7 + 3] = 0;
|
|
expect(c4DropRow(b, 3)).toBe(-1);
|
|
});
|
|
});
|
|
|
|
describe('isBoardFull', () => {
|
|
it('true for a fully filled board, false otherwise', () => {
|
|
expect(isBoardFull(emptyTttBoard())).toBe(false);
|
|
const filled: Cell[] = [0, 1, 0, 1, 0, 1, 1, 0, 1];
|
|
expect(isBoardFull(filled)).toBe(true);
|
|
});
|
|
});
|