Pandemonium 1 & 2, Stealthbomb 1 & 2
authorBenjamin Auder <benjamin.auder@somewhere>
Thu, 25 Mar 2021 11:18:43 +0000 (12:18 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Thu, 25 Mar 2021 11:18:43 +0000 (12:18 +0100)
27 files changed:
client/src/translations/en.js
client/src/translations/es.js
client/src/translations/fr.js
client/src/translations/rules/Pandemonium1/en.pug [moved from client/src/translations/rules/Pandemonium/en.pug with 100% similarity]
client/src/translations/rules/Pandemonium1/es.pug [moved from client/src/translations/rules/Pandemonium/es.pug with 100% similarity]
client/src/translations/rules/Pandemonium1/fr.pug [moved from client/src/translations/rules/Pandemonium/fr.pug with 100% similarity]
client/src/translations/rules/Pandemonium2/en.pug [new file with mode: 0644]
client/src/translations/rules/Pandemonium2/es.pug [new file with mode: 0644]
client/src/translations/rules/Pandemonium2/fr.pug [new file with mode: 0644]
client/src/translations/rules/Stealthbomb1/en.pug [moved from client/src/translations/rules/Stealthbomb/en.pug with 96% similarity]
client/src/translations/rules/Stealthbomb1/es.pug [moved from client/src/translations/rules/Stealthbomb/es.pug with 96% similarity]
client/src/translations/rules/Stealthbomb1/fr.pug [moved from client/src/translations/rules/Stealthbomb/fr.pug with 96% similarity]
client/src/translations/rules/Stealthbomb2/en.pug [new file with mode: 0644]
client/src/translations/rules/Stealthbomb2/es.pug [new file with mode: 0644]
client/src/translations/rules/Stealthbomb2/fr.pug [new file with mode: 0644]
client/src/translations/rules/Wildebeest/en.pug
client/src/translations/rules/Wildebeest/es.pug
client/src/translations/rules/Wildebeest/fr.pug
client/src/translations/variants/en.pug
client/src/translations/variants/es.pug
client/src/translations/variants/fr.pug
client/src/variants/Pandemonium1.js [new file with mode: 0644]
client/src/variants/Pandemonium2.js [moved from client/src/variants/Pandemonium.js with 78% similarity]
client/src/variants/Stealthbomb1.js [moved from client/src/variants/Stealthbomb.js with 97% similarity]
client/src/variants/Stealthbomb2.js [new file with mode: 0644]
client/src/variants/Wildebeest.js
server/db/populate.sql

index a86b6e1..38155cf 100644 (file)
@@ -181,7 +181,8 @@ export const translations = {
   "Augmented Queens": "Augmented Queens",
   "Balanced sliders & leapers": "Balanced sliders & leapers",
   "Baroque Music": "Baroque Music",
   "Augmented Queens": "Augmented Queens",
   "Balanced sliders & leapers": "Balanced sliders & leapers",
   "Baroque Music": "Baroque Music",
-  "Beware the bomb": "Beware the bomb",
+  "Beware the bomb (v1)": "Beware the bomb (v1)",
+  "Beware the bomb (v2)": "Beware the bomb (v2)",
   "Big board": "Big board",
   "Bishop versus pawns": "Bishop versus pawns",
   "Board upside down": "Board upside down",
   "Big board": "Big board",
   "Bishop versus pawns": "Bishop versus pawns",
   "Board upside down": "Board upside down",
@@ -277,7 +278,8 @@ export const translations = {
   "New fairy pieces": "New fairy pieces",
   "No paralyzed pieces": "No paralyzed pieces",
   "No-check mode": "No-check mode",
   "New fairy pieces": "New fairy pieces",
   "No paralyzed pieces": "No paralyzed pieces",
   "No-check mode": "No-check mode",
-  "Noise and confusion": "Noise and confusion",
+  "Noise and confusion (v1)": "Noise and confusion (v1)",
+  "Noise and confusion (v2)": "Noise and confusion (v2)",
   "Non-conformism and utopia": "Non-conformism and utopia",
   "Occupy the enemy palace": "Occupy the enemy palace",
   "Paralyzed pieces": "Paralyzed pieces",
   "Non-conformism and utopia": "Non-conformism and utopia",
   "Occupy the enemy palace": "Occupy the enemy palace",
   "Paralyzed pieces": "Paralyzed pieces",
index a5cd67b..9e8088b 100644 (file)
@@ -181,7 +181,8 @@ export const translations = {
   "Augmented Queens": "Damas aumentadas",
   "Balanced sliders & leapers": "Modos de desplazamiento equilibrados",
   "Baroque Music": "Música Barroca",
   "Augmented Queens": "Damas aumentadas",
   "Balanced sliders & leapers": "Modos de desplazamiento equilibrados",
   "Baroque Music": "Música Barroca",
-  "Beware the bomb": "Cuidado con la bomba",
+  "Beware the bomb (v1)": "Cuidado con la bomba (v1)",
+  "Beware the bomb (v2)": "Cuidado con la bomba (v2)",
   "Big board": "Gran tablero",
   "Bishop versus pawns": "Alfil contra peones",
   "Board upside down": "Tablero al revés",
   "Big board": "Gran tablero",
   "Bishop versus pawns": "Alfil contra peones",
   "Board upside down": "Tablero al revés",
@@ -277,7 +278,8 @@ export const translations = {
   "New fairy pieces": "Nuevas piezas magicas",
   "No paralyzed pieces": "No piezas paralizadas",
   "No-check mode": "Modo sin jaque",
   "New fairy pieces": "Nuevas piezas magicas",
   "No paralyzed pieces": "No piezas paralizadas",
   "No-check mode": "Modo sin jaque",
-  "Noise and confusion": "Ruido y confusión",
+  "Noise and confusion (v1)": "Ruido y confusión (v1)",
+  "Noise and confusion (v2)": "Ruido y confusión (v2)",
   "Non-conformism and utopia": "No-conformismo y utopía",
   "Occupy the enemy palace": "Ocupar el palacio enemigo",
   "Paralyzed pieces": "Piezas paralizadas",
   "Non-conformism and utopia": "No-conformismo y utopía",
   "Occupy the enemy palace": "Ocupar el palacio enemigo",
   "Paralyzed pieces": "Piezas paralizadas",
index 9ca4717..c095bb0 100644 (file)
@@ -181,7 +181,8 @@ export const translations = {
   "Augmented Queens": "Dames augmentées",
   "Balanced sliders & leapers": "Modes de déplacement équilibrés",
   "Baroque Music": "Musique Baroque",
   "Augmented Queens": "Dames augmentées",
   "Balanced sliders & leapers": "Modes de déplacement équilibrés",
   "Baroque Music": "Musique Baroque",
-  "Beware the bomb": "Attention à la bombe",
+  "Beware the bomb (v1)": "Attention à la bombe (v1)",
+  "Beware the bomb (v2)": "Attention à la bombe (v2)",
   "Big board": "Grand échiquier",
   "Bishop versus pawns": "Fou contre pions",
   "Board upside down": "Échiquier à l'envers",
   "Big board": "Grand échiquier",
   "Bishop versus pawns": "Fou contre pions",
   "Board upside down": "Échiquier à l'envers",
@@ -277,7 +278,8 @@ export const translations = {
   "New fairy pieces": "Nouvelles pièces féériques",
   "No paralyzed pieces": "Pas de pièces paralysées",
   "No-check mode": "Mode sans échec",
   "New fairy pieces": "Nouvelles pièces féériques",
   "No paralyzed pieces": "Pas de pièces paralysées",
   "No-check mode": "Mode sans échec",
-  "Noise and confusion": "Bruit et confusion",
+  "Noise and confusion (v1)": "Bruit et confusion (v1)",
+  "Noise and confusion (v2)": "Bruit et confusion (v2)",
   "Non-conformism and utopia": "Non-conformisme et utopie",
   "Occupy the enemy palace": "Occuper le palais ennemi",
   "Paralyzed pieces": "Pièces paralysées",
   "Non-conformism and utopia": "Non-conformisme et utopie",
   "Occupy the enemy palace": "Occuper le palais ennemi",
   "Paralyzed pieces": "Pièces paralysées",
diff --git a/client/src/translations/rules/Pandemonium2/en.pug b/client/src/translations/rules/Pandemonium2/en.pug
new file mode 100644 (file)
index 0000000..8f1570f
--- /dev/null
@@ -0,0 +1,14 @@
+p.boxed
+  | All pieces can promote. Captured units can be dropped later.
+  | 10x8 board. Some new pieces.
+
+figure.diagram-container
+  .diagram
+    | fen:rnbqkmcbnr/pppppppppp/91/91/91/91/PPPPPPPPPP/RNBQKMCBNR:
+  figcaption Initial deterministic position.
+
+p
+  a(href="/#/variants/Pandemonium1") Pandemonium1
+  | &nbsp;on a 10x8 board.
+  | Pawns move as in orthodox chess, and promotions
+  | occur only on the final rank.
diff --git a/client/src/translations/rules/Pandemonium2/es.pug b/client/src/translations/rules/Pandemonium2/es.pug
new file mode 100644 (file)
index 0000000..863d3e4
--- /dev/null
@@ -0,0 +1,14 @@
+p.boxed
+  | Todas las piezas pueden promocionarse. Las unidades capturadas son
+  | en paracaídas más tarde. Tablero de ajedrez 10x8. Algunas piezas nuevas.
+
+figure.diagram-container
+  .diagram
+    | fen:rnbqkmcbnr/pppppppppp/91/91/91/91/PPPPPPPPPP/RNBQKMCBNR:
+  figcaption Posición inicial determinista.
+
+p
+  a(href="/#/variants/Pandemonium1") Pandemonium1
+  | &nbsp;en un tablero 10x8.
+  | Los peones se mueven como en el ajedrez ortodoxo,
+  | y las promociones solo ocurren en la última fila.
diff --git a/client/src/translations/rules/Pandemonium2/fr.pug b/client/src/translations/rules/Pandemonium2/fr.pug
new file mode 100644 (file)
index 0000000..c70bd96
--- /dev/null
@@ -0,0 +1,14 @@
+p.boxed
+  | Toutes les pièces peuvent être promues. Les unités capturées sont
+  | parachutées plus tard. Échiquier 10x8. Quelques nouvelles pièces.
+
+figure.diagram-container
+  .diagram
+    | fen:rnbqkmcbnr/pppppppppp/91/91/91/91/PPPPPPPPPP/RNBQKMCBNR:
+  figcaption Position initiale déterministe.
+
+p
+  a(href="/#/variants/Pandemonium1") Pandemonium1
+  | &nbsp;sur un échiquier 10x8.
+  | Les pions se déplacent comme aux échecs orthodoxes,
+  | et les promotions ne surviennent que sur la dernière rangée.
@@ -29,3 +29,5 @@ p
   | . This variant is Stealthbomber on 
   a(href="fishrandom.io") fishrandom.io
   | , and "Stealthbomb" here... why not :-)
   | . This variant is Stealthbomber on 
   a(href="fishrandom.io") fishrandom.io
   | , and "Stealthbomb" here... why not :-)
+
+p Inventor: Jim Winslow (1992)
@@ -29,3 +29,5 @@ p
   | . Esta variante es Stealthbomber en 
   a(href="fishrandom.io") fishrandom.io
   | , y "Stealthbomb" aquí... ¿Por qué no? :-)
   | . Esta variante es Stealthbomber en 
   a(href="fishrandom.io") fishrandom.io
   | , y "Stealthbomb" aquí... ¿Por qué no? :-)
+
+p Inventor: Jim Winslow (1992)
@@ -29,3 +29,5 @@ p
   | . Cette variante est Stealthbomber sur 
   a(href="fishrandom.io") fishrandom.io
   | , et "Stealthbomb" ici... pourquoi pas :-)
   | . Cette variante est Stealthbomber sur 
   a(href="fishrandom.io") fishrandom.io
   | , et "Stealthbomb" ici... pourquoi pas :-)
+
+p Inventeur : Jim Winslow (1992)
diff --git a/client/src/translations/rules/Stealthbomb2/en.pug b/client/src/translations/rules/Stealthbomb2/en.pug
new file mode 100644 (file)
index 0000000..6ee7beb
--- /dev/null
@@ -0,0 +1,7 @@
+p.boxed.
+  One pawn of each side hides a bomb,
+  which can be triggered instead of playing a move.
+
+p
+  a(href="/#/variants/Stealthbomb1") Stealthbomb1
+  | , where only pawns can hold a bomb.
diff --git a/client/src/translations/rules/Stealthbomb2/es.pug b/client/src/translations/rules/Stealthbomb2/es.pug
new file mode 100644 (file)
index 0000000..b41a979
--- /dev/null
@@ -0,0 +1,7 @@
+p.boxed.
+  Un peon de cada campamento esconde una bomba,
+  que se puede activar en lugar de ejecutar un movimiento.
+
+p
+  a(href="/#/variants/Stealthbomb1") Stealthbomb1
+  | , donde solo los peones pueden llevar una bomba.
diff --git a/client/src/translations/rules/Stealthbomb2/fr.pug b/client/src/translations/rules/Stealthbomb2/fr.pug
new file mode 100644 (file)
index 0000000..14a90b8
--- /dev/null
@@ -0,0 +1,7 @@
+p.boxed.
+  Un pion de chaque camp cache une bombe,
+  qui peut être déclenchée au lieu de jouer un coup.
+
+p
+  a(href="/#/variants/Stealthbomb1") Stealthbomb1
+  | , où seuls les pions peuvent porter une bombe.
index 5f0b631..16323ee 100644 (file)
@@ -24,8 +24,9 @@ p.
   which will end next to him on the other side.
 
 p.
   which will end next to him on the other side.
 
 p.
-  When a pawn reaches last rank, it can promote
-  into a queen or a wildebeest (only).
+  When a pawn reaches the last rank, it promotes into a queen or a
+  wildebeest (only). Promotion is also possible (optionally) on 9th rank.
+  This is an experimental addition to the official rules.
 
 h3 Source
 
 
 h3 Source
 
index a407e33..e5e6d7d 100644 (file)
@@ -24,7 +24,10 @@ p.
   el rey puede saltar cualquier número de casillas (libres) a la torre,
   que terminará junto a él en el otro lado.
 
   el rey puede saltar cualquier número de casillas (libres) a la torre,
   que terminará junto a él en el otro lado.
 
-p Un peón en la última fila es promovido a dama o ñu solamente.
+p.
+  Un peón que llega a la última fila es promovido a dama o ñu solamente.
+  La promoción también es posible (opcionalmente) en la novena fila.
+  Es una adición experimental a las reglas oficiales.
 
 h3 Fuente
 
 
 h3 Fuente
 
index fb04759..52dfc3d 100644 (file)
@@ -26,7 +26,8 @@ p.
 
 p.
   Un pion arrivé sur la dernière rangée se promeut en une dame ou un gnou
 
 p.
   Un pion arrivé sur la dernière rangée se promeut en une dame ou un gnou
-  seulement.
+  seulement. La promotion est également possible (optionnellement)
+  sur la 9eme rangée. C'est un ajout expérimental aux règles officielles.
 
 h3 Source
 
 
 h3 Source
 
index c933d9c..0da0179 100644 (file)
@@ -222,7 +222,8 @@ p.
     "Dark",
     "Hidden",
     "Hiddenqueen",
     "Dark",
     "Hidden",
     "Hiddenqueen",
-    "Stealthbomb",
+    "Stealthbomb1",
+    "Stealthbomb2",
     "Synchrone1",
     "Synchrone2"
   ]
     "Synchrone1",
     "Synchrone2"
   ]
@@ -480,7 +481,8 @@ p.
     "Iceage",
     "Kingsmaker",
     "Magnetic",
     "Iceage",
     "Kingsmaker",
     "Magnetic",
-    "Pandemonium",
+    "Pandemonium1",
+    "Pandemonium2",
     "Refusal1",
     "Refusal2",
     "Relayup",
     "Refusal1",
     "Refusal2",
     "Relayup",
index 81fad93..cc246bd 100644 (file)
@@ -229,7 +229,8 @@ p.
     "Dark",
     "Hidden",
     "Hiddenqueen",
     "Dark",
     "Hidden",
     "Hiddenqueen",
-    "Stealthbomb",
+    "Stealthbomb1",
+    "Stealthbomb2",
     "Synchrone1",
     "Synchrone2"
   ]
     "Synchrone1",
     "Synchrone2"
   ]
@@ -490,7 +491,8 @@ p.
     "Iceage",
     "Kingsmaker",
     "Magnetic",
     "Iceage",
     "Kingsmaker",
     "Magnetic",
-    "Pandemonium",
+    "Pandemonium1",
+    "Pandemonium2",
     "Refusal1",
     "Refusal2",
     "Relayup",
     "Refusal1",
     "Refusal2",
     "Relayup",
index 6743ce2..ae68c66 100644 (file)
@@ -228,7 +228,8 @@ p.
     "Dark",
     "Hidden",
     "Hiddenqueen",
     "Dark",
     "Hidden",
     "Hiddenqueen",
-    "Stealthbomb",
+    "Stealthbomb1",
+    "Stealthbomb2",
     "Synchrone1",
     "Synchrone2"
   ]
     "Synchrone1",
     "Synchrone2"
   ]
@@ -488,7 +489,8 @@ p.
     "Iceage",
     "Kingsmaker",
     "Magnetic",
     "Iceage",
     "Kingsmaker",
     "Magnetic",
-    "Pandemonium",
+    "Pandemonium1",
+    "Pandemonium2",
     "Refusal1",
     "Refusal2",
     "Relayup",
     "Refusal1",
     "Refusal2",
     "Relayup",
diff --git a/client/src/variants/Pandemonium1.js b/client/src/variants/Pandemonium1.js
new file mode 100644 (file)
index 0000000..579ee9c
--- /dev/null
@@ -0,0 +1,128 @@
+import { Pandemonium2Rules } from "@/variants/Pandemonium2";
+
+export class Pandemonium1Rules extends Pandemonium2Rules {
+
+  static get PawnSpecs() {
+    return Object.assign(
+      { },
+      Pandemonium2Rules.PawnSpecs,
+      { threeSquares: true }
+    );
+  }
+
+  static get size() {
+    return { x: 10, y: 10};
+  }
+
+  static IsGoodEnpassant(enpassant) {
+    if (enpassant != "-") {
+      const squares = enpassant.split(",");
+      if (squares.length > 2) return false;
+      for (let sq of squares) {
+        if (!sq.match(/[a-j0-9]/)) return false;
+      }
+    }
+    return true;
+  }
+
+  static GenRandInitFen(randomness) {
+    const baseFen = Pandemonium2Rules.GenRandInitFen(randomness)
+    return baseFen.substr(0, 22) + "91/91/" + baseFen.substr(22);
+  }
+
+  getEnpassantFen() {
+    const L = this.epSquares.length;
+    if (!this.epSquares[L - 1]) return "-"; //no en-passant
+    let res = "";
+    this.epSquares[L - 1].forEach(sq => {
+      res += V.CoordsToSquare(sq) + ",";
+    });
+    return res.slice(0, -1); //remove last comma
+  }
+
+  getEpSquare(moveOrSquare) {
+    if (!moveOrSquare) return undefined;
+    if (typeof moveOrSquare === "string") {
+      const square = moveOrSquare;
+      if (square == "-") return undefined;
+      let res = [];
+      square.split(",").forEach(sq => {
+        res.push(V.SquareToCoords(sq));
+      });
+      return res;
+    }
+    // Argument is a move:
+    const move = moveOrSquare;
+    const [sx, sy, ex] = [move.start.x, move.start.y, move.end.x];
+    if (this.getPiece(sx, sy) == V.PAWN && Math.abs(sx - ex) >= 2) {
+      const step = (ex - sx) / Math.abs(ex - sx);
+      let res = [{
+        x: sx + step,
+        y: sy
+      }];
+      if (sx + 2 * step != ex) {
+        // 3-squares jump
+        res.push({
+          x: sx + 2 * step,
+          y: sy
+        });
+      }
+      return res;
+    }
+    return undefined; //default
+  }
+
+  applyPromotions(moves, promoted) {
+    const lastRanks = (this.turn == 'w' ? [0, 1] : [V.size.x - 1, V.size.x]);
+    let promotions = [];
+    moves.forEach(m => {
+      if (lastRanks.includes(m.start.x) || lastRanks.includes(m.end.x)) {
+        let pMove = JSON.parse(JSON.stringify(m));
+        pMove.appear[0].p = promoted;
+        promotions.push(pMove);
+      }
+    });
+    Array.prototype.push.apply(moves, promotions);
+  }
+
+  addPawnMoves([x1, y1], [x2, y2], moves) {
+    const color = this.turn;
+    const lastRanks = (color == "w" ? [0, 1] : [V.size.x - 1, V.size.x - 2]);
+    if (!lastRanks.includes(x2)) {
+      moves.push(this.getBasicMove([x1, y1], [x2, y2]));
+      return;
+    }
+    let finalPieces = [V.GILDING];
+    if (x2 == lastRanks[1]) finalPieces.push(V.PAWN);
+    for (let piece of finalPieces) {
+      const tr = (piece != V.PAWN ? { c: color, p: piece } : null);
+      moves.push(this.getBasicMove([x1, y1], [x2, y2], tr));
+    }
+  }
+
+  getEnpassantCaptures([x, y], shiftX) {
+    const Lep = this.epSquares.length;
+    const epSquare = this.epSquares[Lep - 1];
+    let moves = [];
+    if (!!epSquare) {
+      for (let epsq of epSquare) {
+        // TODO: some redundant checks
+        if (epsq.x == x + shiftX && Math.abs(epsq.y - y) == 1) {
+          let enpassantMove = this.getBasicMove([x, y], [epsq.x, epsq.y]);
+          // WARNING: the captured pawn may be diagonally behind us,
+          // if it's a 3-squares jump and we take on 1st passing square
+          const px = this.board[x][epsq.y] != V.EMPTY ? x : x - shiftX;
+          enpassantMove.vanish.push({
+            x: px,
+            y: epsq.y,
+            p: "p",
+            c: this.getColor(px, epsq.y)
+          });
+          moves.push(enpassantMove);
+        }
+      }
+    }
+    return moves;
+  }
+
+};
similarity index 78%
rename from client/src/variants/Pandemonium.js
rename to client/src/variants/Pandemonium2.js
index 4894ec1..7951608 100644 (file)
@@ -2,7 +2,15 @@ import { ChessRules, Move, PiPo } from "@/base_rules";
 import { randInt } from "@/utils/alea";
 import { ArrayFun } from "@/utils/array";
 
 import { randInt } from "@/utils/alea";
 import { ArrayFun } from "@/utils/array";
 
-export class PandemoniumRules extends ChessRules {
+export class Pandemonium2Rules extends ChessRules {
+
+  static get PawnSpecs() {
+    return Object.assign(
+      { },
+      ChessRules.PawnSpecs,
+      { promotions: [V.GILDING] }
+    );
+  }
 
   loseOnRepetition() {
     // If current side is under check: lost
 
   loseOnRepetition() {
     // If current side is under check: lost
@@ -55,7 +63,7 @@ export class PandemoniumRules extends ChessRules {
   }
 
   static get size() {
   }
 
   static get size() {
-    return { x: 10, y: 10};
+    return { x: 8, y: 10};
   }
 
   getColor(i, j) {
   }
 
   getColor(i, j) {
@@ -97,17 +105,6 @@ export class PandemoniumRules extends ChessRules {
     };
   }
 
     };
   }
 
-  static IsGoodEnpassant(enpassant) {
-    if (enpassant != "-") {
-      const squares = enpassant.split(",");
-      if (squares.length > 2) return false;
-      for (let sq of squares) {
-        if (!sq.match(/[a-j0-9]/)) return false;
-      }
-    }
-    return true;
-  }
-
   static IsGoodFen(fen) {
     if (!ChessRules.IsGoodFen(fen)) return false;
     const fenParsed = V.ParseFen(fen);
   static IsGoodFen(fen) {
     if (!ChessRules.IsGoodFen(fen)) return false;
     const fenParsed = V.ParseFen(fen);
@@ -145,7 +142,7 @@ export class PandemoniumRules extends ChessRules {
   static GenRandInitFen(randomness) {
     if (randomness == 0) {
       return (
   static GenRandInitFen(randomness) {
     if (randomness == 0) {
       return (
-        "rnbqkmcbnr/pppppppppp/91/91/91/91/91/91/PPPPPPPPPP/RNBQKMCBNR " +
+        "rnbqkmcbnr/pppppppppp/91/91/91/91/PPPPPPPPPP/RNBQKMCBNR " +
         "w 0 ajaj - 00000000000000"
       );
     }
         "w 0 ajaj - 00000000000000"
       );
     }
@@ -212,48 +209,6 @@ export class PandemoniumRules extends ChessRules {
     );
   }
 
     );
   }
 
-  getEnpassantFen() {
-    const L = this.epSquares.length;
-    if (!this.epSquares[L - 1]) return "-"; //no en-passant
-    let res = "";
-    this.epSquares[L - 1].forEach(sq => {
-      res += V.CoordsToSquare(sq) + ",";
-    });
-    return res.slice(0, -1); //remove last comma
-  }
-
-  getEpSquare(moveOrSquare) {
-    if (!moveOrSquare) return undefined;
-    if (typeof moveOrSquare === "string") {
-      const square = moveOrSquare;
-      if (square == "-") return undefined;
-      let res = [];
-      square.split(",").forEach(sq => {
-        res.push(V.SquareToCoords(sq));
-      });
-      return res;
-    }
-    // Argument is a move:
-    const move = moveOrSquare;
-    const [sx, sy, ex] = [move.start.x, move.start.y, move.end.x];
-    if (this.getPiece(sx, sy) == V.PAWN && Math.abs(sx - ex) >= 2) {
-      const step = (ex - sx) / Math.abs(ex - sx);
-      let res = [{
-        x: sx + step,
-        y: sy
-      }];
-      if (sx + 2 * step != ex) {
-        // 3-squares jump
-        res.push({
-          x: sx + 2 * step,
-          y: sy
-        });
-      }
-      return res;
-    }
-    return undefined; //default
-  }
-
   getReservePpath(index, color) {
     const p = V.RESERVE_PIECES[index];
     const prefix = (ChessRules.PIECES.includes(p) ? "" : "Pandemonium/");
   getReservePpath(index, color) {
     const p = V.RESERVE_PIECES[index];
     const prefix = (ChessRules.PIECES.includes(p) ? "" : "Pandemonium/");
@@ -316,6 +271,19 @@ export class PandemoniumRules extends ChessRules {
     };
   }
 
     };
   }
 
+  applyPromotions(moves, promoted) {
+    const lastRank = (this.turn == 'w' ? 0 : V.size.x - 1);
+    let promotions = [];
+    moves.forEach(m => {
+      if ([m.start.x, m.end.x].includes(lastRank)) {
+        let pMove = JSON.parse(JSON.stringify(m));
+        pMove.appear[0].p = promoted;
+        promotions.push(pMove);
+      }
+    });
+    Array.prototype.push.apply(moves, promotions);
+  }
+
   getPotentialMovesFrom([x, y]) {
     const c = this.getColor(x, y);
     const oppCol = V.GetOppCol(c);
   getPotentialMovesFrom([x, y]) {
     const c = this.getColor(x, y);
     const oppCol = V.GetOppCol(c);
@@ -331,12 +299,12 @@ export class PandemoniumRules extends ChessRules {
           })
         ];
       }
           })
         ];
       }
-      const firstRank = (this.movesCount == 0 ? 9 : 0);
+      const firstRank = (this.movesCount == 0 ? V.size.x - 1 : 0);
       if (x != firstRank || this.getPiece(x, y) != V.KNIGHT) return [];
       // Swap with who? search for matching bishop:
       let knights = [],
           bishops = [];
       if (x != firstRank || this.getPiece(x, y) != V.KNIGHT) return [];
       // Swap with who? search for matching bishop:
       let knights = [],
           bishops = [];
-      for (let i = 0; i < 10; i++) {
+      for (let i = 0; i < V.size.y; i++) {
         const elt = this.board[x][i][1];
         if (elt == 'n') knights.push(i);
         else if (elt == 'b') bishops.push(i);
         const elt = this.board[x][i][1];
         if (elt == 'n') knights.push(i);
         else if (elt == 'b') bishops.push(i);
@@ -404,73 +372,8 @@ export class PandemoniumRules extends ChessRules {
         break;
     }
     // Maybe apply promotions:
         break;
     }
     // Maybe apply promotions:
-    if (Object.keys(V.PromoteMap).includes(p)) {
-      const promoted = V.PromoteMap[p];
-      const lastRanks = (c == 'w' ? [0, 1] : [9, 8]);
-      let promotions = [];
-      moves.forEach(m => {
-        if (lastRanks.includes(m.start.x) || lastRanks.includes(m.end.x)) {
-          let pMove = JSON.parse(JSON.stringify(m));
-          pMove.appear[0].p = promoted;
-          promotions.push(pMove);
-        }
-      });
-      Array.prototype.push.apply(moves, promotions);
-    }
-    return moves;
-  }
-
-  addPawnMoves([x1, y1], [x2, y2], moves) {
-    const color = this.turn;
-    const lastRanks = (color == "w" ? [0, 1] : [9, 8]);
-    if (!lastRanks.includes(x2)) {
-      moves.push(this.getBasicMove([x1, y1], [x2, y2]));
-      return;
-    }
-    let finalPieces = [V.GILDING];
-    if (x2 == lastRanks[1]) finalPieces.push(V.PAWN);
-    for (let piece of finalPieces) {
-      const tr = (piece != V.PAWN ? { c: color, p: piece } : null);
-      moves.push(this.getBasicMove([x1, y1], [x2, y2], tr));
-    }
-  }
-
-  getPotentialPawnMoves([x, y]) {
-    const color = this.turn;
-    const shiftX = (color == 'w' ? -1 : 1);
-    let moves = [];
-    if (this.board[x + shiftX][y] == V.EMPTY) {
-      this.addPawnMoves([x, y], [x + shiftX, y], moves);
-      if ((color == 'w' && x >= V.size.x - 3) || (color == 'b' && x <= 2)) {
-        if (this.board[x + 2 * shiftX][y] == V.EMPTY) {
-          moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
-          if (
-            (
-              (color == 'w' && x == V.size.x - 2) ||
-              (color == 'b' && x == 1)
-            )
-            &&
-            this.board[x + 3 * shiftX][y] == V.EMPTY
-          ) {
-            moves.push(this.getBasicMove([x, y], [x + 3 * shiftX, y]));
-          }
-        }
-      }
-    }
-    for (let shiftY of [-1, 1]) {
-      if (y + shiftY >= 0 && y + shiftY < V.size.y) {
-        if (
-          this.board[x + shiftX][y + shiftY] != V.EMPTY &&
-          this.canTake([x, y], [x + shiftX, y + shiftY])
-        ) {
-          this.addPawnMoves([x, y], [x + shiftX, y + shiftY], moves);
-        }
-      }
-    }
-    Array.prototype.push.apply(
-      moves,
-      this.getEnpassantCaptures([x, y], shiftX)
-    );
+    if (Object.keys(V.PromoteMap).includes(p))
+      this.applyPromotions(moves, V.PromoteMap[p]);
     return moves;
   }
 
     return moves;
   }
 
@@ -502,31 +405,6 @@ export class PandemoniumRules extends ChessRules {
       this.getSlideNJumpMoves(sq, V.steps[V.BISHOP], "oneStep"));
   }
 
       this.getSlideNJumpMoves(sq, V.steps[V.BISHOP], "oneStep"));
   }
 
-  getEnpassantCaptures([x, y], shiftX) {
-    const Lep = this.epSquares.length;
-    const epSquare = this.epSquares[Lep - 1];
-    let moves = [];
-    if (!!epSquare) {
-      for (let epsq of epSquare) {
-        // TODO: some redundant checks
-        if (epsq.x == x + shiftX && Math.abs(epsq.y - y) == 1) {
-          let enpassantMove = this.getBasicMove([x, y], [epsq.x, epsq.y]);
-          // WARNING: the captured pawn may be diagonally behind us,
-          // if it's a 3-squares jump and we take on 1st passing square
-          const px = this.board[x][epsq.y] != V.EMPTY ? x : x - shiftX;
-          enpassantMove.vanish.push({
-            x: px,
-            y: epsq.y,
-            p: "p",
-            c: this.getColor(px, epsq.y)
-          });
-          moves.push(enpassantMove);
-        }
-      }
-    }
-    return moves;
-  }
-
   getPotentialKingMoves(sq) {
     // Initialize with normal moves
     let moves = this.getSlideNJumpMoves(
   getPotentialKingMoves(sq) {
     // Initialize with normal moves
     let moves = this.getSlideNJumpMoves(
similarity index 97%
rename from client/src/variants/Stealthbomb.js
rename to client/src/variants/Stealthbomb1.js
index ee73ef5..dce7f5a 100644 (file)
@@ -1,6 +1,6 @@
 import { ChessRules, Move, PiPo } from "@/base_rules";
 
 import { ChessRules, Move, PiPo } from "@/base_rules";
 
-export class StealthbombRules extends ChessRules {
+export class Stealthbomb1Rules extends ChessRules {
 
   static get CanAnalyze() {
     return false;
 
   static get CanAnalyze() {
     return false;
@@ -84,7 +84,7 @@ export class StealthbombRules extends ChessRules {
       this.movesCount >= 2 ||
       (
         (c == 'w' && square[0] < 6) ||
       this.movesCount >= 2 ||
       (
         (c == 'w' && square[0] < 6) ||
-        (c == 'b' && square[0] > 2)
+        (c == 'b' && square[0] > 1)
       )
     ) {
       return null;
       )
     ) {
       return null;
@@ -94,7 +94,8 @@ export class StealthbombRules extends ChessRules {
     return new Move({
       appear: [ new PiPo({ x: x, y: y, c: c, p: V.BOMB_CODE[piece] }) ],
       vanish: [ new PiPo({ x: x, y: y, c: c, p: piece }) ],
     return new Move({
       appear: [ new PiPo({ x: x, y: y, c: c, p: V.BOMB_CODE[piece] }) ],
       vanish: [ new PiPo({ x: x, y: y, c: c, p: piece }) ],
-      start: { x: -1, y: -1 }
+      start: { x: -1, y: -1 },
+      end: { x: x, y: y, noHighlight: true }
     });
   }
 
     });
   }
 
diff --git a/client/src/variants/Stealthbomb2.js b/client/src/variants/Stealthbomb2.js
new file mode 100644 (file)
index 0000000..613a5c2
--- /dev/null
@@ -0,0 +1,27 @@
+import { Move, PiPo } from "@/base_rules";
+import { Stealthbomb1Rules } from "@/variants/Stealthbomb1";
+
+export class Stealthbomb2Rules extends Stealthbomb1Rules {
+
+  // Initiate the game by choosing a square for the bomb:
+  doClick(square) {
+    const c = this.turn;
+    if (
+      this.movesCount >= 2 ||
+      (
+        (c == 'w' && square[0] != 6) ||
+        (c == 'b' && square[0] != 1)
+      )
+    ) {
+      return null;
+    }
+    const [x, y] = square;
+    return new Move({
+      appear: [ new PiPo({ x: x, y: y, c: c, p: 's' }) ],
+      vanish: [ new PiPo({ x: x, y: y, c: c, p: 'p' }) ],
+      start: { x: -1, y: -1 },
+      end: { x: x, y: y, noHighlight: true }
+    });
+  }
+
+};
index a49da9b..93353f9 100644 (file)
@@ -112,10 +112,12 @@ export class WildebeestRules extends ChessRules {
     const [sizeX, sizeY] = [V.size.x, V.size.y];
     const shiftX = color == "w" ? -1 : 1;
     const startRanks = color == "w" ? [sizeX - 2, sizeX - 3] : [1, 2];
     const [sizeX, sizeY] = [V.size.x, V.size.y];
     const shiftX = color == "w" ? -1 : 1;
     const startRanks = color == "w" ? [sizeX - 2, sizeX - 3] : [1, 2];
-    const lastRank = color == "w" ? 0 : sizeX - 1;
-    const finalPieces = x + shiftX == lastRank
-      ? [V.WILDEBEEST, V.QUEEN]
-      : [V.PAWN];
+    const lastRanks = color == "w" ? [0, 1] : [sizeX - 1, sizeX  -2];
+    let finalPieces = [V.PAWN];
+    if (x + shiftX == lastRanks[1])
+      Array.prototype.push.apply(finalPieces, [V.WILDEBEEST, V.QUEEN]);
+    else if (x + shiftX == lastRanks[0])
+      finalPieces = [V.WILDEBEEST, V.QUEEN];
 
     if (this.board[x + shiftX][y] == V.EMPTY) {
       // One square forward
 
     if (this.board[x + shiftX][y] == V.EMPTY) {
       // One square forward
index 13a4fb8..e7e7b70 100644 (file)
@@ -122,7 +122,8 @@ insert or ignore into Variants (name, description) values
   ('Pacifist1', 'Convert & support (v1)'),
   ('Pacifist2', 'Convert & support (v2)'),
   ('Pacosako', 'Dance with the King'),
   ('Pacifist1', 'Convert & support (v1)'),
   ('Pacifist2', 'Convert & support (v2)'),
   ('Pacosako', 'Dance with the King'),
-  ('Pandemonium', 'Noise and confusion'),
+  ('Pandemonium1', 'Noise and confusion (v1)'),
+  ('Pandemonium2', 'Noise and confusion (v2)'),
   ('Parachute', 'Landing on the board'),
   ('Pawnmassacre', 'Pieces upside down'),
   ('Pawns', 'Reach the last rank (v1)'),
   ('Parachute', 'Landing on the board'),
   ('Pawnmassacre', 'Pieces upside down'),
   ('Pawns', 'Reach the last rank (v1)'),
@@ -156,7 +157,8 @@ insert or ignore into Variants (name, description) values
   ('Spartan', 'Spartan versus Persians'),
   ('Squatter1', 'Squat last rank (v1)'),
   ('Squatter2', 'Squat last rank (v2)'),
   ('Spartan', 'Spartan versus Persians'),
   ('Squatter1', 'Squat last rank (v1)'),
   ('Squatter2', 'Squat last rank (v2)'),
-  ('Stealthbomb', 'Beware the bomb'),
+  ('Stealthbomb1', 'Beware the bomb (v1)'),
+  ('Stealthbomb2', 'Beware the bomb (v2)'),
   ('Suicide', 'Lose all pieces'),
   ('Suction', 'Attract opposite king'),
   ('Swap', 'Dangerous captures'),
   ('Suicide', 'Lose all pieces'),
   ('Suction', 'Attract opposite king'),
   ('Swap', 'Dangerous captures'),