Implement Wildebeest castling rule (well... almost correct)
authorBenjamin Auder <benjamin.auder@somewhere>
Mon, 28 Dec 2020 19:57:08 +0000 (20:57 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Mon, 28 Dec 2020 19:57:08 +0000 (20:57 +0100)
TODO
client/public/images/pieces/Wildebeest/castle.svg [new symlink]
client/src/components/Board.vue
client/src/translations/rules/Wildebeest/en.pug
client/src/translations/rules/Wildebeest/es.pug
client/src/translations/rules/Wildebeest/fr.pug
client/src/variants/Wildebeest.js

diff --git a/TODO b/TODO
index bb5989e..227683d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,3 @@
-Implement Wildebeest castle rules
-=> (1, 2, 3 or 4 squares slide; randomized: may be impossible >1, but possible >4...)
-
 Embedded rules language not updated when language is set (in Analyse, Game and Problems)
 If new live game starts in background, "new game" notify OK but not first move (not too serious however)
 On smartphone for Teleport, Chakart, Weiqi and some others: option "confirm moves on touch screen"
diff --git a/client/public/images/pieces/Wildebeest/castle.svg b/client/public/images/pieces/Wildebeest/castle.svg
new file mode 120000 (symlink)
index 0000000..97a07ec
--- /dev/null
@@ -0,0 +1 @@
+../Coregal/castle.svg
\ No newline at end of file
index 1d650ac..d45f33b 100644 (file)
@@ -402,10 +402,12 @@ export default {
               this.choices = [];
               this.play(m);
             };
+            const stopPropagation = (e) => { e.stopPropagation(); }
             const onClick =
               this.mobileBrowser
-                ? { touchend: applyMove }
-                : { mouseup: applyMove };
+                // Must cancel mousedown logic:
+                ? { touchstart: stopPropagation, touchend: applyMove }
+                : { mousedown: stopPropagation, mouseup: applyMove };
             return h(
               "div",
               {
index 7d9dd39..aee7cbf 100644 (file)
@@ -19,17 +19,13 @@ figure.diagram-container
 h3 Special moves
 
 p.
-  Castling is possible as in orthodox 8x8 game. The white king move to c1 or j1
-  (one square to the left of bottom-right corner) for large (resp. small)
-  castle. Same for black on the other side.
+  Castling is possible, and more flexible than in orthodox game:
+  the king can slide any number of (free) squares toward the rook,
+  which will end next to him on the other side.
 
 p.
-  Promotion occurs when pawns reach last rank.
-  They can only transform into a queen or a wildebeest.
-
-p.
-  Note: the castling rule is more restrictive than described in the original
-  rules. The game seems OK like that, but this may change in the future.
+  When a pawn reaches last rank, it can promote
+  into a queen or a wildebeest (only).
 
 h3 Source
 
index 76af898..9b4580d 100644 (file)
@@ -20,17 +20,12 @@ figure.diagram-container
 h3 Movimientos especiales
 
 p.
-  El enroque es posible como en un juego de ajedrez ortodoxo 8x8.
-  El rey blanco va a c1 o j1 (un cuadro a la izquierda de la esquina inferior
-  derecha) para un enroque grande (resp. pequeño). Lo mismo para las negras
-  del otro lado.
+  El enroque es posible y más flexible que en el juego ortodoxo:
+  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.
-  Nota: la regla de enroque es más restrictiva que la descrita por las reglas
-  originales. El juego se ve bien así, pero puede cambiar algún día.
-
 h3 Fuente
 
 p
index 3736086..63ccdab 100644 (file)
@@ -20,19 +20,14 @@ figure.diagram-container
 h3 Coups spéciaux
 
 p.
-  Le roque est possible comme dans une partie d'échecs orthodoxe 8x8.
-  Le roi blanc va en c1 ou j1 (une case à gauche du coin inférieur droit).
-  pour un grand (resp. petit) roque. Pareil pour les noirs de l'autre côté.
+  Le roque est possible, et plus souple que dans le jeu orthodoxe :
+  le roi peut sauter d'un nombre quelconque de cases (libres) vers la tour,
+  qui se retrouvera à côté de lui de l'autre côté.
 
 p.
   Un pion arrivé sur la dernière rangée se promeut en une dame ou un gnou
   seulement.
 
-p.
-  Note : la règle du roque est plus restrictive que celle décrite par les
-  règles originelles. Le jeu semble OK comme ça, mais cela pourrait changer un
-  jour.
-
 h3 Source
 
 p
index 7a9e35c..a2fc614 100644 (file)
@@ -1,4 +1,4 @@
-import { ChessRules } from "@/base_rules";
+import { ChessRules, Move, PiPo } from "@/base_rules";
 import { ArrayFun } from "@/utils/array";
 import { sample, randInt } from "@/utils/alea";
 
@@ -190,6 +190,75 @@ export class WildebeestRules extends ChessRules {
     );
   }
 
+  getPPpath(m) {
+    if (
+      m.appear.length == 2 && m.vanish.length == 2 &&
+      Math.abs(m.end.y - m.start.y) == 1 &&
+      this.board[m.end.x][m.end.y] == V.EMPTY
+    ) {
+      // Castle, king moved by one square only, not directly onto rook
+      return "Wildebeest/castle";
+    }
+    return super.getPPpath(m);
+  }
+
+  // Special Wildebeest castling rules:
+  getCastleMoves([x, y]) {
+    const c = this.getColor(x, y);
+    const oppCol = V.GetOppCol(c);
+    let moves = [];
+    let i = 0;
+    const castlingKing = this.board[x][y].charAt(1);
+    castlingCheck: for (
+      let castleSide = 0;
+      castleSide < 2;
+      castleSide++ //"large", then "small"
+    ) {
+      if (this.castleFlags[c][castleSide] >= V.size.y) continue;
+      // Rook and king are on initial position
+      const rookPos = this.castleFlags[c][castleSide];
+      const range = (castleSide == 0 ? [rookPos, y] : [y, rookPos]);
+
+      // King and rook must be connected:
+      for (let i = range[0] + 1; i <= range[1] - 1; i++) {
+        if (this.board[x][i] != V.EMPTY) continue castlingCheck;
+      }
+      const step = 2 * castleSide - 1;
+      // No attacks on the path of the king ?
+      for (let i = range[0]; i <= range[1]; i++) {
+        if (i != rookPos && this.isAttacked([x, i], oppCol))
+          continue castlingCheck;
+        if (i != y) {
+          // Found a possible castle move:
+          moves.push(
+            new Move({
+              appear: [
+                new PiPo({
+                  x: x,
+                  y: i,
+                  p: V.KING,
+                  c: c
+                }),
+                new PiPo({
+                  x: x,
+                  y: i - step,
+                  p: V.ROOK,
+                  c: c
+                })
+              ],
+              vanish: [
+                new PiPo({ x: x, y: y, p: V.KING, c: c }),
+                new PiPo({ x: x, y: rookPos, p: V.ROOK, c: c })
+              ]
+            })
+          );
+        }
+      }
+    }
+
+    return moves;
+  }
+
   isAttacked(sq, color) {
     return (
       super.isAttacked(sq, color) ||