Sortie : un coup déjà complet peut encore se prolonger (6/off puis 1/off avec 6-1)
La partie fermait la saisie dès que les demi-coups formaient un coup légal. En sortie, 6/off seul mène à la même position que 6/5/off : le 1/off qui suivait était refusé. La saisie reste ouverte tant que le moteur accepte un demi-coup de plus ; le tutoriel suit la même règle. Tests : tous les ordres de saisie des fins de partie d'un à quatre pions, sur les 21 jets, scénario Gherkin et tests du moteur pour les deux ordres. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e9bb9ae88d
commit
ab8dc512ba
+11
-10
@@ -186,8 +186,11 @@ export class Game {
|
||||
}
|
||||
|
||||
/** Les demi-coups saisis forment un coup complet (le moteur le dit) : il
|
||||
* n'attend plus que d'être validé (confirmMove) ou défait
|
||||
* (undoLastHalfMove). */
|
||||
* peut être validé (confirmMove) ou défait (undoLastHalfMove). La saisie
|
||||
* n'est pas close pour autant : en sortie, un coup complet peut encore
|
||||
* se prolonger en un autre coup légal (avec 6-1 et des pions sur 6 et 1,
|
||||
* 6/off seul mène à la même position que 6/5/off, et 1/off reste
|
||||
* possible) ; nextHalfMoves dit lesquels, selon le moteur. */
|
||||
get moveComplete(): boolean {
|
||||
return this.#pending.at(-1)?.complete === true;
|
||||
}
|
||||
@@ -296,11 +299,12 @@ export class Game {
|
||||
* déjà saisis (liste vide hors de son tour de jeu). Chaque candidat
|
||||
* déplace un de ses pions de la valeur d'un dé (vers la sortie si le dé
|
||||
* dépasse la case 1) ; seuls restent ceux que le moteur déclare menant à
|
||||
* un coup légal. Aucune règle n'est jugée ici.
|
||||
* un coup légal. Aucune règle n'est jugée ici : même après un coup
|
||||
* complet, c'est le moteur qui dit si un dé reste à jouer.
|
||||
*/
|
||||
async nextHalfMoves(): Promise<HalfMove[]> {
|
||||
const state = this.state;
|
||||
if (state.turn !== "player" || state.phase !== "moving" || this.moveComplete) {
|
||||
if (state.turn !== "player" || state.phase !== "moving") {
|
||||
return [];
|
||||
}
|
||||
const roll = rollToPlay(state);
|
||||
@@ -370,15 +374,12 @@ export class Game {
|
||||
|
||||
/**
|
||||
* Le joueur déplace un pion (un dé). Renvoie false si ce demi-coup ne
|
||||
* mène à aucun coup légal (ou si le coup est déjà complet) : il est
|
||||
* refusé et rien ne change. Le coup n'est pas joué pour autant : une fois
|
||||
* complet (moveComplete), il attend d'être validé (confirmMove).
|
||||
* mène à aucun coup légal : il est refusé et rien ne change. Le coup
|
||||
* n'est pas joué pour autant : une fois complet (moveComplete), il attend
|
||||
* d'être validé (confirmMove), ou prolongé si le moteur le permet.
|
||||
*/
|
||||
async playHalfMove(halfMove: HalfMove): Promise<boolean> {
|
||||
const state = this.#expect("player", "moving");
|
||||
if (this.moveComplete) {
|
||||
return false;
|
||||
}
|
||||
const check = await this.#engine.checkHalfMoves(state.position, rollToPlay(state), [
|
||||
...this.pendingHalfMoves,
|
||||
halfMove,
|
||||
|
||||
@@ -209,10 +209,14 @@ export class MovePractice {
|
||||
if (!(await this.#game.playHalfMove(halfMove))) {
|
||||
return "wrong";
|
||||
}
|
||||
if (this.#game.moveComplete) {
|
||||
const position = this.#game.displayedPosition;
|
||||
return this.#expected.some((m) => m.position === position) ? "right" : "wrong";
|
||||
if (
|
||||
this.#game.moveComplete &&
|
||||
this.#expected.some((m) => m.position === this.#game.displayedPosition)
|
||||
) {
|
||||
return "right";
|
||||
}
|
||||
// Un coup complet peut encore se prolonger (en sortie) : il n'est
|
||||
// refusé que s'il ne peut plus mener à un coup attendu.
|
||||
return canStillLeadTo(this.#game.pendingHalfMoves, this.#expected) ? "continue" : "wrong";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user