From: Benjamin Auder Date: Thu, 18 Feb 2021 11:16:07 +0000 (+0100) Subject: Experimental loss on repetition for Shogi and Pandemonium. Simplify Crazyhouse, with... X-Git-Url: https://git.auder.net/%7B%7B%20asset%28%27mixstore/images/css/img/logo_Westcastle.png?a=commitdiff_plain;h=809ab1a837e0f748987bcf7d66defa11cb7a1792;p=vchess.git Experimental loss on repetition for Shogi and Pandemonium. Simplify Crazyhouse, with better promoted pieces display --- diff --git a/client/public/images/pieces/Crazyhouse/bc.svg b/client/public/images/pieces/Crazyhouse/bc.svg new file mode 100644 index 00000000..61bd4482 --- /dev/null +++ b/client/public/images/pieces/Crazyhouse/bc.svg @@ -0,0 +1,106 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Crazyhouse/bo.svg b/client/public/images/pieces/Crazyhouse/bo.svg new file mode 100644 index 00000000..02bff6ac --- /dev/null +++ b/client/public/images/pieces/Crazyhouse/bo.svg @@ -0,0 +1,97 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Crazyhouse/bt.svg b/client/public/images/pieces/Crazyhouse/bt.svg new file mode 100644 index 00000000..d38046b4 --- /dev/null +++ b/client/public/images/pieces/Crazyhouse/bt.svg @@ -0,0 +1,82 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Crazyhouse/bu.svg b/client/public/images/pieces/Crazyhouse/bu.svg new file mode 100644 index 00000000..ac04efc0 --- /dev/null +++ b/client/public/images/pieces/Crazyhouse/bu.svg @@ -0,0 +1,92 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Crazyhouse/wc.svg b/client/public/images/pieces/Crazyhouse/wc.svg new file mode 100644 index 00000000..abcdb80f --- /dev/null +++ b/client/public/images/pieces/Crazyhouse/wc.svg @@ -0,0 +1,118 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Crazyhouse/wo.svg b/client/public/images/pieces/Crazyhouse/wo.svg new file mode 100644 index 00000000..18a2cb8e --- /dev/null +++ b/client/public/images/pieces/Crazyhouse/wo.svg @@ -0,0 +1,74 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/client/public/images/pieces/Crazyhouse/wt.svg b/client/public/images/pieces/Crazyhouse/wt.svg new file mode 100644 index 00000000..7d78055f --- /dev/null +++ b/client/public/images/pieces/Crazyhouse/wt.svg @@ -0,0 +1,142 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Crazyhouse/wu.svg b/client/public/images/pieces/Crazyhouse/wu.svg new file mode 100644 index 00000000..78e3e33c --- /dev/null +++ b/client/public/images/pieces/Crazyhouse/wu.svg @@ -0,0 +1,106 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Pandemonium/ba.svg b/client/public/images/pieces/Pandemonium/ba.svg deleted file mode 120000 index c301d868..00000000 --- a/client/public/images/pieces/Pandemonium/ba.svg +++ /dev/null @@ -1 +0,0 @@ -../bq.svg \ No newline at end of file diff --git a/client/public/images/pieces/Pandemonium/ba.svg b/client/public/images/pieces/Pandemonium/ba.svg new file mode 100644 index 00000000..88cd2d4c --- /dev/null +++ b/client/public/images/pieces/Pandemonium/ba.svg @@ -0,0 +1,150 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Pandemonium/bg.svg b/client/public/images/pieces/Pandemonium/bg.svg deleted file mode 120000 index c301d868..00000000 --- a/client/public/images/pieces/Pandemonium/bg.svg +++ /dev/null @@ -1 +0,0 @@ -../bq.svg \ No newline at end of file diff --git a/client/public/images/pieces/Pandemonium/bg.svg b/client/public/images/pieces/Pandemonium/bg.svg new file mode 100644 index 00000000..d4894653 --- /dev/null +++ b/client/public/images/pieces/Pandemonium/bg.svg @@ -0,0 +1,97 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Pandemonium/bw.svg b/client/public/images/pieces/Pandemonium/bw.svg deleted file mode 120000 index c301d868..00000000 --- a/client/public/images/pieces/Pandemonium/bw.svg +++ /dev/null @@ -1 +0,0 @@ -../bq.svg \ No newline at end of file diff --git a/client/public/images/pieces/Pandemonium/bw.svg b/client/public/images/pieces/Pandemonium/bw.svg new file mode 100644 index 00000000..38bce687 --- /dev/null +++ b/client/public/images/pieces/Pandemonium/bw.svg @@ -0,0 +1,148 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Pandemonium/wa.svg b/client/public/images/pieces/Pandemonium/wa.svg deleted file mode 120000 index aed155fe..00000000 --- a/client/public/images/pieces/Pandemonium/wa.svg +++ /dev/null @@ -1 +0,0 @@ -../wq.svg \ No newline at end of file diff --git a/client/public/images/pieces/Pandemonium/wa.svg b/client/public/images/pieces/Pandemonium/wa.svg new file mode 100644 index 00000000..21fe684e --- /dev/null +++ b/client/public/images/pieces/Pandemonium/wa.svg @@ -0,0 +1,205 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Pandemonium/wg.svg b/client/public/images/pieces/Pandemonium/wg.svg deleted file mode 120000 index aed155fe..00000000 --- a/client/public/images/pieces/Pandemonium/wg.svg +++ /dev/null @@ -1 +0,0 @@ -../wq.svg \ No newline at end of file diff --git a/client/public/images/pieces/Pandemonium/wg.svg b/client/public/images/pieces/Pandemonium/wg.svg new file mode 100644 index 00000000..d8c37b08 --- /dev/null +++ b/client/public/images/pieces/Pandemonium/wg.svg @@ -0,0 +1,152 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/pieces/Pandemonium/ww.svg b/client/public/images/pieces/Pandemonium/ww.svg deleted file mode 120000 index aed155fe..00000000 --- a/client/public/images/pieces/Pandemonium/ww.svg +++ /dev/null @@ -1 +0,0 @@ -../wq.svg \ No newline at end of file diff --git a/client/public/images/pieces/Pandemonium/ww.svg b/client/public/images/pieces/Pandemonium/ww.svg new file mode 100644 index 00000000..7df2240c --- /dev/null +++ b/client/public/images/pieces/Pandemonium/ww.svg @@ -0,0 +1,203 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/base_rules.js b/client/src/base_rules.js index df150262..5cf1d97e 100644 --- a/client/src/base_rules.js +++ b/client/src/base_rules.js @@ -139,6 +139,10 @@ export const ChessRules = class ChessRules { static get IgnoreRepetition() { return false; } + loseOnRepetition() { + // In some variants, result depends on the position: + return V.LoseOnRepetition; + } // At some stages, some games could wait clicks only: onlyClick() { diff --git a/client/src/translations/rules/Pandemonium/en.pug b/client/src/translations/rules/Pandemonium/en.pug index f5d518d6..1c315cb3 100644 --- a/client/src/translations/rules/Pandemonium/en.pug +++ b/client/src/translations/rules/Pandemonium/en.pug @@ -43,14 +43,11 @@ p. On the third rank, they can still advance two squares. A dropped pawn cannot give checkmate. -p. - While castling, the king moves three squares lateraly. - Castling is possible even if the king or the rooks moved. - However, it can only be done once. +p While castling, the king moves three squares lateraly. p. - If after a move both kings are facing each other (on a rank or file) - without intervening pieces, then the player who made the move loses. + Threefold repetition is a draw, unless caused by a perpetual check. + In this case, the player giving check loses. h3 More information diff --git a/client/src/translations/rules/Pandemonium/es.pug b/client/src/translations/rules/Pandemonium/es.pug index 8aed7fe1..56ab473e 100644 --- a/client/src/translations/rules/Pandemonium/es.pug +++ b/client/src/translations/rules/Pandemonium/es.pug @@ -44,15 +44,11 @@ p. En la tercera fila, todavía pueden avanzar dos espacios. Un peón lanzado en paracaídas no puede dar jaque mate. -p. - Durante el enroque, el rey mueve tres casillas hacia los lados. - El enroque es posible incluso si el rey o las torres se han movido. - Sin embargo, solo se puede realizar una vez. +p Durante el enroque, el rey mueve tres casillas hacia los lados. p. - Si después de una jugada los dos reyes se encuentran cara a cara (en fila - o una columna) sin piezas intermedias, entonces el jugador que hizo - el movimiento pierde. + La triple repetición es un empate, a menos que sea causado por un jaque + perpetuo. En este caso, el jugador que da jaque pierde. h3 Más información diff --git a/client/src/translations/rules/Pandemonium/fr.pug b/client/src/translations/rules/Pandemonium/fr.pug index bdd6d3b5..63de846c 100644 --- a/client/src/translations/rules/Pandemonium/fr.pug +++ b/client/src/translations/rules/Pandemonium/fr.pug @@ -44,15 +44,11 @@ p. Sur la troisième rangée, ils peuvent encore avancer de deux cases. Un pion parachuté ne peut pas donner échec et mat. -p. - Lors du roque, le roi se déplace de trois cases latéralement. - Le roque est possible même si le roi ou les tours ont bougé. - Cependant, il ne peut être exécuté qu'une fois. +p Lors du roque, le roi se déplace de trois cases latéralement. p. - Si après un coup les deux rois se retrouvent face à face (sur une rangée - ou une colonne) sans pièces intermédiaires, alors le joueur ayant effectué - le coup perd. + La triple répétition fait nulle, à moins d'être causée par un échec + perpétuel. Dans ce cas, le joueur donnant échec perd. h3 Plus d'information diff --git a/client/src/variants/Crazyhouse.js b/client/src/variants/Crazyhouse.js index 2a95dc85..56e65412 100644 --- a/client/src/variants/Crazyhouse.js +++ b/client/src/variants/Crazyhouse.js @@ -3,21 +3,30 @@ import { ArrayFun } from "@/utils/array"; export class CrazyhouseRules extends ChessRules { + static get PawnSpecs() { + return Object.assign( + {}, + ChessRules.PawnSpecs, + // Change names to know that this goes back to pawn after capture: + { promotions: ['u', 'o', 'c', 't'] } + ); + } + + static get PIECES() { + return ChessRules.PIECES.concat(['u', 'o', 'c', 't']); + } + + getPpath(b) { + const prefix = (ChessRules.PIECES.includes(b[1]) ? "" : "Crazyhouse/"); + return prefix + b; + } + static IsGoodFen(fen) { if (!ChessRules.IsGoodFen(fen)) return false; const fenParsed = V.ParseFen(fen); // 5) Check reserves if (!fenParsed.reserve || !fenParsed.reserve.match(/^[0-9]{10,10}$/)) return false; - // 6) Check promoted array - if (!fenParsed.promoted) return false; - if (fenParsed.promoted == "-") return true; //no promoted piece on board - const squares = fenParsed.promoted.split(","); - for (let square of squares) { - const c = V.SquareToCoords(square); - if (c.y < 0 || c.y > V.size.y || isNaN(c.x) || c.x < 0 || c.x > V.size.x) - return false; - } return true; } @@ -25,10 +34,7 @@ export class CrazyhouseRules extends ChessRules { const fenParts = fen.split(" "); return Object.assign( ChessRules.ParseFen(fen), - { - reserve: fenParts[5], - promoted: fenParts[6] - } + { reserve: fenParts[5] } ); } @@ -37,19 +43,11 @@ export class CrazyhouseRules extends ChessRules { } getFen() { - return ( - super.getFen() + " " + - this.getReserveFen() + " " + - this.getPromotedFen() - ); + return super.getFen() + " " + this.getReserveFen(); } getFenForRepeat() { - return ( - super.getFenForRepeat() + "_" + - this.getReserveFen() + "_" + - this.getPromotedFen() - ); + return super.getFenForRepeat() + "_" + this.getReserveFen(); } getReserveFen() { @@ -65,19 +63,6 @@ export class CrazyhouseRules extends ChessRules { return counts.join(""); } - getPromotedFen() { - let res = ""; - for (let i = 0; i < V.size.x; i++) { - for (let j = 0; j < V.size.y; j++) { - if (this.promoted[i][j]) res += V.CoordsToSquare({ x: i, y: j }) + ","; - } - } - // Remove last comma: - if (res.length > 0) res = res.slice(0, -1); - else res = "-"; - return res; - } - setOtherVariables(fen) { super.setOtherVariables(fen); const fenParsed = V.ParseFen(fen); @@ -99,13 +84,6 @@ export class CrazyhouseRules extends ChessRules { [V.QUEEN]: reserve[9] } }; - this.promoted = ArrayFun.init(V.size.x, V.size.y, false); - if (fenParsed.promoted != "-") { - for (let square of fenParsed.promoted.split(",")) { - const coords = V.SquareToCoords(square); - this.promoted[coords.x][coords.y] = true; - } - } } getColor(i, j) { @@ -113,9 +91,22 @@ export class CrazyhouseRules extends ChessRules { return this.board[i][j].charAt(0); } + // Pieces types after pawn promotion + static get PromotionMap() { + return { + u: 'r', + o: 'n', + c: 'b', + t: 'q' + }; + } + getPiece(i, j) { if (i >= V.size.x) return V.RESERVE_PIECES[j]; - return this.board[i][j].charAt(1); + const p = this.board[i][j].charAt(1); + if (ChessRules.PIECES.includes(p)) return p; + // Pawn promotion: + return V.PromotionMap[p]; } // Used by the interface: @@ -205,14 +196,11 @@ export class CrazyhouseRules extends ChessRules { this.reserve[color][move.appear[0].p]--; return; } - move.movePromoted = this.promoted[move.start.x][move.start.y]; - move.capturePromoted = this.promoted[move.end.x][move.end.y]; - this.promoted[move.start.x][move.start.y] = false; - this.promoted[move.end.x][move.end.y] = - move.movePromoted || - (move.vanish[0].p == V.PAWN && move.appear[0].p != V.PAWN); - if (move.capturePromoted) this.reserve[color][V.PAWN]++; - else if (move.vanish.length == 2) this.reserve[color][move.vanish[1].p]++; + if (move.vanish.length == 2) { + if (V.PawnSpecs.promotions.includes(move.vanish[1].p)) + this.reserve[color][V.PAWN]++; + else this.reserve[color][move.vanish[1].p]++; + } } postUndo(move) { @@ -223,10 +211,11 @@ export class CrazyhouseRules extends ChessRules { this.reserve[color][move.appear[0].p]++; return; } - if (move.movePromoted) this.promoted[move.start.x][move.start.y] = true; - this.promoted[move.end.x][move.end.y] = move.capturePromoted; - if (move.capturePromoted) this.reserve[color][V.PAWN]--; - else if (move.vanish.length == 2) this.reserve[color][move.vanish[1].p]--; + if (move.vanish.length == 2) { + if (V.PawnSpecs.promotions.includes(move.vanish[1].p)) + this.reserve[color][V.PAWN]--; + else this.reserve[color][move.vanish[1].p]--; + } } static get SEARCH_DEPTH() { @@ -247,8 +236,11 @@ export class CrazyhouseRules extends ChessRules { getNotation(move) { if (move.vanish.length > 0) return super.getNotation(move); // Rebirth: - const piece = - move.appear[0].p != V.PAWN ? move.appear[0].p.toUpperCase() : ""; + let piece = move.appear[0].p; + if (ChessRules.PIECES.includes(piece)) { + if (move.appear[0].p != V.PAWN) piece = move.appear[0].p.toUpperCase(); + } + else piece = V.PromotionMap[piece].toUpperCase(); return piece + "@" + V.CoordsToSquare(move.end); } diff --git a/client/src/variants/Pandemonium.js b/client/src/variants/Pandemonium.js index 1291eda1..4ae73033 100644 --- a/client/src/variants/Pandemonium.js +++ b/client/src/variants/Pandemonium.js @@ -14,6 +14,11 @@ export class PandemoniumRules extends ChessRules { ); } + loseOnRepetition() { + // If current side is under check: lost + return this.underCheck(this.turn); + } + static get GILDING() { return "g"; } diff --git a/client/src/variants/Shogi.js b/client/src/variants/Shogi.js index ac98835a..bca37627 100644 --- a/client/src/variants/Shogi.js +++ b/client/src/variants/Shogi.js @@ -24,6 +24,11 @@ export class ShogiRules extends ChessRules { return true; } + loseOnRepetition() { + // If current side is under check: lost + return this.underCheck(this.turn); + } + static IsGoodFen(fen) { if (!ChessRules.IsGoodFen(fen)) return false; const fenParsed = V.ParseFen(fen); diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue index 65d46460..fc86e90d 100644 --- a/client/src/views/Game.vue +++ b/client/src/views/Game.vue @@ -1414,7 +1414,7 @@ export default { ? this.repeat[fenObj] + 1 : 1; if (this.repeat[fenObj] >= 3) { - if (V.LoseOnRepetition) + if (this.vr.loseOnRepetition()) this.gameOver(moveCol == "w" ? "0-1" : "1-0", "Repetition"); else this.drawOffer = "threerep"; }