From: Benjamin Auder Date: Sat, 18 Apr 2020 02:14:26 +0000 (+0200) Subject: Add Diamond Chess X-Git-Url: https://git.auder.net/doc/html/%7B%7B%20asset%28%27mixstore/css/user/common.css%27%29%20%7D%7D?a=commitdiff_plain;h=59e74176f5e2e828ce0b81c2ead6f8cdb0654f69;p=vchess.git Add Diamond Chess --- diff --git a/client/src/translations/en.js b/client/src/translations/en.js index 520c4823..e3fb36df 100644 --- a/client/src/translations/en.js +++ b/client/src/translations/en.js @@ -217,6 +217,7 @@ export const translations = { "Queen disguised as a pawn": "Queen disguised as a pawn", "Reuse pieces": "Reuse pieces", "Reverse captures": "Reverse captures", + "Rotating board": "Rotating board", "Run forward": "Run forward", "Score a goal": "Score a goal", "Seirawan-Harper Chess": "Seirawan-Harper Chess", diff --git a/client/src/translations/es.js b/client/src/translations/es.js index f803df2c..556072bd 100644 --- a/client/src/translations/es.js +++ b/client/src/translations/es.js @@ -217,6 +217,7 @@ export const translations = { "Queen disguised as a pawn": "Reina disfrazada de peón", "Reuse pieces": "Reutilizar piezas", "Reverse captures": "Capturas invertidas", + "Rotating board": "Tablero giratorio", "Run forward": "Correr hacia adelante", "Score a goal": "Marcar una meta", "Seirawan-Harper Chess": "Ajedrez Seirawan-Harper", diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js index e73e2e50..eb345b8e 100644 --- a/client/src/translations/fr.js +++ b/client/src/translations/fr.js @@ -217,6 +217,7 @@ export const translations = { "Queen disguised as a pawn": "Reine déguisée en pion", "Reuse pieces": "Réutiliser les pièces", "Reverse captures": "Captures inversées", + "Rotating board": "Échiquier tournant", "Run forward": "Courir vers l'avant", "Score a goal": "Marquer un but", "Seirawan-Harper Chess": "Échecs Seirawan-Harper", diff --git a/client/src/translations/rules/Diamond/en.pug b/client/src/translations/rules/Diamond/en.pug new file mode 100644 index 00000000..95af3245 --- /dev/null +++ b/client/src/translations/rules/Diamond/en.pug @@ -0,0 +1,25 @@ +p.boxed + | The board is rotated by 45°, and then the game follow usual rules. + +p. + White (resp. Black) pawns move one square diagonally north-west: h1 to a8 + (resp. south-east: a8 to h1). + White (resp. Black) pawns capture on the adjacent orthogonal squares either + up or to the left (resp. down or to the right). + This is natural after rotating the board by 45° clockwise, + explaining the name "Diamond Chess". + +p All other pieces move like in orthodox chess. + +figure.diagram-container + .diagram + | fen:8/1p6/1B4P1/8/8/3n4/3pP3/8 b6,c6,d2,f7: + figcaption Pawn moves. + +h3 Source + +p + a(href="https://www.chessvariants.com/rules/diamond-chess") Diamond Chess + |  on chessvariants.com. + +p Inventor: James Alexander Porterfield Rynd (1886) diff --git a/client/src/translations/rules/Diamond/es.pug b/client/src/translations/rules/Diamond/es.pug new file mode 100644 index 00000000..672283fa --- /dev/null +++ b/client/src/translations/rules/Diamond/es.pug @@ -0,0 +1,26 @@ +p.boxed + | El tablero de ajedrez gira 45°, luego el juego sigue las reglas habituales. + +p. + Los peones blancos (resp. negros) avanzan un espacio en diagonal al noroeste: + h1 a a8 (resp. sureste: a8 a h1). + Los peones blancos (resp. Negro) capturan en un cuadrado ortogonalmente + adyacente ya sea arriba o a la izquierda (resp. abajo o hacia la derecha). + Es natural después de girar el tablero de ajedrez 45° en la dirección + cada hora, explicando el nombre "Ajedrez diamante". + +p Todas las otras piezas se mueven como en el ajedrez ortodoxo. + +figure.diagram-container + .diagram + | fen:8/1p6/1B4P1/8/8/3n4/3pP3/8 b6,c6,d2,f7: + figcaption Juagadas del peón. + +h3 Fuente + +p + | La + a(href="https://www.chessvariants.com/rules/diamond-chess") variante Diamond + |  en chessvariants.com. + +p Inventor: James Alexander Porterfield Rynd (1886) diff --git a/client/src/translations/rules/Diamond/fr.pug b/client/src/translations/rules/Diamond/fr.pug new file mode 100644 index 00000000..a4dbb0ff --- /dev/null +++ b/client/src/translations/rules/Diamond/fr.pug @@ -0,0 +1,26 @@ +p.boxed + | L'échiquier est tourné de 45°, puis la partie suit les règles habituelles. + +p. + Les pions blancs (resp. noirs) avancent d'une case en diagonale nord-ouest : + h1 vers a8 (resp. sud-est : a8 vers h1). + Les pions blancs (resp. noirs) capturent sur une case orthogonalement + adjacente soit au dessus soit vers la gauche (resp. en dessous ou vers la + droite). C'est naturel après avoir tourné l'échiquier de 45° dans le sens + horaire, expliquant le nom "Échecs Diamant". + +p Toutes les autres pièces se déplacent comme aux échecs orthodoxes. + +figure.diagram-container + .diagram + | fen:8/1p6/1B4P1/8/8/3n4/3pP3/8 b6,c6,d2,f7: + figcaption Coups de pion. + +h3 Source + +p + | La + a(href="https://www.chessvariants.com/rules/diamond-chess") variante Diamond + |  sur chessvariants.com. + +p Inventeur : James Alexander Porterfield Rynd (1886) diff --git a/client/src/variants/Berolina.js b/client/src/variants/Berolina.js index 8473b13e..a7f7afa7 100644 --- a/client/src/variants/Berolina.js +++ b/client/src/variants/Berolina.js @@ -129,15 +129,11 @@ export class BerolinaRules extends ChessRules { 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; + return ( + x + pawnShift >= 0 && x + pawnShift < V.size.x && + this.getPiece(x + pawnShift, y) == V.PAWN && + this.getColor(x + pawnShift, y) == color + ); } static get SEARCH_DEPTH() { diff --git a/client/src/variants/Diamond.js b/client/src/variants/Diamond.js new file mode 100644 index 00000000..2a3869ed --- /dev/null +++ b/client/src/variants/Diamond.js @@ -0,0 +1,139 @@ +import { ChessRules } from "@/base_rules"; +import { ArrayFun } from "@/utils/array"; +import { shuffle } from "@/utils/alea"; + +export class DiamondRules extends ChessRules { + static get HasFlags() { + return false; + } + + static get HasEnpassant() { + return false; + } + + static GenRandInitFen(randomness) { + if (randomness == 0) + return "krbp4/rqnp4/nbpp4/pppp4/4PPPP/4PPBN/4PNQR/4PBRK w 0"; + let pieces = { w: new Array(8), b: new Array(8) }; + for (let c of ["w", "b"]) { + if (c == 'b' && randomness == 1) { + pieces['b'] = pieces['w']; + break; + } + // Get random squares for every piece, totally freely + let positions = shuffle(ArrayFun.range(8)); + const composition = ['b', 'b', 'r', 'r', 'n', 'n', 'k', 'q']; + const rem2 = positions[0] % 2; + if (rem2 == positions[1] % 2) { + // Fix bishops (on different colors) + for (let i=2; i<8; i++) { + if (positions[i] % 2 != rem2) + [positions[1], positions[i]] = [positions[i], positions[1]]; + } + } + for (let i = 0; i < 8; i++) pieces[c][positions[i]] = composition[i]; + } + return ( + pieces["b"].slice(0, 3).join("") + "p4/" + + pieces["b"].slice(3, 6).join("") + "p4/" + + pieces["b"].slice(6, 8).join("") + "pp4/" + + "pppp4/4PPPP/" + + "4PP" + pieces["w"].slice(6, 8).reverse().join("").toUpperCase() + "/" + + "4P" + pieces["w"].slice(3, 6).reverse().join("").toUpperCase() + "/" + + "4P" + pieces["w"].slice(0, 3).reverse().join("").toUpperCase() + + " w 0" + ); + } + + // Special pawns movements + getPotentialPawnMoves([x, y]) { + const color = this.turn; + let moves = []; + const [sizeX, sizeY] = [V.size.x, V.size.y]; + const shift = (color == "w" ? -1 : 1); + const lastRank = (color == "w" ? 0 : 7); + + // One square forward (diagonally along h1-a8) + if (this.board[x + shift][y + shift] == V.EMPTY) { + const finalPieces = + [x + shift, y + shift].includes(lastRank) + ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN] + : [V.PAWN]; + for (let piece of finalPieces) { + moves.push( + this.getBasicMove( + [x, y], [x + shift, y + shift], { c: color, p: piece }) + ); + } + } + // Capture + for (let pShift of [[0, shift], [shift, 0]]) { + if ( + this.board[x + pShift[0]][y + pShift[1]] != V.EMPTY && + this.canTake([x, y], [x + pShift[0], y + pShift[1]]) + ) { + const finalPieces = + [x + pShift[0], y + pShift[1]].includes(lastRank) + ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN] + : [V.PAWN]; + for (let piece of finalPieces) { + moves.push( + this.getBasicMove( + [x, y], + [x + pShift[0], y + pShift[1]], + { + c: color, + p: piece + } + ) + ); + } + } + } + + return moves; + } + + isAttackedByPawn([x, y], color) { + let pawnShift = (color == "w" ? 1 : -1); + return ( + ( + x + pawnShift >= 0 && x + pawnShift < V.size.x && + this.getPiece(x + pawnShift, y) == V.PAWN && + this.getColor(x + pawnShift, y) == color + ) + || + ( + y + pawnShift >= 0 && y + pawnShift < V.size.y && + this.getPiece(x, y + pawnShift) == V.PAWN && + this.getColor(x, y + pawnShift) == color + ) + ); + } + + static get SEARCH_DEPTH() { + return 2; + } + + getNotation(move) { + const piece = this.getPiece(move.start.x, move.start.y); + if (piece == V.PAWN) { + // Pawn move + const finalSquare = V.CoordsToSquare(move.end); + let notation = ""; + if (move.vanish.length == 2) + // Capture + notation = "Px" + finalSquare; + else { + // No capture: indicate the initial square for potential ambiguity + const startSquare = V.CoordsToSquare(move.start); + notation = startSquare + finalSquare; + } + if (move.appear[0].p != V.PAWN) + // Promotion + notation += "=" + move.appear[0].p.toUpperCase(); + return notation; + } + return super.getNotation(move); //all other pieces are orthodox + } +}; diff --git a/server/db/populate.sql b/server/db/populate.sql index 48f97c03..21f7c7a8 100644 --- a/server/db/populate.sql +++ b/server/db/populate.sql @@ -32,6 +32,7 @@ insert or ignore into Variants (name, description) values ('Coregal', 'Two royal pieces'), ('Crazyhouse', 'Captures reborn'), ('Cylinder', 'Neverending rows'), + ('Diamond', 'Rotating board'), ('Doublearmy', '64 pieces on the board'), ('Doublemove1', 'Double moves (v1)'), ('Doublemove2', 'Double moves (v2)'),