From: Benjamin Auder Date: Sat, 13 Mar 2021 13:57:48 +0000 (+0100) Subject: Split Refusal into Refusal1 + Refusal2, fix endgame bug, remove castling X-Git-Url: https://git.auder.net/images/assets/doc/html/css/pieces/cb.svg?a=commitdiff_plain;h=39867b70918e8199bdc830f4e99be954d653a1f0;p=vchess.git Split Refusal into Refusal1 + Refusal2, fix endgame bug, remove castling --- diff --git a/client/src/translations/en.js b/client/src/translations/en.js index 502b8bb1..50f648a7 100644 --- a/client/src/translations/en.js +++ b/client/src/translations/en.js @@ -205,7 +205,8 @@ export const translations = { "Dance with the King": "Dance with the King", "Dangerous captures": "Dangerous captures", "Dangerous collisions": "Dangerous collisions", - "Do not play that!": "Do not play that!", + "Do not play that! (v1)": "Do not play that! (v1)", + "Do not play that! (v2)": "Do not play that! (v2)", "Double moves (v1)": "Double moves (v1)", "Double moves (v2)": "Double moves (v2)", "Dynasty versus Kingdom": "Dynasty versus Kingdom", diff --git a/client/src/translations/es.js b/client/src/translations/es.js index 7e39759e..74414b94 100644 --- a/client/src/translations/es.js +++ b/client/src/translations/es.js @@ -205,7 +205,8 @@ export const translations = { "Dance with the King": "Baila con el Rey", "Dangerous captures": "Capturas peligrosas", "Dangerous collisions": "Colisiones peligrosas", - "Do not play that!": "¡No juegues eso!", + "Do not play that! (v1)": "¡No juegues eso! (v1)", + "Do not play that! (v2)": "¡No juegues eso! (v2)", "Double moves (v1)": "Jugadas doble (v1)", "Double moves (v2)": "Jugadas doble (v2)", "Dynasty versus Kingdom": "Dinastía contra Reino", diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js index 6d04f40b..521df052 100644 --- a/client/src/translations/fr.js +++ b/client/src/translations/fr.js @@ -205,7 +205,8 @@ export const translations = { "Dance with the King": "Dansez avec le Roi", "Dangerous captures": "Captures dangeureuses", "Dangerous collisions": "Collisions dangeureuses", - "Do not play that!": "Ne joue pas ça !", + "Do not play that! (v1)": "Ne joue pas ça ! (v1)", + "Do not play that! (v2)": "Ne joue pas ça ! (v2)", "Double moves (v1)": "Coups doubles (v1)", "Double moves (v2)": "Coups doubles (v2)", "Dynasty versus Kingdom": "Dynastie contre Royaume", diff --git a/client/src/translations/rules/Refusal/en.pug b/client/src/translations/rules/Refusal1/en.pug similarity index 64% rename from client/src/translations/rules/Refusal/en.pug rename to client/src/translations/rules/Refusal1/en.pug index c5ad81a4..2be7b7fe 100644 --- a/client/src/translations/rules/Refusal/en.pug +++ b/client/src/translations/rules/Refusal1/en.pug @@ -1,16 +1,20 @@ p.boxed - | You can forbid the opponent to play the move he wanted. + | You can forbid the opponent to play the move he wanted, + | even if only one move is available. p. All rules are as in normal chess, except for the following: each turn, a player has the right to refuse at most one move of the opponent. To refuse a move, re-play it from end to starting square. + To avoid unnecessary complications, castle is not allowed. p. Two moves promoting the same pawn on the same square, but to a different type of piece, count as two different moves. -p If a player has only one legal move, this move must be accepted. +p. + If a player has only one legal move, refusing it will end the game, + either by checkmate or stalemate (draw). h3 More information diff --git a/client/src/translations/rules/Refusal/es.pug b/client/src/translations/rules/Refusal1/es.pug similarity index 70% rename from client/src/translations/rules/Refusal/es.pug rename to client/src/translations/rules/Refusal1/es.pug index c2f75fca..796200d6 100644 --- a/client/src/translations/rules/Refusal/es.pug +++ b/client/src/translations/rules/Refusal1/es.pug @@ -1,16 +1,20 @@ p.boxed - | Puedes evitar que el oponente haga cualquier movimiento que quiera. + | Puedes evitar que el oponente haga cualquier movimiento que quiera, + | incluso si solo tiene un movimiento legal. p. Todo va como en el ajedrez ortodoxo, excepto por un detalle: en cada turno, un jugador tiene derecho a rechazar como máximo una jugada del oponente. Para rechazar un movimiento, vuelva a reproducirlo al revés. + Para evitar complicaciones innecesarias, no se permite el enroque. p. Dos movimientos, cada uno promoviendo un peón en la misma casilla, pero en dos piezas diferentes, se ven como jugadas diferentes. -p Si un jugador tiene solo un movimiento legal, debe ser aceptado. +p. + Si un jugador tiene solo un movimiento legal, su rechazo conduce al final + del juego, con jaque mate o empate (dibujar). h3 Más información diff --git a/client/src/translations/rules/Refusal/fr.pug b/client/src/translations/rules/Refusal1/fr.pug similarity index 69% rename from client/src/translations/rules/Refusal/fr.pug rename to client/src/translations/rules/Refusal1/fr.pug index e1b1750e..7aa534b7 100644 --- a/client/src/translations/rules/Refusal/fr.pug +++ b/client/src/translations/rules/Refusal1/fr.pug @@ -1,16 +1,20 @@ p.boxed - | Vous pouvez empêcher l'adversaire de jouer le coup qu'il souhaite. + | Vous pouvez empêcher l'adversaire de jouer le coup qu'il souhaite, + | même s'il ne dispose que d'un seul coup légal. p. Tout se déroule comme aux échecs orthodoxes, à l'exception d'un détail : à chaque tour, un joueur a le droit de refuser au plus un coup adverse. Pour refuser un coup, re-jouez le à l'envers. + Afin d'éviter les complications inutiles, le roque n'est pas autorisé. p. Deux coups promouvant chacun un pion sur la même case, mais en deux pièces différentes, sont vus comme des coups différents. -p Si un joueur n'a qu'un seul coup légal, celui-ci doit être accepté. +p. + Si un joueur n'a qu'un seul coup légal, son refus entraîne la fin de la + partie, par échec et mat ou pat (match nul). h3 Plus d'information diff --git a/client/src/translations/rules/Refusal2/en.pug b/client/src/translations/rules/Refusal2/en.pug new file mode 100644 index 00000000..29f741b5 --- /dev/null +++ b/client/src/translations/rules/Refusal2/en.pug @@ -0,0 +1,7 @@ +p.boxed + | You can forbid the opponent to play the move he wanted, + | unless it is the only move available. + +p + a(href="/#/variants/Refusal1") Refusal1 + | , but if a player has only one legal move, this move must be accepted. diff --git a/client/src/translations/rules/Refusal2/es.pug b/client/src/translations/rules/Refusal2/es.pug new file mode 100644 index 00000000..00ba425d --- /dev/null +++ b/client/src/translations/rules/Refusal2/es.pug @@ -0,0 +1,7 @@ +p.boxed + | Puedes evitar que el oponente haga cualquier movimiento que quiera, + | a menos que sea el único movimiento posible. + +p + a(href="/#/variants/Refusal1") Refusal1 + | , pero si un jugador tiene solo un movimiento legal, debe ser aceptado. diff --git a/client/src/translations/rules/Refusal2/fr.pug b/client/src/translations/rules/Refusal2/fr.pug new file mode 100644 index 00000000..b1fddd96 --- /dev/null +++ b/client/src/translations/rules/Refusal2/fr.pug @@ -0,0 +1,7 @@ +p.boxed + | Vous pouvez empêcher l'adversaire de jouer le coup qu'il souhaite, + | sauf si c'est le seul coup possible. + +p + a(href="/#/variants/Refusal1") Refusal1 + | , mais si un joueur n'a qu'un seul coup légal, celui-ci doit être accepté. diff --git a/client/src/translations/variants/en.pug b/client/src/translations/variants/en.pug index c380c427..c384bab9 100644 --- a/client/src/translations/variants/en.pug +++ b/client/src/translations/variants/en.pug @@ -474,7 +474,8 @@ p. "Kingsmaker", "Magnetic", "Pandemonium", - "Refusal", + "Refusal1", + "Refusal2", "Relayup", "Rollerball", "Selfabsorb", diff --git a/client/src/translations/variants/es.pug b/client/src/translations/variants/es.pug index 6658c9b9..d8151ef2 100644 --- a/client/src/translations/variants/es.pug +++ b/client/src/translations/variants/es.pug @@ -484,7 +484,8 @@ p. "Kingsmaker", "Magnetic", "Pandemonium", - "Refusal", + "Refusal1", + "Refusal2", "Relayup", "Rollerball", "Selfabsorb", diff --git a/client/src/translations/variants/fr.pug b/client/src/translations/variants/fr.pug index 7d7ab45b..19a799dd 100644 --- a/client/src/translations/variants/fr.pug +++ b/client/src/translations/variants/fr.pug @@ -482,7 +482,8 @@ p. "Kingsmaker", "Magnetic", "Pandemonium", - "Refusal", + "Refusal1", + "Refusal2", "Relayup", "Rollerball", "Selfabsorb", diff --git a/client/src/variants/Refusal.js b/client/src/variants/Refusal1.js similarity index 79% rename from client/src/variants/Refusal.js rename to client/src/variants/Refusal1.js index 76d737dd..4f50d754 100644 --- a/client/src/variants/Refusal.js +++ b/client/src/variants/Refusal1.js @@ -1,7 +1,11 @@ import { ChessRules } from "@/base_rules"; import { randInt } from "@/utils/alea"; -export class RefusalRules extends ChessRules { +export class Refusal1Rules extends ChessRules { + + static get HasFlags() { + return false; + } static IsGoodFen(fen) { if (!ChessRules.IsGoodFen(fen)) return false; @@ -11,7 +15,7 @@ export class RefusalRules extends ChessRules { static ParseFen(fen) { return Object.assign( - { lastMove: fen.split(" ")[5] }, + { lastMove: fen.split(" ")[4] }, ChessRules.ParseFen(fen) ); } @@ -26,7 +30,7 @@ export class RefusalRules extends ChessRules { // some extra repetitions could be detected... TODO (...) static GenRandInitFen(randomness) { - return ChessRules.GenRandInitFen(randomness) + " null"; + return ChessRules.GenRandInitFen(randomness).slice(0, -6) + "- null"; } setOtherVariables(fen) { @@ -66,26 +70,6 @@ export class RefusalRules extends ChessRules { return super.getPotentialMovesFrom([x, y]); } - // NOTE: do not take refusal move into account here (two own moves) - atLeastTwoMoves() { - let movesCounter = 0; - const color = this.turn; - for (let i = 0; i < V.size.x; i++) { - for (let j = 0; j < V.size.y; j++) { - if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) { - const moves = this.getPotentialMovesFrom([i, j]); - for (let m of moves) { - if (m.vanish[0].c == color && this.filterValid([m]).length > 0) { - movesCounter++; - if (movesCounter >= 2) return true; - } - } - } - } - } - return false; - } - filterValid(moves) { if (moves.length == 0) return []; const color = this.turn; @@ -115,16 +99,13 @@ export class RefusalRules extends ChessRules { prePlay(move) { const L = this.lastMove.length; const lm = this.lastMove[L-1]; - if ( - // My previous move was already refused? - (!!lm && this.getColor(lm.end.x, lm.end.y) == this.turn) || - // I've only one move available? - !this.atLeastTwoMoves() - ) { - move.noRef = true; - } // NOTE: refusal could be recomputed, but, it's easier like this if (move.vanish[0].c != this.turn) move.refusal = true; + move.noRef = ( + !!move.refusal || + // My previous move was already refused? + !!lm && this.getColor(lm.end.x, lm.end.y) == this.turn + ); } getEpSquare(move) { @@ -137,7 +118,8 @@ export class RefusalRules extends ChessRules { else { const L = this.lastMove.length; const lm = this.lastMove[L-1]; - this.disaggregateFlags(JSON.parse(lm.flags)); + if (move.appear[0].p == V.KING) + this.kingPos[move.appear[0].c] = [move.end.x, move.end.y]; } // NOTE: explicitely give fields, because some are assigned in BaseGame let mvInLm = { @@ -145,7 +127,6 @@ export class RefusalRules extends ChessRules { end: move.end, appear: move.appear, vanish: move.vanish, - flags: move.flags }; if (!!move.noRef) mvInLm.noRef = true; if (!!move.refusal) mvInLm.refusal = true; @@ -154,6 +135,10 @@ export class RefusalRules extends ChessRules { postUndo(move) { if (!move.refusal) super.postUndo(move); + else { + if (move.appear[0].p == V.KING) + this.kingPos[move.appear[0].c] = [move.start.x, move.start.y]; + } this.lastMove.pop(); } @@ -162,16 +147,12 @@ export class RefusalRules extends ChessRules { const L = this.lastMove.length; const lm = this.lastMove[L-1]; let potentialMoves = []; + if (!!lm && !lm.noRef) + // Add refusal move: + potentialMoves = this.getPotentialMovesFrom([lm.end.x, lm.end.y]); for (let i = 0; i < V.size.x; i++) { for (let j = 0; j < V.size.y; j++) { - if ( - this.board[i][j] != V.EMPTY && - ( - this.getColor(i, j) == color || - // Add move refusal: - (!!lm && lm.end.x == i && lm.end.y == j) - ) - ) { + if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) { Array.prototype.push.apply( potentialMoves, this.getPotentialMovesFrom([i, j]) @@ -182,13 +163,20 @@ export class RefusalRules extends ChessRules { return potentialMoves; } + atLeastOneMove() { + const L = this.lastMove.length; + const lm = this.lastMove[L-1]; + if (!!lm && !lm.noRef) return true; + return super.atLeastOneMove(); + } + getComputerMove() { // Just play at random for now... (TODO?) // Refuse last move with odds 1/3. const moves = this.getAllValidMoves(); const refusal = moves.find(m => m.vanish[0].c != this.turn); if (!!refusal) { - if (Math.random() <= 0.33) return refusal; + if (moves.length == 1 || Math.random() <= 0.33) return refusal; const others = moves.filter(m => m.vanish[0].c == this.turn); return others[randInt(others.length)]; } diff --git a/client/src/variants/Refusal2.js b/client/src/variants/Refusal2.js new file mode 100644 index 00000000..05eca7a6 --- /dev/null +++ b/client/src/variants/Refusal2.js @@ -0,0 +1,40 @@ +import { Refusal1Rules } from "@/variants/Refusal1"; + +export class Refusal2Rules extends Refusal1Rules { + + // NOTE: do not take refusal move into account here (two own moves) + atLeastTwoMoves() { + let movesCounter = 0; + const color = this.turn; + for (let i = 0; i < V.size.x; i++) { + for (let j = 0; j < V.size.y; j++) { + if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) { + const moves = this.getPotentialMovesFrom([i, j]); + for (let m of moves) { + if (m.vanish[0].c == color && this.filterValid([m]).length > 0) { + movesCounter++; + if (movesCounter >= 2) return true; + } + } + } + } + } + return false; + } + + prePlay(move) { + const L = this.lastMove.length; + const lm = this.lastMove[L-1]; + if ( + // My previous move was already refused? + (!!lm && this.getColor(lm.end.x, lm.end.y) == this.turn) || + // I've only one move available? + !this.atLeastTwoMoves() + ) { + move.noRef = true; + } + // NOTE: refusal could be recomputed, but, it's easier like this + if (move.vanish[0].c != this.turn) move.refusal = true; + } + +}; diff --git a/server/db/populate.sql b/server/db/populate.sql index 3726f974..aa0dace2 100644 --- a/server/db/populate.sql +++ b/server/db/populate.sql @@ -133,7 +133,8 @@ insert or ignore into Variants (name, description) values ('Relayup', 'Upgrade pieces'), ('Rifle', 'Shoot pieces'), ('Recycle', 'Reuse pieces'), - ('Refusal', 'Do not play that!'), + ('Refusal1', 'Do not play that! (v1)'), + ('Refusal2', 'Do not play that! (v2)'), ('Rollerball', 'As in the movie'), ('Rococo', 'Capture on the edge'), ('Rookpawns', 'Rook versus pawns'),