Domaine : coup à valider, demi-coups défaits un par un, dés joués

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Pierre MARTIN
2026-11-03 07:04:26 +01:00
co-authored by Claude Opus 5.5
parent ce2bd46ec3
commit 2c5278965b
4 changed files with 218 additions and 24 deletions
+100
View File
@@ -78,14 +78,111 @@ test("un coup se saisit demi-coup par demi-coup ; un demi-coup refusé ne change
assert.deepEqual(game.pendingHalfMoves, [{ from: 8, to: 5 }]);
assert.equal(await game.playHalfMove({ from: 6, to: 5 }), true);
// Coup complet : il attend la validation, hors du journal.
assert.equal(game.moveComplete, true);
assert.equal(game.displayedPosition, "AFTER");
assert.equal(game.events.length, 2);
assert.equal(game.state.turn, "player");
assert.deepEqual(await game.nextHalfMoves(), []);
assert.equal(await game.playHalfMove({ from: 8, to: 7 }), false);
await game.confirmMove();
const last = game.events.at(-1);
assert.equal(last?.type, "MovePlayed");
assert.deepEqual(game.pendingHalfMoves, []);
assert.equal(game.moveComplete, false);
assert.equal(game.state.turn, "computer");
assert.equal(game.state.phase, "rolling");
assert.equal(game.state.position, "SWAPPED");
});
test("un coup incomplet ne se valide pas", async () => {
const game = Game.start(fakeEngine(), { dice: fixedDice([3, 1]) });
await assert.rejects(game.confirmMove(), /pas complet/);
await game.playHalfMove({ from: 8, to: 5 });
await assert.rejects(game.confirmMove(), /pas complet/);
assert.equal(game.events.length, 2);
});
test("Annuler défait les demi-coups un par un, sans toucher au journal", async () => {
const game = Game.start(fakeEngine(), { dice: fixedDice([3, 1]) });
await game.playHalfMove({ from: 8, to: 5 });
await game.playHalfMove({ from: 6, to: 5 });
const journal = game.journal;
game.undoLastHalfMove();
assert.deepEqual(game.pendingHalfMoves, [{ from: 8, to: 5 }]);
assert.equal(game.moveComplete, false);
assert.equal(game.displayedPosition, "HALF");
game.undoLastHalfMove();
assert.deepEqual(game.pendingHalfMoves, []);
assert.equal(game.displayedPosition, START_POSITION);
game.undoLastHalfMove(); // rien à défaire : sans effet
assert.equal(game.journal, journal);
// Le coup se ressaisit ensuite normalement.
assert.equal(await game.playHalfMove({ from: 8, to: 5 }), true);
assert.equal(await game.playHalfMove({ from: 6, to: 5 }), true);
assert.equal(game.moveComplete, true);
});
test("les dés utilisés par les demi-coups saisis sont marqués", async () => {
const game = Game.start(fakeEngine(), { dice: fixedDice([3, 1]) });
assert.deepEqual(game.diceToPlay, [
{ value: 3, used: false },
{ value: 1, used: false },
]);
await game.playHalfMove({ from: 8, to: 5 });
assert.deepEqual(game.diceToPlay, [
{ value: 3, used: true },
{ value: 1, used: false },
]);
await game.playHalfMove({ from: 6, to: 5 });
assert.deepEqual(
game.diceToPlay.map((d) => d.used),
[true, true],
);
await game.confirmMove();
assert.deepEqual(game.diceToPlay, []);
});
test("un double donne quatre dés, marqués un par un ; une sortie prend le plus petit dé suffisant", async () => {
const engine = fakeEngine({
checkHalfMoves: async () => ({ valid: true, complete: false, position: "P" }),
});
const double = Game.start(engine, {
dice: fixedDice([2, 2]),
setup: { position: "X", firstTurn: "player" },
});
await double.roll();
assert.equal(double.diceToPlay.length, 4);
await double.playHalfMove({ from: 13, to: 11 });
await double.playHalfMove({ from: 11, to: 9 });
assert.deepEqual(
double.diceToPlay.map((d) => d.used),
[true, true, false, false],
);
const bearOff = Game.start(engine, {
dice: fixedDice([6, 4]),
setup: { position: "X", firstTurn: "player" },
});
await bearOff.roll();
// 3/off : le 4 suffit, le 6 reste.
await bearOff.playHalfMove({ from: 3, to: 0 });
assert.deepEqual(bearOff.diceToPlay, [
{ value: 6, used: false },
{ value: 4, used: true },
]);
// 6/2 demande le 4 : la sortie a donc pris le 6.
await bearOff.playHalfMove({ from: 6, to: 2 });
assert.deepEqual(
bearOff.diceToPlay.map((d) => d.used),
[true, true],
);
});
test("sans coup possible, le tour passe quand le joueur le laisse passer", async () => {
const engine = fakeEngine({ legalMoves: async () => [] });
const game = Game.start(engine, {
@@ -192,6 +289,7 @@ test("annuler repart du parent ; l'action suivante ouvre une branche", async ()
const game = Game.start(fakeEngine(), { dice: fixedDice([3, 1, 6, 5, 4, 2]) });
await game.playHalfMove({ from: 8, to: 5 });
await game.playHalfMove({ from: 6, to: 5 });
await game.confirmMove();
const played = game.events.at(-1);
assert.equal(played?.type, "MovePlayed");
@@ -200,6 +298,7 @@ test("annuler repart du parent ; l'action suivante ouvre une branche", async ()
assert.equal(game.state.turn, "player");
await game.playHalfMove({ from: 8, to: 5 });
await game.playHalfMove({ from: 6, to: 5 });
await game.confirmMove();
// Deux coups accrochés au même jet : l'ancien reste dans le journal.
const moves = game.journal.events.filter((e) => e.type === "MovePlayed");
@@ -244,6 +343,7 @@ test("une partie se reprend depuis son journal ; un journal d'une autre version
const game = Game.start(fakeEngine(), { dice: fixedDice([3, 1]) });
await game.playHalfMove({ from: 8, to: 5 });
await game.playHalfMove({ from: 6, to: 5 });
await game.confirmMove();
const saved = JSON.parse(JSON.stringify(game.journal));
const resumed = Game.resume(fakeEngine(), saved);