From: Benjamin Auder Date: Tue, 17 Mar 2020 12:39:28 +0000 (+0100) Subject: Add Antiking v1 X-Git-Url: https://git.auder.net/variants/Chakart/doc/scripts/app_dev.php?a=commitdiff_plain;h=c583ef1c1dfd19aee88b22c2175202fbdf4dc1c0;p=vchess.git Add Antiking v1 --- diff --git a/TODO b/TODO index 6916bdf3..094de496 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,8 @@ +# Improvements + +Find a way to generalize getCastleMoves and getPotentialPawnMoves, +to limit code duplication. + # New variants Landing pieces from empty board: https://www.chessvariants.com/diffsetup.dir/unachess.html @@ -6,10 +11,6 @@ Rugby http://www.echecspourtous.com/?page_id=7945 Cannibal Chess with forced captures. -Knightrelay: implement "official" version as Knightrelay v1 - -Antiking: implement v1 (deterministic) https://www.chessvariants.com/diffobjective.dir/anti-king-chess.html - S-chess https://en.wikipedia.org/wiki/Seirawan_chess Generator variant, called "Matrix" ? diff --git a/client/src/base_rules.js b/client/src/base_rules.js index fad1853a..29b3af60 100644 --- a/client/src/base_rules.js +++ b/client/src/base_rules.js @@ -750,12 +750,13 @@ export const ChessRules = class ChessRules { // What are the king moves from square x,y ? getPotentialKingMoves(sq) { // Initialize with normal moves - const moves = this.getSlideNJumpMoves( + let moves = this.getSlideNJumpMoves( sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep" ); - return moves.concat(this.getCastleMoves(sq)); + if (V.HasCastle) moves = moves.concat(this.getCastleMoves(sq)); + return moves; } getCastleMoves([x, y]) { diff --git a/client/src/translations/en.js b/client/src/translations/en.js index 593d68be..4267fa41 100644 --- a/client/src/translations/en.js +++ b/client/src/translations/en.js @@ -169,7 +169,8 @@ export const translations = { "In the shadow": "In the shadow", "Get strong at self-mate": "Get strong at self-mate", "Give three checks": "Give three checks", - "Keep antiking in check": "Keep antiking in check", + "Keep antiking in check (v1)": "Keep antiking in check (v1)", + "Keep antiking in check (v2)": "Keep antiking in check (v2)", "Kings cross the 8x8 board": "Kings cross the 8x8 board", "Kings cross the 11x11 board": "Kings cross the 11x11 board", "Laws of attraction": "Laws of attraction", diff --git a/client/src/translations/es.js b/client/src/translations/es.js index 84a32951..fe6509e9 100644 --- a/client/src/translations/es.js +++ b/client/src/translations/es.js @@ -169,7 +169,8 @@ export const translations = { "In the shadow": "En la sombra", "Get strong at self-mate": "Progreso en mates asistidos", "Give three checks": "Dar tres jaques", - "Keep antiking in check": "Mantener el antirey en jaque", + "Keep antiking in check (v1)": "Mantener el antirey en jaque (v1)", + "Keep antiking in check (v2)": "Mantener el antirey en jaque (v2)", "Kings cross the 8x8 board": "Los reyes cruzan el 8x8 tablero", "Kings cross the 11x11 board": "Los reyes cruzan el 11x11 tablero", "Laws of attraction": "Las leyes de las atracciones", diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js index 15575cb7..b29ccb7a 100644 --- a/client/src/translations/fr.js +++ b/client/src/translations/fr.js @@ -169,7 +169,8 @@ export const translations = { "In the shadow": "Dans l'ombre", "Get strong at self-mate": "Progressez en mats aidés", "Give three checks": "Donnez trois échecs", - "Keep antiking in check": "Gardez l'antiroi en échec", + "Keep antiking in check (v1)": "Gardez l'antiroi en échec (v1)", + "Keep antiking in check (v2)": "Gardez l'antiroi en échec (v2)", "Kings cross the 8x8 board": "Les rois traversent l'échiquier 8x8", "Kings cross the 11x11 board": "Les rois traversent l'échiquier 11x11", "Laws of attraction": "Les lois de l'attraction", diff --git a/client/src/translations/rules/Antiking1/en.pug b/client/src/translations/rules/Antiking1/en.pug new file mode 100644 index 00000000..50f183a5 --- /dev/null +++ b/client/src/translations/rules/Antiking1/en.pug @@ -0,0 +1,51 @@ +p.boxed. + You have a king and an antiking. King cannot be let in check, but antiking + must always stay under check. Antiking captures his own kind. + +p. + A new piece is introduced: the antiking, noted by the letter 'A'. + This piece must always remain under (orthodox) check: it is + considered in (anti-)check when not attacked by any enemy piece. In such a + situation, the antiking must move immediately to an attacked square. + +p. + The antiking is a royal figure, and thus cannot be captured. + It captures only the pieces of his color. + Antikings don't give check, and kings do not attack antikings. + +figure.diagram-container + .diagram + | fen:2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2: + figcaption Initial setup: antikings stand in the corners. + +h3 Unusual moves + +ul + li. + Pawns are Berolina Pawns, which move diagonally forward one square + without capturing, or move one square straight forward to capture. + li. + If a King or Anti-King has not yet moved, it may make as its first + move a Knight's leap to an empty square. + +h3 End of the game + +p There are three ways to win: +ol + li Checkmate opponent king + li Anti-checkmate opponent antiking + li Give a double check, as on the following diagram + +figure.diagram-container + .diagram + | fen:2pr3A/2pb1qbr/2p1pkQp/2pnp1n1/1PPN4/PPB1PPN1/1K2RP2/a2BRP2: + figcaption After Qb1xg6# + +h3 More information + +p + a(href="https://www.chessvariants.com/diffobjective.dir/anti-king-chess.html") + | Antiking chess + |  on chessvariants.com. + +p Inventor: Peter Aronson (2002) diff --git a/client/src/translations/rules/Antiking1/es.pug b/client/src/translations/rules/Antiking1/es.pug new file mode 100644 index 00000000..894559eb --- /dev/null +++ b/client/src/translations/rules/Antiking1/es.pug @@ -0,0 +1,53 @@ +p.boxed. + Tienes un rey y un "antirey". El rey no puede estar en jaque al final de un + turno, pero el antirey siempre debe estar en jaque. Este último captura las + piezas de su color. + +p. + Se presenta una nueva pieza: el antirey, denotado por la letra 'A'. + Esta pieza debe estar siempre en jaque (ortodoxo): se + considera en (anti-)jaque cuando no es atacada por ninguna pieza enemiga. + En este caso, el antirey debe unirse inmediatamente a una casilla atacada. + +p. + El antirey es una pieza real, por lo que no puede ser capturado. + Ella captura solo las piezas de su color. + Los antireyes no dan jaque, y los reyes no atacan a los antireyes. + +figure.diagram-container + .diagram + | fen:2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2: + figcaption Posición inicial: los antireyes están en las esquinas. + +h3 Jugadas inusuales + +ul + li. + Los peones son peones Berolina, que se mueven diagonalmente una + casilla y captura avanzando verticalmente. + li. + Si un rey o anti-rey aún no se ha movido, puede realizar + un salto de caballo a una casilla vacía. + +h3 Fin de la partida + +p Hay tres maneras de ganar: +ol + li Mater el rey contrario + li "Anti-mater" el antirey contrario + li Dar un doble jaque, como en el siguiente diagrama + +figure.diagram-container + .diagram + | fen:2pr3A/2pb1qbr/2p1pkQp/2pnp1n1/1PPN4/PPB1PPN1/1K2RP2/a2BRP2: + figcaption Después de Qb1xg6# + +h3 Más información + +p + | La + a(href="https://www.chessvariants.com/diffobjective.dir/anti-king-chess.html") + | variante Antiking + |  en chessvariants.com. + +p Inventor: Peter Aronson (2002) diff --git a/client/src/translations/rules/Antiking1/fr.pug b/client/src/translations/rules/Antiking1/fr.pug new file mode 100644 index 00000000..c8da8ce1 --- /dev/null +++ b/client/src/translations/rules/Antiking1/fr.pug @@ -0,0 +1,55 @@ +p.boxed. + Vous disposez d'un roi et d'un "antiroi". Le roi ne peut pas se retrouver + en échec à la fin d'un tour, mais l'antiroi doit lui toujours être en échec. + Ce dernier capture les pièces de sa couleur. + +p. + Une nouvelle pièce fait son apparition : l'antiroi, noté par la lettre 'A'. + Cette pièce doit toujour rester en échec (orthodoxe) : + elle est considérée en (anti-)échec lorsqu'elle n'est attaquée + par aucune pièce ennemie. Dans ce cas, l'antiroi doit immédiatement + rejoindre une case attaquée. + +p. + L'antiroi est une pièce royale, elle ne peut donc pas être capturée. + Elle capture seulement les pièces de sa couleur. + Les antirois ne donnent pas échec, et les rois n'attaquent pas les antirois. + + +figure.diagram-container + .diagram + | fen:2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2: + figcaption Position initiale : les antirois sont dans les coins. + +h3 Coups inhabituels + +ul + li. + Les pions sont des pions Berolina, qui se déplacent en diagonale d'une + case et capturent en avançant verticalement. + li. + Si un roi ou antiroi n'a pas encore bougé, il peut effectuer + un saut de cavalier vers une case vide. + +h3 Fin de partie + +p Il y a trois façons de gagner : +ol + li Mater le roi adverse + li "Anti-mater" l'anti-roi adverse + li Donner un échec double, comme sur le diagramme suivant + +figure.diagram-container + .diagram + | fen:2pr3A/2pb1qbr/2p1pkQp/2pnp1n1/1PPN4/PPB1PPN1/1K2RP2/a2BRP2: + figcaption Après Qb1xg6# + +h3 Plus d'information + +p + | La + a(href="https://www.chessvariants.com/diffobjective.dir/anti-king-chess.html") + | variante Antiking + |  sur chessvariants.com. + +p Inventeur : Peter Aronson (2002) diff --git a/client/src/translations/rules/Antiking/en.pug b/client/src/translations/rules/Antiking2/en.pug similarity index 58% rename from client/src/translations/rules/Antiking/en.pug rename to client/src/translations/rules/Antiking2/en.pug index 0c10c012..b7bc4320 100644 --- a/client/src/translations/rules/Antiking/en.pug +++ b/client/src/translations/rules/Antiking2/en.pug @@ -3,38 +3,28 @@ p.boxed. must always stay under check. Antiking captures his own kind. p. - A new piece is introduced: the antiking, noted by the letter 'A' in diagrams - and PGNs. This piece must always remain under (orthodox) check: it is + A new piece is introduced: the antiking, noted by the letter 'A'. + This piece must always remain under (orthodox) check: it is considered in (anti-)check when not attacked by any enemy piece. In such a situation, the antiking must move immediately to an attacked square. p. The antiking is a royal figure, and thus cannot be captured. - It captures only the pieces of his color (to help checkmating the opponent's - antiking, but this also complicates standard checkmate). + It captures only the pieces of his color. + Antikings don't give check, and kings do not attack antikings. figure.diagram-container .diagram | fen:rnbqkbnr/pppppppp/3A4/8/8/3a4/PPPPPPPP/RNBQKBNR c5,d5,e5: figcaption Marked squares are not allowed antiking moves. -ul - li. - Although antiking captures his color, it doesn't check his king - it - doesn't check the opponent's king either. - li. - Since it would allow a basic tactic (keep antiking touching opponent's - king), kings do not attack antikings. - h3 End of the game -p There are two ways to win: +p There are three ways to win: ol - li Checkmate opponent king - li Anti-checkmate opponent antiking -p. - ...Or do both at the same time, as on the following diagram after 3.Qxf7# - (the black antiking was on g3). + li Checkmate the opponent king + li "Anti-checkmate" the opponent antiking + li Give a double check, as on the following diagram figure.diagram-container .diagram diff --git a/client/src/translations/rules/Antiking/es.pug b/client/src/translations/rules/Antiking2/es.pug similarity index 61% rename from client/src/translations/rules/Antiking/es.pug rename to client/src/translations/rules/Antiking2/es.pug index 647eb9f6..c2d9dc34 100644 --- a/client/src/translations/rules/Antiking/es.pug +++ b/client/src/translations/rules/Antiking2/es.pug @@ -4,39 +4,28 @@ p.boxed. piezas de su color. p. - Se presenta una nueva pieza: el antirey, denotado por la letra 'A' en los - diagramas y PGNs. Esta pieza debe estar siempre en jaque (ortodoxo): se + Se presenta una nueva pieza: el antirey, denotado por la letra 'A'. + Esta pieza debe estar siempre en jaque (ortodoxo): se considera en (anti-)jaque cuando no es atacada por ninguna pieza enemiga. En este caso, el antirey debe unirse inmediatamente a una casilla atacada. p. El antirey es una pieza real, por lo que no puede ser capturado. - Ella captura solo las piezas de su color (esto ayuda a mate el anti-rey del - oponente, pero complica el mate ortodoxo). + Ella captura solo las piezas de su color. + Los antireyes no dan jaque, y los reyes no atacan a los antireyes. figure.diagram-container .diagram | fen:rnbqkbnr/pppppppp/3A4/8/8/3a4/PPPPPPPP/RNBQKBNR c5,d5,e5: figcaption Las casillas mostradas no son legales jugadas de antirey. -ul - li. - Aunque el antirey captura las piezas de su color, no da jaque a su rey, - ni tampoco al rey contrario. - li. - Los reyes no atacan a los antireyes (de color opuesto). De hecho, esto - permitiría aplicar un método simple para nunca estar en "anti-jaque": - permanecer pegado al rey contrario. - h3 Fin de la partida -p Hay dos maneras de ganar: +p Hay tres maneras de ganar: ol li Mater el rey contrario li "Anti-mater" el antirey contrario -p. - ...O haga ambas cosas al mismo tiempo, como se muestra en el siguiente - diagrama después de 3.Qxf7# (el antirey negro estaba en g3). + li Dar un doble jaque, como en el siguiente diagrama figure.diagram-container .diagram diff --git a/client/src/translations/rules/Antiking/fr.pug b/client/src/translations/rules/Antiking2/fr.pug similarity index 52% rename from client/src/translations/rules/Antiking/fr.pug rename to client/src/translations/rules/Antiking2/fr.pug index 7c058b2d..d3be1b1c 100644 --- a/client/src/translations/rules/Antiking/fr.pug +++ b/client/src/translations/rules/Antiking2/fr.pug @@ -4,40 +4,28 @@ p.boxed. Ce dernier capture les pièces de sa couleur. p. - Une nouvelle pièce fait son apparition : l'antiroi, noté par la lettre 'A' - sur les diagrammes et PGNs. Cette pièce doit toujour rester en échec - (orthodoxe) : elle est considérée en (anti-)échec lorsqu'elle n'est attaquée - par aucune pièce ennemie. Dans ce cas, l'antiroi doit immédiatement - rejoindre une case attaquée. + Une nouvelle pièce fait son apparition : l'antiroi, noté par la lettre 'A'. + Cette pièce doit toujour rester en échec (orthodoxe) : elle est considérée + en (anti-)échec lorsqu'elle n'est attaquée par aucune pièce ennemie. + Dans ce cas, l'antiroi doit immédiatement rejoindre une case attaquée. p. L'antiroi est une pièce royale, elle ne peut donc pas être capturée. - Elle capture seulement les pièces de sa couleur (cela aide à mater - l'anti-roi adverse, mais complique le mat orthodoxe). + Elle capture seulement les pièces de sa couleur. + Les antirois ne donnent pas échec, et les rois n'attaquent pas les antirois. figure.diagram-container .diagram | fen:rnbqkbnr/pppppppp/3A4/8/8/3a4/PPPPPPPP/RNBQKBNR c5,d5,e5: figcaption Les cases indiquées ne sont pas des coups d'anti-roi légaux. -ul - li. - Bien que l'antiroi capture les pièces de son camp, il ne met pas - en échec son roi - ni d'ailleurs le roi adverse. - li. - Les rois n'attaquent pas les antirois (de couleur opposée). - En effet ceci permettrait d'appliquer une méthode simple pour ne jamais - être en "anti-échec" : rester collé au roi adverse. - h3 Fin de partie -p Il y a deux façons de gagner : +p Il y a trois façons de gagner : ol li Mater le roi adverse li "Anti-mater" l'anti-roi adverse -p. - ...Ou faire les deux en même temps, comme sur le diagramme suivant après - 3.Qxf7# (l'antiroi noir était en g3). + li Donner un échec double, comme sur le diagramme suivant figure.diagram-container .diagram diff --git a/client/src/variants/Antiking1.js b/client/src/variants/Antiking1.js new file mode 100644 index 00000000..42450d17 --- /dev/null +++ b/client/src/variants/Antiking1.js @@ -0,0 +1,270 @@ +import { ChessRules } from "@/base_rules"; +import { ArrayFun } from "@/utils/array"; +import { randInt } from "@/utils/alea"; + +export const VariantRules = class Antiking1Rules extends ChessRules { + static get HasEnpassant() { + return false; + } + + static get HasCastle() { + return false; + } + + static get ANTIKING() { + return "a"; + } + + static get PIECES() { + return ChessRules.PIECES.concat([V.ANTIKING]); + } + + getPpath(b) { + return b[1] == "a" ? "Antiking/" + b : b; + } + + setOtherVariables(fen) { + super.setOtherVariables(fen); + this.antikingPos = { w: [-1, -1], b: [-1, -1] }; + const rows = V.ParseFen(fen).position.split("/"); + for (let i = 0; i < rows.length; i++) { + let k = 0; + for (let j = 0; j < rows[i].length; j++) { + switch (rows[i].charAt(j)) { + case "a": + this.antikingPos["b"] = [i, k]; + break; + case "A": + this.antikingPos["w"] = [i, k]; + break; + default: { + const num = parseInt(rows[i].charAt(j)); + if (!isNaN(num)) k += num - 1; + } + } + k++; + } + } + } + + // (Anti)King flags at 1 (true) if they can knight-jump + setFlags(fenflags) { + this.kingFlags = { + // King then antiking + w: [...Array(2).fill(false)], + b: [...Array(2).fill(false)] + }; + for (let c of ["w", "b"]) { + for (let i = 0; i < 2; i++) + this.kingFlags[c][i] = fenflags.charAt((c == "w" ? 0 : 2) + i) == "1"; + } + } + + aggregateFlags() { + return this.kingFlags; + } + + disaggregateFlags(flags) { + this.kingFlags = flags; + } + + getFlagsFen() { + // Return kings flags + let flags = ""; + for (let c of ["w", "b"]) { + for (let i = 0; i < 2; i++) flags += this.kingFlags[c][i] ? "1" : "0"; + } + return flags; + } + + canTake([x1, y1], [x2, y2]) { + const piece1 = this.getPiece(x1, y1); + const piece2 = this.getPiece(x2, y2); + const color1 = this.getColor(x1, y1); + const color2 = this.getColor(x2, y2); + return ( + piece2 != "a" && + ((piece1 != "a" && color1 != color2) || + (piece1 == "a" && color1 == color2)) + ); + } + + getPotentialMovesFrom([x, y]) { + let moves = []; + let addKnightJumps = false; + const piece = this.getPiece(x, y); + const color = this.getColor(x, y); + if (piece == V.ANTIKING) { + moves = this.getPotentialAntikingMoves([x, y]); + addKnightJumps = this.kingFlags[color][1]; + } else { + moves = super.getPotentialMovesFrom([x, y]); + if (piece == V.KING) addKnightJumps = this.kingFlags[color][0]; + } + if (addKnightJumps) { + // Add potential knight jump to (anti)kings + const knightJumps = super.getPotentialKnightMoves([x, y]); + // Remove captures (TODO: could be done more efficiently...) + moves = moves.concat(knightJumps.filter(m => m.vanish.length == 1)); + } + return moves; + } + + getPotentialPawnMoves([x, y]) { + const color = this.turn; + let moves = []; + const [sizeX, sizeY] = [V.size.x, V.size.y]; + const shiftX = color == "w" ? -1 : 1; + const startRank = color == "w" ? sizeX - 2 : 1; + const lastRank = color == "w" ? 0 : sizeX - 1; + const finalPieces = + x + shiftX == lastRank ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN] : [V.PAWN]; + + // One square diagonally + for (let shiftY of [-1, 1]) { + if (this.board[x + shiftX][y + shiftY] == V.EMPTY) { + for (let piece of finalPieces) { + moves.push( + this.getBasicMove([x, y], [x + shiftX, y + shiftY], { + c: color, + p: piece + }) + ); + } + } + } + // Capture + if ( + this.board[x + shiftX][y] != V.EMPTY && + this.canTake([x, y], [x + shiftX, y]) + ) { + for (let piece of finalPieces) + moves.push( + this.getBasicMove([x, y], [x + shiftX, y], { c: color, p: piece }) + ); + } + + return moves; + } + + getPotentialAntikingMoves(sq) { + // The antiking moves like a king (only captured colors differ) + return this.getSlideNJumpMoves( + sq, + V.steps[V.ROOK].concat(V.steps[V.BISHOP]), + "oneStep" + ); + } + + isAttacked(sq, color) { + return ( + super.isAttacked(sq, color) || + this.isAttackedByAntiking(sq, color) + ); + } + + isAttackedByPawn([x, y], color) { + let pawnShift = (color == "w" ? 1 : -1); + if (x + pawnShift >= 0 && x + pawnShift < V.size.x) { + if ( + this.getPiece(x + pawnShift, y) == V.PAWN && + this.getColor(x + pawnShift, y) == color + ) { + return true; + } + } + return false; + } + + isAttackedByKing([x, y], color) { + // Antiking is not attacked by king: + if (this.getPiece(x, y) == V.ANTIKING) return false; + return this.isAttackedBySlideNJump( + [x, y], + color, + V.KING, + V.steps[V.ROOK].concat(V.steps[V.BISHOP]), + "oneStep" + ); + } + + isAttackedByAntiking([x, y], color) { + // (Anti)King is not attacked by antiking + if ([V.KING, V.ANTIKING].includes(this.getPiece(x, y))) return false; + return this.isAttackedBySlideNJump( + [x, y], + color, + V.ANTIKING, + V.steps[V.ROOK].concat(V.steps[V.BISHOP]), + "oneStep" + ); + } + + underCheck(color) { + const oppCol = V.GetOppCol(color); + let res = + this.isAttacked(this.kingPos[color], oppCol) || + !this.isAttacked(this.antikingPos[color], oppCol); + return res; + } + + getCheckSquares(color) { + let res = []; + const oppCol = V.GetOppCol(color); + if (this.isAttacked(this.kingPos[color], oppCol)) + res.push(JSON.parse(JSON.stringify(this.kingPos[color]))); + if (!this.isAttacked(this.antikingPos[color], oppCol)) + res.push(JSON.parse(JSON.stringify(this.antikingPos[color]))); + return res; + } + + postPlay(move) { + super.postPlay(move); + const piece = move.vanish[0].p; + const c = move.vanish[0].c; + // Update antiking position, and kings flags + if (piece == V.ANTIKING) { + this.antikingPos[c][0] = move.appear[0].x; + this.antikingPos[c][1] = move.appear[0].y; + this.kingFlags[c][1] = false; + } else if (piece == V.KING) this.kingFlags[c][0] = false; + } + + postUndo(move) { + super.postUndo(move); + const c = move.vanish[0].c; + if (move.vanish[0].p == V.ANTIKING) + this.antikingPos[c] = [move.start.x, move.start.y]; + } + + getCurrentScore() { + if (this.atLeastOneMove()) + return "*"; + + const color = this.turn; + const oppCol = V.GetOppCol(color); + if ( + !this.isAttacked(this.kingPos[color], oppCol) && + this.isAttacked(this.antikingPos[color], oppCol) + ) { + return "1/2"; + } + return color == "w" ? "0-1" : "1-0"; + } + + static get VALUES() { + return Object.assign( + { a: 1000 }, + ChessRules.VALUES + ); + } + + static GenRandInitFen() { + // Always deterministic setup + return "2prbkqA/2p1nnbr/2pppppp/8/8/PPPPPP2/RBNN1P2/aQKBRP2 w 0 1111"; + } + + static get SEARCH_DEPTH() { + return 2; + } +}; diff --git a/client/src/variants/Antiking.js b/client/src/variants/Antiking2.js similarity index 91% rename from client/src/variants/Antiking.js rename to client/src/variants/Antiking2.js index 94c8af6d..3be41af5 100644 --- a/client/src/variants/Antiking.js +++ b/client/src/variants/Antiking2.js @@ -2,7 +2,7 @@ import { ChessRules } from "@/base_rules"; import { ArrayFun } from "@/utils/array"; import { randInt } from "@/utils/alea"; -export const VariantRules = class AntikingRules extends ChessRules { +export const VariantRules = class Antiking2Rules extends ChessRules { static get ANTIKING() { return "a"; } @@ -46,8 +46,10 @@ export const VariantRules = class AntikingRules extends ChessRules { const color2 = this.getColor(x2, y2); return ( piece2 != "a" && - ((piece1 != "a" && color1 != color2) || - (piece1 == "a" && color1 == color2)) + ( + (piece1 != "a" && color1 != color2) || + (piece1 == "a" && color1 == color2) + ) ); } @@ -61,6 +63,7 @@ export const VariantRules = class AntikingRules extends ChessRules { } getPotentialAntikingMoves(sq) { + // The antiking moves like a king (only captured colors differ) return this.getSlideNJumpMoves( sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), @@ -78,13 +81,7 @@ export const VariantRules = class AntikingRules extends ChessRules { isAttackedByKing([x, y], color) { // Antiking is not attacked by king: if (this.getPiece(x, y) == V.ANTIKING) return false; - return this.isAttackedBySlideNJump( - [x, y], - color, - V.KING, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); + return super.isAttackedByKing([x, y], color); } isAttackedByAntiking([x, y], color) { @@ -108,8 +105,11 @@ export const VariantRules = class AntikingRules extends ChessRules { } getCheckSquares(color) { - let res = super.getCheckSquares(color); - if (!this.isAttacked(this.antikingPos[color], V.GetOppCol(color))) + let res = []; + const oppCol = V.GetOppCol(color); + if (this.isAttacked(this.kingPos[color], oppCol)) + res.push(JSON.parse(JSON.stringify(this.kingPos[color]))); + if (!this.isAttacked(this.antikingPos[color], oppCol)) res.push(JSON.parse(JSON.stringify(this.antikingPos[color]))); return res; } diff --git a/client/src/variants/Baroque.js b/client/src/variants/Baroque.js index c7c100c6..a19d09e5 100644 --- a/client/src/variants/Baroque.js +++ b/client/src/variants/Baroque.js @@ -7,6 +7,10 @@ export const VariantRules = class BaroqueRules extends ChessRules { return false; } + static get HasCastle() { + return false; + } + static get HasEnpassant() { return false; } @@ -352,14 +356,6 @@ export const VariantRules = class BaroqueRules extends ChessRules { return super.getPotentialQueenMoves(sq); } - getPotentialKingMoves(sq) { - return this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); - } - // isAttacked() is OK because the immobilizer doesn't take isAttackedByPawn([x, y], color) { diff --git a/client/src/variants/Benedict.js b/client/src/variants/Benedict.js index 73a55088..f0d4f2ba 100644 --- a/client/src/variants/Benedict.js +++ b/client/src/variants/Benedict.js @@ -103,35 +103,6 @@ export const VariantRules = class BenedictRules extends ChessRules { return moves; } - getPotentialRookMoves(sq) { - return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]); - } - - getPotentialKnightMoves(sq) { - return this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep"); - } - - getPotentialBishopMoves(sq) { - return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]); - } - - getPotentialQueenMoves(sq) { - return this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]) - ); - } - - getPotentialKingMoves(sq) { - // Initialize with normal (non-capturing) moves - let noCaptures = this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); - return noCaptures.concat(this.getCastleMoves(sq)); - } - // No "under check" verifications: getCastleMoves([x, y]) { const c = this.getColor(x, y); diff --git a/client/src/variants/Circular.js b/client/src/variants/Circular.js index 5468dc54..61997f29 100644 --- a/client/src/variants/Circular.js +++ b/client/src/variants/Circular.js @@ -158,14 +158,6 @@ export const VariantRules = class CircularRules extends ChessRules { return moves; } - getPotentialKingMoves(sq) { - return this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); - } - filterValid(moves) { const filteredMoves = super.filterValid(moves); // If at least one full move made, everything is allowed: diff --git a/client/src/variants/Hidden.js b/client/src/variants/Hidden.js index 79c3dfbd..8a5858ea 100644 --- a/client/src/variants/Hidden.js +++ b/client/src/variants/Hidden.js @@ -7,6 +7,10 @@ export const VariantRules = class HiddenRules extends ChessRules { return false; } + static get HasCastle() { + return false; + } + static get HasEnpassant() { return false; } @@ -143,16 +147,6 @@ export const VariantRules = class HiddenRules extends ChessRules { return mv; } - // What are the king moves from square x,y ? - getPotentialKingMoves(sq) { - // No castling: - return this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); - } - filterValid(moves) { return moves; } diff --git a/client/src/variants/Royalrace.js b/client/src/variants/Royalrace.js index 346ca5f0..c9095558 100644 --- a/client/src/variants/Royalrace.js +++ b/client/src/variants/Royalrace.js @@ -7,6 +7,10 @@ export const VariantRules = class RoyalraceRules extends ChessRules { return false; } + static get HasCastle() { + return false; + } + static get HasEnpassant() { return false; } @@ -133,15 +137,6 @@ export const VariantRules = class RoyalraceRules extends ChessRules { return this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT]); } - // What are the king moves from square x,y ? - getPotentialKingMoves(sq) { - return this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); - } - filterValid(moves) { if (moves.length == 0) return []; const color = this.turn; diff --git a/client/src/variants/Shatranj.js b/client/src/variants/Shatranj.js index 969b8197..45a34c04 100644 --- a/client/src/variants/Shatranj.js +++ b/client/src/variants/Shatranj.js @@ -5,6 +5,10 @@ export const VariantRules = class ShatranjRules extends ChessRules { return false; } + static get HasCastle() { + return false; + } + static get HasEnpassant() { return false; } @@ -90,14 +94,6 @@ export const VariantRules = class ShatranjRules extends ChessRules { ); } - getPotentialKingMoves(sq) { - return this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); - } - isAttackedByBishop(sq, color) { return this.isAttackedBySlideNJump( sq, diff --git a/client/src/variants/Suicide.js b/client/src/variants/Suicide.js index 24e8ef29..4bb5d36b 100644 --- a/client/src/variants/Suicide.js +++ b/client/src/variants/Suicide.js @@ -7,6 +7,10 @@ export const VariantRules = class SuicideRules extends ChessRules { return false; } + static get HasCastle() { + return false; + } + getPotentialPawnMoves([x, y]) { let moves = super.getPotentialPawnMoves([x, y]); @@ -44,15 +48,6 @@ export const VariantRules = class SuicideRules extends ChessRules { return moves; } - getPotentialKingMoves(sq) { - // No castle: - return this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); - } - // Trim all non-capturing moves (not the most efficient, but easy) static KeepCaptures(moves) { return moves.filter(m => m.vanish.length == 2); diff --git a/client/src/variants/Upsidedown.js b/client/src/variants/Upsidedown.js index 10bb83dd..e8242004 100644 --- a/client/src/variants/Upsidedown.js +++ b/client/src/variants/Upsidedown.js @@ -7,17 +7,12 @@ export const VariantRules = class UpsidedownRules extends ChessRules { return false; } - static get HasEnpassant() { + static get HasCastle() { return false; } - getPotentialKingMoves(sq) { - // No castle - return this.getSlideNJumpMoves( - sq, - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); + static get HasEnpassant() { + return false; } static GenRandInitFen(randomness) { diff --git a/server/db/populate.sql b/server/db/populate.sql index 72dff2ec..c37709b7 100644 --- a/server/db/populate.sql +++ b/server/db/populate.sql @@ -4,7 +4,8 @@ insert or ignore into Variants (name,description) values ('Alice', 'Both sides of the mirror'), ('Allmate1', 'Mate any piece (v1)'), ('Allmate2', 'Mate any piece (v2)'), - ('Antiking', 'Keep antiking in check'), + ('Antiking1', 'Keep antiking in check (v1)'), + ('Antiking2', 'Keep antiking in check (v2)'), ('Antimatter', 'Dangerous collisions'), ('Arena', 'Middle battle'), ('Atomic', 'Explosive captures'),