chore: восстановление репозитория из снапшота v0.3.1

Прежняя git-история утрачена при переносе проекта на машину владельца
(снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной
истории.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
sab.code.lab 2026-08-07 09:34:02 +02:00
commit 1c85091186
184 changed files with 33303 additions and 0 deletions

View file

@ -0,0 +1,40 @@
/**
* Партии бот-бот: детерминизм (одинаковый seed идентичная партия),
* легальность каждого хода и завершение за 200 ходов (property-style
* на запиненных seedах; проверка легальности внутри playBotGame через
* applyMove, нелегальный ход = ошибка теста).
*/
import { describe, expect, it } from 'vitest';
import type { AiLevel } from './index.js';
import { playBotGame } from './test-utils.js';
const MAX_MOVES_9x9 = 200;
describe('детерминизм', () => {
it('одинаковый seed → идентичные последовательности ходов (два прогона)', () => {
for (const seed of [7, 42, 2026]) {
const first = playBotGame(seed, 3, 9, MAX_MOVES_9x9);
const second = playBotGame(seed, 3, 9, MAX_MOVES_9x9);
expect(second.moves).toEqual(first.moves);
expect(second.finalState.grid).toEqual(first.finalState.grid);
}
});
});
describe('легальность и завершение (property, запиненные seedы)', () => {
const levels: readonly AiLevel[] = [1, 2, 3];
const cases = Array.from({ length: 12 }, (_, index) => ({
seed: index + 1,
level: levels[index % levels.length] ?? 1,
}));
for (const { seed, level } of cases) {
it(`партия seed=${seed} ур.${level}: все ходы легальны, over за ≤ ${MAX_MOVES_9x9}`, () => {
const game = playBotGame(seed, level, 9, MAX_MOVES_9x9);
expect(game.finalState.over).toBe(true);
expect(game.moves.length).toBeLessThanOrEqual(MAX_MOVES_9x9);
// Партия завершается двумя пасами подряд.
expect(game.moves[game.moves.length - 1]).toBe('pass');
expect(game.moves[game.moves.length - 2]).toBe('pass');
});
}
});