From f9385686d9434c607cdaa55e41a0425269db0815 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Sat, 28 Mar 2020 20:49:02 +0100 Subject: [PATCH] Add Horde variant + fix typos --- client/src/translations/en.js | 1 + client/src/translations/es.js | 1 + client/src/translations/fr.js | 1 + client/src/translations/rules/Horde/en.pug | 35 +++++++++++ client/src/translations/rules/Horde/es.pug | 36 +++++++++++ client/src/translations/rules/Horde/fr.pug | 36 +++++++++++ client/src/variants/Dynamo.js | 49 ++++++++------- client/src/variants/Horde.js | 69 ++++++++++++++++++++++ server/db/populate.sql | 1 + 9 files changed, 203 insertions(+), 26 deletions(-) create mode 100644 client/src/translations/rules/Horde/en.pug create mode 100644 client/src/translations/rules/Horde/es.pug create mode 100644 client/src/translations/rules/Horde/fr.pug create mode 100644 client/src/variants/Horde.js diff --git a/client/src/translations/en.js b/client/src/translations/en.js index ef503530..04900207 100644 --- a/client/src/translations/en.js +++ b/client/src/translations/en.js @@ -156,6 +156,7 @@ export const translations = { // Variants boxes: "64 pieces on the board": "64 pieces on the board", + "A pawns cloud": "A pawns cloud", "Ancient rules": "Ancient rules", "Attract opposite king": "Attract opposite king", "Balanced sliders & leapers": "Balanced sliders & leapers", diff --git a/client/src/translations/es.js b/client/src/translations/es.js index c5c32af3..32282e25 100644 --- a/client/src/translations/es.js +++ b/client/src/translations/es.js @@ -156,6 +156,7 @@ export const translations = { // Variants boxes: "64 pieces on the board": "64 piezas en el tablero", + "A pawns cloud": "Une nube de peones", "Ancient rules": "Viejas reglas", "Attract opposite king": "Atraer al rey contrario", "Balanced sliders & leapers": "Modos de desplazamiento equilibrados", diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js index e2c5f236..0e516844 100644 --- a/client/src/translations/fr.js +++ b/client/src/translations/fr.js @@ -156,6 +156,7 @@ export const translations = { // Variants boxes: "64 pieces on the board": "64 pièces sur l'échiquier", + "A pawns cloud": "Une nuée de pions", "Ancient rules": "Règles anciennes", "Attract opposite king": "Attirer le roi adverse", "Balanced sliders & leapers": "Modes de déplacement équilibrés", diff --git a/client/src/translations/rules/Horde/en.pug b/client/src/translations/rules/Horde/en.pug new file mode 100644 index 00000000..66538b1b --- /dev/null +++ b/client/src/translations/rules/Horde/en.pug @@ -0,0 +1,35 @@ +p.boxed + | A horde of 36 pawns is fighting to checkmate the king. + | Black goal is to eliminate all white pieces. + +p. + The initial configuration shows 36 white pawns, filling the four first ranks + and half of the fifth: + +figure.diagram-container + .diagram + | fen:rnbqkbnr/pppppppp/8/1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPP: + figcaption Deterministic starting position. + +p. + From white perspective, the material is unusual but the goal is the same as + in orthodox chess. Since there is no white king, black wins by capturing all + white pieces. + +p. + There is no castling, but en-passant captures may be executed after each two + squares pawn move, either from the first or second rank. + +h3 Source + +p + | This variant is inspired by + a(href="https://www.chessvariants.com/unequal.dir/dunsany.html") + | Dunsany's Chess + | , invented by Lord Dunsany in 1942. The additional white pawns are here to + | balance the game. See also + a(href="https://lichess.org/variant/horde") Horde on lichess.org + |   and + a(href="https://docs.google.com/document/d/136BCRPzm1QH_OBK3qjKwlmK3MIji7ZmLZPMYgDpmOCU/edit") + | this document + |  about the strategy to adopt for both sides. diff --git a/client/src/translations/rules/Horde/es.pug b/client/src/translations/rules/Horde/es.pug new file mode 100644 index 00000000..15571fe5 --- /dev/null +++ b/client/src/translations/rules/Horde/es.pug @@ -0,0 +1,36 @@ +p.boxed + | Una horda de 36 peones lucha para dar jaque mate al rey contrario. + | El objetivo de las negras es eliminar todas las piezas blancas. + +p. + 36 peones blancos están presentes en la configuración inicial, + llenando las primeras cuatro filas y la mitad de la quinta: + +figure.diagram-container + .diagrama + | fen:rnbqkbnr/pppppppp/8/1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPPP: + figcaption Posición de inicio determinista. + +p. + Desde un punto de vista blanco, el material es inusual pero el objetivo sigue + siendo lo mismo que el ajedrez ortodoxo. Como no hay un rey blanco, las + negras gana capturando todas las piezas blancas. + +p. + El enroque no es posible, pero las capturas al pasar pueden ser + ejecutado después de cualquier movimiento de peón por dos espacios, desde el + primera o segunda fila. + +h3 Fuente + +p + | Esta variante está inspirada por el + a(href="https://www.chessvariants.com/unequal.dir/dunsany.html") + | Ajedrez de Dunsany + | , inventado por Lord Dunsany en 1942. Peones blancos adicionales + | sirven para equilibrar el juego. Ver también + a(href="https://lichess.org/variant/horde") Horda en lichess.org + |   y + a(href="https://docs.google.com/document/d/136BCRPzm1QH_OBK3qjKwlmK3MIji7ZmLZPMYgDpmOCU/edit") + | este documento + |   sobre la estrategia a adoptar para cada campamento. diff --git a/client/src/translations/rules/Horde/fr.pug b/client/src/translations/rules/Horde/fr.pug new file mode 100644 index 00000000..92809794 --- /dev/null +++ b/client/src/translations/rules/Horde/fr.pug @@ -0,0 +1,36 @@ +p.boxed + | Une horde de 36 pions combat pour mater le roi adverse. + | L'objectif des noirs est d'éliminer toutes les pièces blanches. + +p. + 36 pions blancs sont présents dans la configuration initiale, + remplissant les quatre premières rangées et la moitié de la cinquième : + +figure.diagram-container + .diagram + | fen:rnbqkbnr/pppppppp/8/1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPP: + figcaption Position de départ déterministe. + +p. + Du point de vue des blancs, le matériel est inhabituel mais l'objectif reste + le même qu'aux échecs orthodoxes. Puisqu'il n'y a pas de roi blanc, les noirs + gagnent en capturant toutes les pièces blanches. + +p. + Le roque n'est pas possible, mais les prises en passant peuvent être + exécutées après n'importe quel déplacement de pion de deux cases, depuis la + première ou seconde rangée. + +h3 Source + +p + | Cette variante est inspirée par les + a(href="https://www.chessvariants.com/unequal.dir/dunsany.html") + | Échecs de Dunsany + | , inventés par Lord Dunsany en 1942. Les pions blancs supplémentaires + | servent à équilibrer le jeu. Voir aussi la + a(href="https://lichess.org/variant/horde") Horde sur lichess.org + |   et + a(href="https://docs.google.com/document/d/136BCRPzm1QH_OBK3qjKwlmK3MIji7ZmLZPMYgDpmOCU/edit") + | ce document + |  sur la stratégie à adopter pour chaque camp. diff --git a/client/src/variants/Dynamo.js b/client/src/variants/Dynamo.js index c600b8ae..9f4cf3ff 100644 --- a/client/src/variants/Dynamo.js +++ b/client/src/variants/Dynamo.js @@ -73,7 +73,7 @@ export class DynamoRules extends ChessRules { if ( this.subTurn == 2 && square.x == this.firstMove.end.x && - square.y == this.firstMove.end.y) + square.y == this.firstMove.end.y ) { return { appear: [], @@ -186,32 +186,29 @@ export class DynamoRules extends ChessRules { if (this.getColor(x, y) != color) // The only moves possible with enemy pieces are pulls and pushes: return this.getPactions([x, y], color); - else { - // Playing my pieces: either on their own, or pushed by another - // If subTurn == 2 then we should have a first move, - // TODO = use it to allow some type of action - if (this.subTurn == 2) { - return ( - this.moveOnSubturn1.isAnAction - ? super.getPotentialMovesFrom([x, y]) - : this.getPactions([x, y], color, TODO_arg) - ); - } else { - // Both options are possible at subTurn1: normal move, or push - moves = - super.getPotentialMovesFrom([x, y]) - .concat(this.getPactions([x, y], color, "push"); - // TODO: discard moves that let the king underCheck, and no second - // move can counter check. Example: pinned queen pushes pinned pawn. - .filter(m => { - this.play(m); - const res = this.filterMoves(this.getPotentialMoves(/* TODO: args? */)).length > 0; - this.undo(m); - return res; - }); - } + // Playing my pieces: either on their own, or pushed by another + // If subTurn == 2 then we should have a first move, + // TODO = use it to allow some type of action + if (this.subTurn == 2) { + return ( + this.moveOnSubturn1.isAnAction + ? super.getPotentialMovesFrom([x, y]) + : this.getPactions([x, y], color, TODO_arg) + ); } - return moves; + // Both options are possible at subTurn1: normal move, or push + return ( + super.getPotentialMovesFrom([x, y]) + .concat(this.getPactions([x, y], color, "push")) + // TODO: discard moves that let the king underCheck, and no second + // move can counter check. Example: pinned queen pushes pinned pawn. + .filter(m => { + this.play(m); + const res = this.filterMoves(this.getPotentialMoves(/* TODO: args? */)).length > 0; + this.undo(m); + return res; + }) + ); } // TODO: track rooks locations, should be a field in FEN, in castleflags? diff --git a/client/src/variants/Horde.js b/client/src/variants/Horde.js new file mode 100644 index 00000000..e61803b3 --- /dev/null +++ b/client/src/variants/Horde.js @@ -0,0 +1,69 @@ +import { ChessRules } from "@/base_rules"; + +export class HordeRules extends ChessRules { + static get HasFlags() { + return false; + } + + static IsGoodPosition() { + // At least one white unit, and exactly one black king: + if (position.length == 0) return false; + const rows = position.split("/"); + if (rows.length != V.size.x) return false; + let things = { "k": 0, "w": false }; + for (let row of rows) { + let sumElts = 0; + for (let i = 0; i < row.length; i++) { + if (row[i] == 'k') things['k']++; + if (V.PIECES.includes(row[i].toLowerCase())) { + const rowCharCode = row[i].charCodeAt(0); + if (rowCharCode >= 65 && rowCharCode <= 90) { + // No white king: + if (row[i] == 'K') return false; + if (!things['w']) things['w'] = true; + } + sumElts++; + } else { + const num = parseInt(row[i]); + if (isNaN(num)) return false; + sumElts += num; + } + } + if (sumElts != V.size.y) return false; + } + if (things[''] != 1 || !things['w']) return false; + return true; + } + + static GenRandInitFen(randomness) { + if (randomness == 2) randomness--; + const fen = ChessRules.GenRandInitFen(randomness); + return ( + // 27 first chars are 3 rows + 3 slashes + fen.substr(0, 27) + // En passant available, but no castle: + .concat("1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPP w 0 -") + ); + } + + getCurrentScore() { + if (this.turn == 'w') { + // Do I have any unit remaining? If not, I lost. + // If yes and no available move, draw. + let somethingRemains = false; + outerLoop: for (let i=0; i<8; i++) { + for (let j=0; j<8; j++) { + if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == 'w') { + somethingRemains = true; + break outerLoop; + } + } + } + if (!somethingRemains) return "0-1"; + if (this.atLeastOneMove()) return "*"; + return "1/2"; + } + // From black side, just run usual checks: + return super.getCurrentScore(); + } +}; diff --git a/server/db/populate.sql b/server/db/populate.sql index 5046b54b..147868d9 100644 --- a/server/db/populate.sql +++ b/server/db/populate.sql @@ -36,6 +36,7 @@ insert or ignore into Variants (name, description) values ('Extinction', 'Capture all of a kind'), ('Grand', 'Big board'), ('Grasshopper', 'Long jumps over pieces'), + ('Horde', 'A pawns cloud'), ('Knightmate', 'Mate the knight'), ('Knightrelay1', 'Move like a knight (v1)'), ('Knightrelay2', 'Move like a knight (v2)'), -- 2.44.0