Fix rules implementation and translations for Allmate1
authorBenjamin Auder <benjamin.auder@somewhere>
Sat, 11 Apr 2020 21:11:01 +0000 (23:11 +0200)
committerBenjamin Auder <benjamin.auder@somewhere>
Sat, 11 Apr 2020 21:11:01 +0000 (23:11 +0200)
client/src/translations/rules/Allmate1/en.pug
client/src/translations/rules/Allmate1/es.pug
client/src/translations/rules/Allmate1/fr.pug
client/src/translations/rules/Allmate2/en.pug
client/src/translations/rules/Allmate2/es.pug
client/src/translations/rules/Allmate2/fr.pug
client/src/variants/Allmate1.js
client/src/variants/Allmate2.js

index ab60488..fabc8af 100644 (file)
@@ -9,6 +9,19 @@ p.
   the piece is not captured.
   Thus, kings and other pieces may remain under check.
 
+p.
+  If after a mate-capture another is made possible thanks to some pieces
+  removal, then the new mate-capture is applied and the process goes on.
+
+figure.diagram-container
+  .diagram.diag12
+    | fen:1rb1n1r1/1ppp1pkp/pn4p1/4p3/3qN2Q/4bP2/PPP1P1PP/R2BKR1N:
+  .diagram.diag22
+    | fen:1rb1n1r1/1ppp1pkp/pn6/4p1Q1/3qN3/5P2/PPP1P1PP/R2BKR1N:
+  figcaption.
+    Before and after 1.Qg5X, which takes first the bishop on e3,
+    and then the pawn on g6.
+
 p.
   Pieces cannot be taken in the normal way, only by the "mate-capture"
   described above.
index 73c7baf..d6ba11b 100644 (file)
@@ -9,6 +9,20 @@ p.
   la pieza no se captura.
   Por lo tanto, los reyes y otras piezas pueden permanecer en jaque.
 
+p.
+  Si después de una mate-captura se hace posible otra gracias a la desaparición
+  de ciertas piezas, entonces esta nueva captura de estera se ejecuta y
+  seguimos buscando capturas.
+
+figure.diagram-container
+  .diagram.diag12
+    | fen:1rb1n1r1/1ppp1pkp/pn4p1/4p3/3qN2Q/4bP2/PPP1P1PP/R2BKR1N:
+  .diagram.diag22
+    | fen:1rb1n1r1/1ppp1pkp/pn6/4p1Q1/3qN3/5P2/PPP1P1PP/R2BKR1N:
+  figcaption.
+    Antes y después de 1.Qg5X, que primero toma el alfil en e3,
+    y luego el peón en g6.
+
 p.
   Las piezas no pueden capturar en el sentido habitual, solo a través de
   "mate-captura" descrito anteriormente.
index bfed36e..d396233 100644 (file)
@@ -10,6 +10,20 @@ p.
   la pièce n'est pas capturée.
   Ainsi, les rois et autres pièces peuvent rester en échec.
 
+p.
+  Si après une mat-capture une autre est rendue possible grâce à la disparition
+  de certaines pièces, alors cette nouvelle mat-capture est exécutée et le
+  on continue de chercher des captures.
+
+figure.diagram-container
+  .diagram.diag12
+    | fen:1rb1n1r1/1ppp1pkp/pn4p1/4p3/3qN2Q/4bP2/PPP1P1PP/R2BKR1N:
+  .diagram.diag22
+    | fen:1rb1n1r1/1ppp1pkp/pn6/4p1Q1/3qN3/5P2/PPP1P1PP/R2BKR1N:
+  figcaption.
+    Avant et après 1.Qg5X, qui prend d'abord le fou en e3,
+    et ensuite le pion en g6.
+
 p.
   Les pièces ne peuvent capturer au sens habituel, seulement via la
   "mat-capture" décrite ci-dessus.
index b606991..70fdafe 100644 (file)
@@ -3,7 +3,7 @@ p.boxed
   | be prevented with non-capturing moves.
 
 p.
-  This is exactly the Allmate1 variant, with a weaker mating condition:
+  This is the Allmate1 variant, with a weaker mating condition:
   capturing moves to escape from checkmate are not considered.
   (Mate-)Capturing is thus easier: on the next diagram, 1.Qe6 captures
   the d7, e7 and f7 pawns.
@@ -15,6 +15,8 @@ figure.diagram-container
     | fen:4k3/ppp3pp/4Q3/8/8/8/PPP2PPP/4K3:
   figcaption Before and after 1.Qe6X
 
+p Since captures are much easier, they don't cascade as in Allmate1.
+
 h3 Source
 
 p See Allmate1 variant.
index f3b5974..df2defd 100644 (file)
@@ -3,7 +3,7 @@ p.boxed
   | la toma por movimientos sin captura.
 
 p.
-  Esta es exactamente la variante Allmate1, con una condición de mate más
+  Esta es la variante Allmate1, con una condición de mate más
   débil: no se consideran las capturas para escapar de un jaque mate.
   Por lo tanto, las (mate-)capturas son más fáciles: en el siguiente diagrama,
   1.Qe6 toma los peones d7, e7 y f7.
@@ -15,6 +15,10 @@ figure.diagram-container
     | fen:4K3/ppp3pp/4Q3/8/8/8/PPP2PPP/4K3:
   figcaption Antes y después 1.Qe6X
 
+p.
+  Como las capturas son mucho más fáciles, no tienen lugar
+  en cascada como en Allmate1.
+
 h3 Fuente
 
 p Ver la variante Allmate1.
index b8d959f..1ea1a05 100644 (file)
@@ -3,7 +3,7 @@ p.boxed
   | empêchée par des coups non capturants.
 
 p.
-  C'est exactement la variante Allmate1, avec une condition de mat plus
+  C'est la variante Allmate1, avec une condition de mat plus
   faible : les coups capturants pour échapper à un mat ne sont pas considérés.
   Les (mat-)captures sont donc plus faciles : sur le diagramme suivant,
   1.Qe6 prend les pions d7, e7 et f7.
@@ -15,6 +15,10 @@ figure.diagram-container
     | fen:4k3/ppp3pp/4Q3/8/8/8/PPP2PPP/4K3:
   figcaption Avant et après 1.Qe6X
 
+p.
+  Puisque les captures sont beaucoup plus faciles, elles ne s'effectuent pas
+  en cascade comme dans Allmate1.
+
 h3 Source
 
 p Voir la variante Allmate1.
index f3c0b2e..0e7e8ed 100644 (file)
@@ -27,77 +27,97 @@ export class Allmate1Rules extends ChessRules {
     const oppCol = V.GetOppCol(this.turn);
     moves.forEach(m => {
       this.play(m);
+      let allAttacks = [];
 
-      // 1) What is attacked?
-      let attacked = {};
-      for (let i=0; i<V.size.x; i++) {
-        for (let j=0; j<V.size.y; j++) {
-          if (this.getColor(i,j) == oppCol && this.isAttacked([i,j], color))
-            attacked[i+"_"+j] = [i,j];
+      // While something has been captured:
+      // remove it, and keep looking for captures
+      outerLoop: while (true) {
+
+        // 1) What is attacked?
+        let attacked = {};
+        for (let i=0; i<V.size.x; i++) {
+          for (let j=0; j<V.size.y; j++) {
+            if (this.getColor(i,j) == oppCol && this.isAttacked([i,j], color))
+              attacked[i+"_"+j] = [i,j];
+          }
         }
-      }
+        if (Object.keys(attacked).length == 0) break outerLoop;
 
-      // 2) Among attacked pieces, which cannot escape capture?
-      // Avoid "oppMoves = this.getAllValidMoves();" => infinite recursion
-      outerLoop: for (let i=0; i<V.size.x; i++) {
-        for (let j=0; j<V.size.y; j++) {
-          if (this.getColor(i,j) == oppCol) {
-            let oppMoves = [];
-            switch (this.getPiece(i, j)) {
-              case V.PAWN:
-                oppMoves = this.getPotentialPawnMoves([i, j]);
-                break;
-              case V.ROOK:
-                oppMoves = this.getPotentialRookMoves([i, j]);
-                break;
-              case V.KNIGHT:
-                oppMoves = this.getPotentialKnightMoves([i, j]);
-                break;
-              case V.BISHOP:
-                oppMoves = this.getPotentialBishopMoves([i, j]);
-                break;
-              case V.QUEEN:
-                oppMoves = this.getPotentialQueenMoves([i, j]);
-                break;
-              case V.KING:
-                // Do not allow castling to escape from check
-                oppMoves = super.getSlideNJumpMoves(
-                  [x, y],
-                  V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
-                  "oneStep"
-                );
-                break;
-            }
-            for (let om of oppMoves) {
-              V.PlayOnBoard(this.board, om);
-              Object.values(attacked).forEach(sq => {
-                const origSq = [sq[0], sq[1]];
-                if (om.start.x == sq[0] && om.start.y == sq[1])
-                  // Piece moved:
-                  sq = [om.appear[0].x, om.appear[0].y];
-                if (!this.isAttacked(sq, color))
-                  delete attacked[origSq[0]+"_"+origSq[1]];
-              });
-              V.UndoOnBoard(this.board, om);
-              if (Object.keys(attacked).length == 0)
-                // No need to explore more moves
-                break outerLoop;
+        // 2) Among attacked pieces, which cannot escape capture?
+        // Avoid "oppMoves = this.getAllValidMoves();" => infinite recursion
+        for (let i=0; i<V.size.x; i++) {
+          for (let j=0; j<V.size.y; j++) {
+            if (this.getColor(i,j) == oppCol) {
+              let oppMoves = [];
+              switch (this.getPiece(i, j)) {
+                case V.PAWN:
+                  oppMoves = this.getPotentialPawnMoves([i, j]);
+                  break;
+                case V.ROOK:
+                  oppMoves = this.getPotentialRookMoves([i, j]);
+                  break;
+                case V.KNIGHT:
+                  oppMoves = this.getPotentialKnightMoves([i, j]);
+                  break;
+                case V.BISHOP:
+                  oppMoves = this.getPotentialBishopMoves([i, j]);
+                  break;
+                case V.QUEEN:
+                  oppMoves = this.getPotentialQueenMoves([i, j]);
+                  break;
+                case V.KING:
+                  // Do not allow castling to escape from check
+                  oppMoves = super.getSlideNJumpMoves(
+                    [i, j],
+                    V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
+                    "oneStep"
+                  );
+                  break;
+              }
+              for (let om of oppMoves) {
+                V.PlayOnBoard(this.board, om);
+                Object.values(attacked).forEach(sq => {
+                  const origSq = [sq[0], sq[1]];
+                  if (om.start.x == sq[0] && om.start.y == sq[1])
+                    // Piece moved:
+                    sq = [om.appear[0].x, om.appear[0].y];
+                  if (!this.isAttacked(sq, color))
+                    delete attacked[origSq[0]+"_"+origSq[1]];
+                });
+                V.UndoOnBoard(this.board, om);
+                if (Object.keys(attacked).length == 0)
+                  // No need to explore more moves
+                  break outerLoop;
+              }
             }
           }
         }
+
+        // 3) Add mate-captures and remove pieces from board:
+        Object.keys(attacked).forEach(k => {
+          allAttacks.push({
+            sq: attacked[k],
+            p: this.getPiece(attacked[k][0], attacked[k][1])
+          });
+          this.board[attacked[k][0]][attacked[k][1]] = V.EMPTY;
+        });
       }
 
-      // 3) Add mate-captures:
-      Object.values(attacked).forEach(sq => {
-        m.vanish.push(new PiPo({
-          x: sq[0],
-          y: sq[1],
-          c: oppCol,
-          p: this.getPiece(sq[0], sq[1])
-        }));
+      // Put removed pieces back on board:
+      allAttacks.forEach(v => {
+        this.board[v.sq[0]][v.sq[1]] = oppCol + v.p;
       });
-
       this.undo(m);
+      allAttacks.forEach(v => {
+        m.vanish.push(
+          new PiPo({
+            x: v.sq[0],
+            y: v.sq[1],
+            c: oppCol,
+            p: v.p
+          })
+        );
+      });
     });
 
     return moves;
index 424bb09..9b60a5f 100644 (file)
@@ -70,7 +70,7 @@ export class Allmate2Rules extends ChessRules {
                 break;
             }
             for (let om of oppMoves) {
-              if (om.vanish.length == 2 && om.appear.length == 1)
+              if (om.vanish.length == 2)
                 // Skip captures: forbidden in this mode
                 continue;
               V.PlayOnBoard(this.board, om);
@@ -90,6 +90,7 @@ export class Allmate2Rules extends ChessRules {
           }
         }
       }
+      this.undo(m);
 
       // 3) Add mate-captures:
       Object.values(attacked).forEach(sq => {
@@ -100,8 +101,6 @@ export class Allmate2Rules extends ChessRules {
           p: this.getPiece(sq[0], sq[1])
         }));
       });
-
-      this.undo(m);
     });
 
     return moves;