// Une partie complète sur le vrai moteur WebAssembly, avec des dés imposés : // l'ordinateur contre une stratégie simple du joueur (toujours le premier // coup légal, saisi demi-coup par demi-coup, et toujours prendre). // // Copyright (C) 2026 les auteurs d'Ustagammon. // Licence : GPLv3 ou ultérieure (voir LICENSE). import assert from "node:assert/strict"; import { test } from "node:test"; import { Game } from "../src/domain/game/game.js"; import type { DiceSource } from "../src/domain/game/roll.js"; import { replay } from "../src/domain/game/state.js"; import { loadNodeEngine } from "./support/node-engine.js"; /** Des dés pseudo-aléatoires reproductibles (générateur congruentiel). */ function seededDice(seed: number): DiceSource { let state = seed; return () => { state = (state * 1103515245 + 12345) % 2147483648; return 1 + (Math.floor(state / 65536) % 6); }; } /** Joue jusqu'à la fin ; renvoie le nombre d'actions. */ async function playToTheEnd(game: Game, engine: Awaited>) { let actions = 0; while (game.state.phase !== "over") { assert.ok(++actions < 2000, "la partie ne finit pas"); const state = game.state; if (state.turn === "computer" && state.phase === "doubled") { game.take(); } else if (state.turn === "computer") { await game.playComputerTurn(); } else if (state.phase === "rolling") { await game.roll(); } else { assert.ok(state.roll !== null); const [first] = await engine.legalMoves(state.position, state.roll); if (first === undefined) { // Aucun coup possible : le joueur laisse passer son tour. assert.equal(await game.cannotMove(), true); await game.skipTurn(); continue; } for (const halfMove of first.halfMoves) { assert.equal(await game.playHalfMove(halfMove), true); } assert.equal(game.moveComplete, true); await game.confirmMove(); } } return actions; } for (const [seed, ply] of [ [1, 0], [7, 2], ] as const) { test(`partie complète, dés ${seed}, ordinateur à ${ply} pli(s)`, async () => { const engine = await loadNodeEngine(); const game = Game.start(engine, { dice: seededDice(seed), ply }); await playToTheEnd(game, engine); const events = game.events; const last = events.at(-1); assert.equal(last?.type, "GameEnded"); const result = game.state.result; assert.ok(result !== null); assert.ok(result.points >= 1); assert.ok(events.some((e) => e.type === "MovePlayed" && e.side === "player")); assert.ok(events.some((e) => e.type === "MovePlayed" && e.side === "computer")); // Rejouer le journal redonne le même état. assert.deepEqual(replay(events), game.state); }); }