Partie de match (score et Crawford dits par le moteur), niveau choisi porté par GameStarted, ordinateur joué comme ComputerTurn de gnubg ; migration des journaux de la version 1 ; scénarios, glossaire, ADR 0007 et 0013 amendés. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
129 lines
5.5 KiB
TypeScript
129 lines
5.5 KiB
TypeScript
// Tests du choix de la partie et du match, sans navigateur : réglages de
|
|
// l'écran « Nouvelle partie », correspondance des niveaux avec ceux de
|
|
// GNU Backgammon, résumé d'une partie de match enregistrée, adaptateur du
|
|
// moteur (Match ID d'un match) sur le vrai moteur.
|
|
//
|
|
// 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 { COMPUTER_LEVELS, computerLevelOf, ENGINE_LEVELS } from "../src/domain/game/level.js";
|
|
import { firstGameOf, MATCH_LENGTHS, nextGameOf } from "../src/domain/game/match.js";
|
|
import { START_POSITION } from "../src/domain/game/position.js";
|
|
import { fixedDice } from "../src/domain/game/roll.js";
|
|
import { levelOf, summarizeGame } from "../src/domain/game/saved-game.js";
|
|
import { chosenGame, DEFAULT_SETTINGS, parseSettings } from "../src/ui/settings.js";
|
|
import { loadNodeEngine } from "./support/node-engine.js";
|
|
|
|
test("les six niveaux montrés au joueur, du plus faible au plus fort, et leur niveau de gnubg", () => {
|
|
assert.deepEqual(COMPUTER_LEVELS, [
|
|
"beginner",
|
|
"amateur",
|
|
"intermediate",
|
|
"advanced",
|
|
"expert",
|
|
"champion",
|
|
]);
|
|
assert.deepEqual(
|
|
COMPUTER_LEVELS.map((level) => ENGINE_LEVELS[level]),
|
|
["beginner", "casual", "intermediate", "advanced", "0ply", "2ply"],
|
|
);
|
|
assert.equal(computerLevelOf("casual"), "amateur");
|
|
assert.equal(computerLevelOf("3ply"), null);
|
|
});
|
|
|
|
test("réglages de la nouvelle partie : partie libre, Intermédiaire, conseil activé par défaut ; valeurs illisibles ignorées", () => {
|
|
assert.equal(DEFAULT_SETTINGS.gameKind, "free");
|
|
assert.equal(DEFAULT_SETTINGS.level, "intermediate");
|
|
assert.equal(DEFAULT_SETTINGS.masterAdvice, true);
|
|
// Réglages d'avant l'étape 1c : les valeurs par défaut.
|
|
const old = parseSettings('{"vibrations": false, "gamesStarted": 4}');
|
|
assert.equal(old.gameKind, "free");
|
|
assert.equal(old.matchLength, 5);
|
|
assert.equal(old.level, "intermediate");
|
|
const saved = parseSettings(
|
|
'{"gameKind": "match", "matchLength": 7, "level": "champion", "masterAdvice": false}',
|
|
);
|
|
assert.deepEqual(
|
|
[saved.gameKind, saved.matchLength, saved.level, saved.masterAdvice],
|
|
["match", 7, "champion", false],
|
|
);
|
|
const wrong = parseSettings('{"gameKind": "x", "matchLength": 4, "level": "4ply"}');
|
|
assert.deepEqual([wrong.gameKind, wrong.matchLength, wrong.level], ["free", 5, "intermediate"]);
|
|
assert.deepEqual([...MATCH_LENGTHS], [3, 5, 7, 11]);
|
|
});
|
|
|
|
test("la partie choisie : le niveau de gnubg, et la première partie d'un match à 0-0", () => {
|
|
assert.deepEqual(chosenGame(DEFAULT_SETTINGS), { level: "intermediate" });
|
|
assert.deepEqual(chosenGame({ ...DEFAULT_SETTINGS, gameKind: "match", level: "expert" }), {
|
|
level: "0ply",
|
|
match: { length: 5, score: { player: 0, computer: 0 }, crawford: false },
|
|
});
|
|
assert.throws(() => firstGameOf(0), /longueur/);
|
|
const match = firstGameOf(3);
|
|
assert.equal(
|
|
nextGameOf(match, { score: { player: 3, computer: 0 }, over: true, crawford: false }),
|
|
null,
|
|
);
|
|
assert.deepEqual(
|
|
nextGameOf(match, { score: { player: 2, computer: 0 }, over: false, crawford: true }),
|
|
{ length: 3, score: { player: 2, computer: 0 }, crawford: true },
|
|
);
|
|
});
|
|
|
|
test("le résumé d'une partie de match enregistrée porte le match ; celui d'une partie libre n'en a pas", async () => {
|
|
const engine = await loadNodeEngine();
|
|
const times = { startedAt: 1, updatedAt: 2 };
|
|
const free = Game.start(engine, { dice: fixedDice([3, 1]), level: "beginner" });
|
|
assert.equal(levelOf(free.journal), "beginner");
|
|
const freeSummary = summarizeGame("a", free.journal, { level: "beginner" }, times);
|
|
assert.equal(freeSummary.match, undefined);
|
|
assert.equal(freeSummary.level, "beginner");
|
|
|
|
const match = Game.start(engine, {
|
|
dice: fixedDice([3, 1]),
|
|
level: "2ply",
|
|
match: { length: 5, score: { player: 4, computer: 2 }, crawford: true },
|
|
});
|
|
const summary = summarizeGame("b", match.journal, { level: levelOf(match.journal) }, times);
|
|
assert.deepEqual(summary.match, {
|
|
length: 5,
|
|
score: { player: 4, computer: 2 },
|
|
crawford: true,
|
|
over: false,
|
|
});
|
|
});
|
|
|
|
test("adaptateur : le Match ID d'un match code la longueur, le score vu du joueur au trait et Crawford", async () => {
|
|
const engine = await loadNodeEngine();
|
|
const id = await engine.encodeMatch({
|
|
value: 1,
|
|
owner: "centered",
|
|
match: { length: 5, score: { onRoll: 4, opponent: 2 }, crawford: true },
|
|
});
|
|
const decoded = await engine.decodeMatch(id);
|
|
assert.deepEqual(
|
|
[decoded.matchLength, decoded.score, decoded.crawford, decoded.jacoby],
|
|
[5, [4, 2], true, false],
|
|
);
|
|
// En partie Crawford, le moteur refuse le videau au joueur au trait.
|
|
const crawford = await engine.cubeDecision(
|
|
START_POSITION,
|
|
{
|
|
value: 1,
|
|
owner: "centered",
|
|
match: { length: 5, score: { onRoll: 2, opponent: 4 }, crawford: true },
|
|
},
|
|
0,
|
|
);
|
|
assert.equal(crawford.available, false);
|
|
const after = await engine.matchAfterGame(
|
|
{ length: 5, score: { onRoll: 3, opponent: 2 }, crawford: false },
|
|
"onRoll",
|
|
1,
|
|
);
|
|
assert.deepEqual(after, { score: { onRoll: 4, opponent: 2 }, over: false, crawford: true });
|
|
});
|