Mes parties : scénarios, glossaire, test navigateur sur IndexedDB
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
274fbf6252
commit
31815134e5
@@ -15,81 +15,10 @@
|
||||
|
||||
import { mkdirSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import type { Engine } from "../../src/domain/game/engine.js";
|
||||
import { Game } from "../../src/domain/game/game.js";
|
||||
import type { DiceSource } from "../../src/domain/game/roll.js";
|
||||
import { exportSgf } from "../../src/domain/game/sgf.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);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Une action de la partie, quel que soit le camp qui a la main. Le joueur
|
||||
* joue le choice-ième coup légal (le dernier s'il y en a moins), prend les
|
||||
* doubles si take, et double quand il le peut si double.
|
||||
*/
|
||||
async function step(
|
||||
game: Game,
|
||||
engine: Engine,
|
||||
strategy: { choice?: number; take?: boolean; double?: boolean } = {},
|
||||
): Promise<void> {
|
||||
const state = game.state;
|
||||
if (state.turn === "computer" && state.phase === "doubled") {
|
||||
if (strategy.take ?? true) {
|
||||
game.take();
|
||||
} else {
|
||||
game.drop();
|
||||
}
|
||||
} else if (state.turn === "computer") {
|
||||
await game.playComputerTurn();
|
||||
} else if (state.phase === "rolling") {
|
||||
if (strategy.double === true && (await game.canDouble())) {
|
||||
await game.double();
|
||||
} else {
|
||||
await game.roll();
|
||||
}
|
||||
} else if (state.phase === "moving" && state.roll !== null) {
|
||||
const moves = await engine.legalMoves(state.position, state.roll);
|
||||
const move = moves[Math.min(strategy.choice ?? 0, moves.length - 1)];
|
||||
if (move === undefined) {
|
||||
await game.skipTurn();
|
||||
return;
|
||||
}
|
||||
for (const halfMove of move.halfMoves) {
|
||||
if (!(await game.playHalfMove(halfMove))) {
|
||||
throw new Error("coup légal refusé");
|
||||
}
|
||||
}
|
||||
await game.confirmMove();
|
||||
} else {
|
||||
throw new Error(`phase inattendue : ${state.phase}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function playMoves(game: Game, engine: Engine, count: number, choice = 0): Promise<void> {
|
||||
let played = 0;
|
||||
while (played < count && game.state.phase !== "over") {
|
||||
const before = game.events.length;
|
||||
await step(game, engine, { choice });
|
||||
played += game.events.slice(before).filter((event) => event.type === "MovePlayed").length;
|
||||
}
|
||||
}
|
||||
|
||||
async function playToTheEnd(game: Game, engine: Engine, choice = 0): Promise<void> {
|
||||
for (let i = 0; game.state.phase !== "over"; i++) {
|
||||
if (i > 2000) {
|
||||
throw new Error("la partie ne finit pas");
|
||||
}
|
||||
await step(game, engine, { choice });
|
||||
}
|
||||
}
|
||||
import { playMoves, playToTheEnd, seededDice, step } from "../support/play.js";
|
||||
|
||||
/** Le dernier événement « coup joué » de la ligne courante. */
|
||||
function lastMoveId(game: Game, skip = 0): string {
|
||||
|
||||
Reference in New Issue
Block a user