From: Benjamin Auder <benjamin.auder@somewhere>
Date: Fri, 19 Mar 2021 07:56:20 +0000 (+0100)
Subject: Rename Monochrome --> Monocolor , split Cannibal (forced captures or not)
X-Git-Url: https://git.auder.net/doc/html/css/scripts/current/assets/DESCRIPTION?a=commitdiff_plain;h=3955246aca52e36cd02a528c98712e473c93417c;p=vchess.git

Rename Monochrome --> Monocolor , split Cannibal (forced captures or not)
---

diff --git a/client/src/translations/en.js b/client/src/translations/en.js
index eb0c0bbd..5a5461da 100644
--- a/client/src/translations/en.js
+++ b/client/src/translations/en.js
@@ -195,7 +195,8 @@ export const translations = {
   "Capture both colors": "Capture both colors",
   "Capture en passant": "Capture en passant",
   "Capture on the edge": "Capture on the edge",
-  "Capture powers": "Capture powers",
+  "Capture powers (v1)": "Capture powers (v1)",
+  "Capture powers (v2)": "Capture powers (v2)",
   "Capture the princess": "Capture the princess",
   "Captures reborn": "Captures reborn",
   "Change colors": "Change colors",
diff --git a/client/src/translations/es.js b/client/src/translations/es.js
index 051978c6..f868d266 100644
--- a/client/src/translations/es.js
+++ b/client/src/translations/es.js
@@ -195,7 +195,8 @@ export const translations = {
   "Capture both colors": "Captura ambos colores",
   "Capture en passant": "Capturar en passant",
   "Capture on the edge": "Capturar en el borde",
-  "Capture powers": "Capturar los poderes",
+  "Capture powers (v1)": "Capturar los poderes (v1)",
+  "Capture powers (v2)": "Capturar los poderes (v2)",
   "Capture the princess": "Capturar a la princesa",
   "Captures reborn": "Las capturas renacen",
   "Change colors": "Cambiar colores",
diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js
index 5e92206d..b0a92165 100644
--- a/client/src/translations/fr.js
+++ b/client/src/translations/fr.js
@@ -195,7 +195,8 @@ export const translations = {
   "Capture both colors": "Capturer les deux couleurs",
   "Capture en passant": "Capturer en passant",
   "Capture on the edge": "Capturer sur le bord",
-  "Capture powers": "Capturer les pouvoirs",
+  "Capture powers (v1)": "Capturer les pouvoirs (v1)",
+  "Capture powers (v2)": "Capturer les pouvoirs (v2)",
   "Capture the princess": "Capturer la princesse",
   "Captures reborn": "Les captures renaissent",
   "Change colors": "Changer les couleurs",
diff --git a/client/src/translations/rules/Cannibal/en.pug b/client/src/translations/rules/Cannibal/en.pug
deleted file mode 100644
index b12d95a5..00000000
--- a/client/src/translations/rules/Cannibal/en.pug
+++ /dev/null
@@ -1,25 +0,0 @@
-p.boxed
-  | Captures are mandatory, with transformation into the captured piece.
-
-p.
-  Everything is the same as in orthodox rules, except that when possible,
-  captures are forced.
-  The goal is still to checkmate, and stalemate is a draw.
-
-p.
-  After each capture the capturer takes the nature of the captured piece.
-  For example after 1.e4 a6 2.Bxa6 is forced and a6 is now a white pawn.
-
-figure.diagram-container
-  .diagram
-    | fen:rnbqkbnr/1ppppppp/p7/8/4P3/8/PPPP1PPP/RNBQKBNR a6:
-  figcaption After 1.e4 a6, 2.Bxa6 turns the bishop into a pawn.
-
-p If the king captures, it transforms as well but stays royal.
-
-h3 More information
-
-p
-  a(href="https://www.chessvariants.com/difftaking.dir/cannibal.html")
-    | Cannibal Chess
-  | &nbsp;on chessvariants.com. I added the forced captures for more fun.
diff --git a/client/src/translations/rules/Cannibal/es.pug b/client/src/translations/rules/Cannibal/es.pug
deleted file mode 100644
index ec046db3..00000000
--- a/client/src/translations/rules/Cannibal/es.pug
+++ /dev/null
@@ -1,27 +0,0 @@
-p.boxed
-  | Las capturas son obligatorias, con transformación en la pieza capturada.
-
-p.
-  Todo va como el ajedrez ortodoxo, pero cuando es posible
-  las capturas son forzadas.
-  El objetivo aún es de matar, y el empate es tablas.
-
-p.
-  Después de cada captura, el atacante toma la naturaleza de la pieza capturada.
-  Por ejemplo, después de 1.e4 a6 2.Bxa6 es forzado y a6 ahora es un peón blanco.
-
-figure.diagram-container
-  .diagram
-    | fen:rnbqkbnr/1ppppppp/p7/8/4P3/8/PPPP1PPP/RNBQKBNR a6:
-  figcaption Después de 1.e4 a6, 2.Bxa6 transforma el alfil en un peón.
-
-p Si el rey captura, también se transforma pero permanece real.
-
-h3 Más información
-
-p
-  | La 
-  a(href="https://www.chessvariants.com/difftaking.dir/cannibal.html")
-    | variante Cannibal
-  | &nbsp;en chessvariants.com.
-  | Esta regla me parece más divertida con las capturas obligatorias.
diff --git a/client/src/translations/rules/Cannibal/fr.pug b/client/src/translations/rules/Cannibal/fr.pug
deleted file mode 100644
index 4626ac2e..00000000
--- a/client/src/translations/rules/Cannibal/fr.pug
+++ /dev/null
@@ -1,27 +0,0 @@
-p.boxed
-  | Les captures sont obligatoires, avec transformation en la pièce capturée.
-
-p.
-  Tout se déroule comme aux échecs orthodoxes, mais quand elles sont possibles
-  les captures sont forcées.
-  L'objectif est toujours de mater, et le pat fait nulle.
-
-p.
-  Après chaque capture, l'attaquant prend la nature de la pièce capturée.
-  Par exemple après 1.e4 a6 2.Bxa6 est forcé et a6 est maintenant un pion blanc.
-
-figure.diagram-container
-  .diagram
-    | fen:rnbqkbnr/1ppppppp/p7/8/4P3/8/PPPP1PPP/RNBQKBNR a6:
-  figcaption Après 1.e4 a6, 2.Bxa6 transforme le fou en un pion.
-
-p Si le roi capture, il se transforme aussi mais reste royal.
-
-h3 Plus d'information
-
-p
-  | La 
-  a(href="https://www.chessvariants.com/difftaking.dir/cannibal.html")
-    | variante Cannibal
-  | &nbsp;sur chessvariants.com.
-  | Cett règle me paraît plus amusante avec des captures obligatoires.
diff --git a/client/src/translations/rules/Cannibal1/en.pug b/client/src/translations/rules/Cannibal1/en.pug
new file mode 100644
index 00000000..92da2c34
--- /dev/null
+++ b/client/src/translations/rules/Cannibal1/en.pug
@@ -0,0 +1,28 @@
+p.boxed
+  | Captures turn the capturer into the captured piece.
+
+p.
+  Everything is the same as in orthodox rules, with one exception:
+  after each capture, the capturer takes the nature of the captured piece.
+  The goal is still to checkmate, and stalemate is a draw.
+
+p.
+  For example after 1.e4 e5 2.Nf3 b6 3.Nxe5, e5 is now a white pawn.
+  This capture seems bad, but anything which capture e5 later
+  will turn into a pawn...
+
+figure.diagram-container
+  .diagram.diag12
+    | fen:rnbqkbnr/p1pp1ppp/1p6/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R:
+  .diagram.diag22
+    | fen:rnbqkbnr/p1pp1ppp/1p6/4P3/4P3/8/PPPP1PPP/RNBQKB1R:
+  figcaption After 1.e4 e5 2.Nf3 b6 (left) with 3.Nxe5 (right)
+
+p If the king captures, it transforms as well but stays royal.
+
+h3 More information
+
+p
+  a(href="https://www.chessvariants.com/difftaking.dir/cannibal.html")
+    | Cannibal Chess
+  | &nbsp;on chessvariants.com.
diff --git a/client/src/translations/rules/Cannibal1/es.pug b/client/src/translations/rules/Cannibal1/es.pug
new file mode 100644
index 00000000..381c3cef
--- /dev/null
+++ b/client/src/translations/rules/Cannibal1/es.pug
@@ -0,0 +1,29 @@
+p.boxed
+  | Las caturas transforman la pieza que captura en la pieza capturada.
+
+p.
+  Todo va como el ajedrez ortodoxo, con una excepcion: después de
+  cada captura, el atacante toma la naturaleza de la pieza capturada.
+  El objetivo aún es de matar, y el empate es tablas.
+
+p.
+  Por ejemplo, después de 1.e4 e5 2.Nf3 b6 3.Nxe5, e5 es ahora un peón blanco.
+  Esta captura se ve mal, pero cualquier pieza que tome e5 más tarde
+  se convertirá en un peón...
+
+figure.diagram-container
+  .diagram.diag12
+    | fen:rnbqkbnr/p1pp1ppp/1p6/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R:
+  .diagram.diag22
+    | fen:rnbqkbnr/p1pp1ppp/1p6/4P3/4P3/8/PPPP1PPP/RNBQKB1R:
+  figcaption Después de 1.e4 e5 2.Nf3 b6 (izquierda) con 3.Cxe5 (derecha)
+
+p Si el rey captura, también se transforma pero permanece real.
+
+h3 Más información
+
+p
+  | La 
+  a(href="https://www.chessvariants.com/difftaking.dir/cannibal.html")
+    | variante Cannibal
+  | &nbsp;en chessvariants.com.
diff --git a/client/src/translations/rules/Cannibal1/fr.pug b/client/src/translations/rules/Cannibal1/fr.pug
new file mode 100644
index 00000000..7f2ce313
--- /dev/null
+++ b/client/src/translations/rules/Cannibal1/fr.pug
@@ -0,0 +1,29 @@
+p.boxed
+  | Les captures transforment la pièce capturante en la pièce capturée.
+
+p.
+  Tout se déroule comme aux échecs orthodoxes, à une exception près :
+  après chaque capture, l'attaquant prend la nature de la pièce capturée.
+  L'objectif est toujours de mater, et le pat fait nulle.
+
+p.
+  Par exemple après 1.e4 e5 2.Nf3 b6 3.Nxe5, e5 est à présent un pion blanc.
+  Cette capture semble mauvaise, mais toute pièce prenant en e5 plus tard
+  se transformera en pion...
+
+figure.diagram-container
+  .diagram.diag12
+    | fen:rnbqkbnr/p1pp1ppp/1p6/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R:
+  .diagram.diag22
+    | fen:rnbqkbnr/p1pp1ppp/1p6/4P3/4P3/8/PPPP1PPP/RNBQKB1R:
+  figcaption Après 1.e4 e5 2.Nf3 b6 (gauche) avec 3.Nxe5 (droite)
+
+p Si le roi capture, il se transforme aussi mais reste royal.
+
+h3 Plus d'information
+
+p
+  | La 
+  a(href="https://www.chessvariants.com/difftaking.dir/cannibal.html")
+    | variante Cannibal
+  | &nbsp;sur chessvariants.com.
diff --git a/client/src/translations/rules/Cannibal2/en.pug b/client/src/translations/rules/Cannibal2/en.pug
new file mode 100644
index 00000000..702166ba
--- /dev/null
+++ b/client/src/translations/rules/Cannibal2/en.pug
@@ -0,0 +1,14 @@
+p.boxed
+  | Captures are mandatory, with transformation into the captured piece.
+
+p
+  a(href="/#/variants/Cannibal1") Cannibal1
+  | , with forced captures.
+  | I initially believed it was better like that. Not sure anymore :-)
+
+p For example after 1.e4 a6, 2.Bxa6 is forced and a6 is now a white pawn.
+
+figure.diagram-container
+  .diagram
+    | fen:rnbqkbnr/1ppppppp/p7/8/4P3/8/PPPP1PPP/RNBQKBNR a6:
+  figcaption After 1.e4 a6, 2.Bxa6 turns the bishop into a pawn.
diff --git a/client/src/translations/rules/Cannibal2/es.pug b/client/src/translations/rules/Cannibal2/es.pug
new file mode 100644
index 00000000..be7906b5
--- /dev/null
+++ b/client/src/translations/rules/Cannibal2/es.pug
@@ -0,0 +1,16 @@
+p.boxed
+  | Las capturas son obligatorias, con transformación en la pieza capturada.
+
+p
+  a(href="/#/variants/Cannibal1") Cannibal1
+  | , con capturas obligatorias.
+  | Pensé que era mejor así, pero ya no estoy seguro :-)
+
+p.
+  Por ejemplo después de 1.e4 a6, 2.Bxa6 es forzado
+  y a6 ahora es un peón blanco.
+
+figure.diagram-container
+  .diagram
+    | fen:rnbqkbnr/1ppppppp/p7/8/4P3/8/PPPP1PPP/RNBQKBNR a6:
+  figcaption Después de 1.e4 a6, 2.Bxa6 transforma el alfil en un peón.
diff --git a/client/src/translations/rules/Cannibal2/fr.pug b/client/src/translations/rules/Cannibal2/fr.pug
new file mode 100644
index 00000000..972f24a5
--- /dev/null
+++ b/client/src/translations/rules/Cannibal2/fr.pug
@@ -0,0 +1,14 @@
+p.boxed
+  | Les captures sont obligatoires, avec transformation en la pièce capturée.
+
+p
+  a(href="/#/variants/Cannibal1") Cannibal1
+  | , avec captures obligatoires.
+  | Je pensais que c'était mieux ainsi, mais n'en suis plus très sûr :-)
+
+p Par exemple après 1.e4 a6, 2.Bxa6 est forcé et a6 est alors un pion blanc.
+
+figure.diagram-container
+  .diagram
+    | fen:rnbqkbnr/1ppppppp/p7/8/4P3/8/PPPP1PPP/RNBQKBNR a6:
+  figcaption Après 1.e4 a6, 2.Bxa6 transforme le fou en un pion.
diff --git a/client/src/translations/rules/Monochrome/en.pug b/client/src/translations/rules/Monocolor/en.pug
similarity index 100%
rename from client/src/translations/rules/Monochrome/en.pug
rename to client/src/translations/rules/Monocolor/en.pug
diff --git a/client/src/translations/rules/Monochrome/es.pug b/client/src/translations/rules/Monocolor/es.pug
similarity index 100%
rename from client/src/translations/rules/Monochrome/es.pug
rename to client/src/translations/rules/Monocolor/es.pug
diff --git a/client/src/translations/rules/Monochrome/fr.pug b/client/src/translations/rules/Monocolor/fr.pug
similarity index 100%
rename from client/src/translations/rules/Monochrome/fr.pug
rename to client/src/translations/rules/Monocolor/fr.pug
diff --git a/client/src/translations/variants/en.pug b/client/src/translations/variants/en.pug
index d6c8f5ba..e5e92f84 100644
--- a/client/src/translations/variants/en.pug
+++ b/client/src/translations/variants/en.pug
@@ -36,7 +36,7 @@ p.
     "Arena",
     "Capture",
     "Losers",
-    "Monochrome",
+    "Monocolor",
     "Suicide"
   ]
 ul
@@ -49,7 +49,8 @@ p Pieces generally transform when capturing.
 -
   var varlist = [
     "Absorption",
-    "Cannibal"
+    "Cannibal1",
+    "Cannibal2"
   ]
 ul
   for v in varlist
diff --git a/client/src/translations/variants/es.pug b/client/src/translations/variants/es.pug
index 32a83c8b..a09ce9d3 100644
--- a/client/src/translations/variants/es.pug
+++ b/client/src/translations/variants/es.pug
@@ -38,7 +38,7 @@ p.
     "Arena",
     "Capture",
     "Losers",
-    "Monochrome",
+    "Monocolor",
     "Suicide"
   ]
 ul
@@ -51,7 +51,8 @@ p En general, las piezas se transforman mediante la captura.
 -
   var varlist = [
     "Absorption",
-    "Cannibal"
+    "Cannibal1",
+    "Cannibal2"
   ]
 ul
   for v in varlist
diff --git a/client/src/translations/variants/fr.pug b/client/src/translations/variants/fr.pug
index f8fcb299..2737859f 100644
--- a/client/src/translations/variants/fr.pug
+++ b/client/src/translations/variants/fr.pug
@@ -37,7 +37,7 @@ p.
     "Arena",
     "Capture",
     "Losers",
-    "Monochrome",
+    "Monocolor",
     "Suicide"
   ]
 ul
@@ -50,7 +50,8 @@ p En général les pièces se transforment en capturant.
 -
   var varlist = [
     "Absorption",
-    "Cannibal"
+    "Cannibal1",
+    "Cannibal2"
   ]
 ul
   for v in varlist
diff --git a/client/src/variants/Cannibal.js b/client/src/variants/Cannibal1.js
similarity index 73%
rename from client/src/variants/Cannibal.js
rename to client/src/variants/Cannibal1.js
index a0da0fd6..0c327b45 100644
--- a/client/src/variants/Cannibal.js
+++ b/client/src/variants/Cannibal1.js
@@ -1,6 +1,6 @@
 import { ChessRules, Move, PiPo } from "@/base_rules";
 
-export class CannibalRules extends ChessRules {
+export class Cannibal1Rules extends ChessRules {
 
   static get KING_CODE() {
     return {
@@ -84,31 +84,6 @@ export class CannibalRules extends ChessRules {
     }
   }
 
-  // Trim all non-capturing moves
-  static KeepCaptures(moves) {
-    return moves.filter(m => m.vanish.length == 2 && m.appear.length == 1);
-  }
-
-  // Stop at the first capture found (if any)
-  atLeastOneCapture() {
-    const color = this.turn;
-    const oppCol = V.GetOppCol(color);
-    for (let i = 0; i < V.size.x; i++) {
-      for (let j = 0; j < V.size.y; j++) {
-        if (
-          this.board[i][j] != V.EMPTY &&
-          this.getColor(i, j) != oppCol &&
-          this.filterValid(this.getPotentialMovesFrom([i, j])).some(m =>
-            // Warning: discard castle moves
-            m.vanish.length == 2 && m.appear.length == 1)
-        ) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
   // Because of the disguised kings, getPiece() could be wrong:
   // use board[x][y][1] instead (always valid).
   getBasicMove([sx, sy], [ex, ey], tr) {
@@ -140,38 +115,6 @@ export class CannibalRules extends ChessRules {
     return super.getPotentialMovesFrom([x, y], piece);
   }
 
-  addPawnMoves([x1, y1], [x2, y2], moves) {
-    let finalPieces = [V.PAWN];
-    const color = this.turn;
-    const lastRank = (color == "w" ? 0 : V.size.x - 1);
-    if (x2 == lastRank) {
-      if (this.board[x2][y2] != V.EMPTY)
-        // Cannibal rules: no choice if capture
-        finalPieces = [this.getPiece(x2, y2)];
-      else finalPieces = V.PawnSpecs.promotions;
-    }
-    let tr = null;
-    for (let piece of finalPieces) {
-      tr = (piece != V.PAWN ? { c: color, p: piece } : null);
-      moves.push(this.getBasicMove([x1, y1], [x2, y2], tr));
-    }
-  }
-
-  getPossibleMovesFrom(sq) {
-    let moves = this.filterValid(this.getPotentialMovesFrom(sq));
-    const captureMoves = V.KeepCaptures(moves);
-    if (captureMoves.length > 0) return captureMoves;
-    if (this.atLeastOneCapture()) return [];
-    return moves;
-  }
-
-  getAllValidMoves() {
-    const moves = super.getAllValidMoves();
-    if (moves.some(m => m.vanish.length == 2 && m.appear.length == 1))
-      return V.KeepCaptures(moves);
-    return moves;
-  }
-
   postPlay(move) {
     const c = V.GetOppCol(this.turn);
     const piece = move.appear[0].p;
diff --git a/client/src/variants/Cannibal2.js b/client/src/variants/Cannibal2.js
new file mode 100644
index 00000000..aa4dcb84
--- /dev/null
+++ b/client/src/variants/Cannibal2.js
@@ -0,0 +1,63 @@
+import { ChessRules, Move, PiPo } from "@/base_rules";
+import { Cannibal1Rules } from "@/variants/Cannibal1";
+
+export class Cannibal2Rules extends Cannibal1Rules {
+
+  // Trim all non-capturing moves
+  static KeepCaptures(moves) {
+    return moves.filter(m => m.vanish.length == 2 && m.appear.length == 1);
+  }
+
+  // Stop at the first capture found (if any)
+  atLeastOneCapture() {
+    const color = this.turn;
+    const oppCol = V.GetOppCol(color);
+    for (let i = 0; i < V.size.x; i++) {
+      for (let j = 0; j < V.size.y; j++) {
+        if (
+          this.board[i][j] != V.EMPTY &&
+          this.getColor(i, j) != oppCol &&
+          this.filterValid(this.getPotentialMovesFrom([i, j])).some(m =>
+            // Warning: discard castle moves
+            m.vanish.length == 2 && m.appear.length == 1)
+        ) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  addPawnMoves([x1, y1], [x2, y2], moves) {
+    let finalPieces = [V.PAWN];
+    const color = this.turn;
+    const lastRank = (color == "w" ? 0 : V.size.x - 1);
+    if (x2 == lastRank) {
+      if (this.board[x2][y2] != V.EMPTY)
+        // Cannibal rules: no choice if capture
+        finalPieces = [this.getPiece(x2, y2)];
+      else finalPieces = V.PawnSpecs.promotions;
+    }
+    let tr = null;
+    for (let piece of finalPieces) {
+      tr = (piece != V.PAWN ? { c: color, p: piece } : null);
+      moves.push(this.getBasicMove([x1, y1], [x2, y2], tr));
+    }
+  }
+
+  getPossibleMovesFrom(sq) {
+    let moves = this.filterValid(this.getPotentialMovesFrom(sq));
+    const captureMoves = V.KeepCaptures(moves);
+    if (captureMoves.length > 0) return captureMoves;
+    if (this.atLeastOneCapture()) return [];
+    return moves;
+  }
+
+  getAllValidMoves() {
+    const moves = super.getAllValidMoves();
+    if (moves.some(m => m.vanish.length == 2 && m.appear.length == 1))
+      return V.KeepCaptures(moves);
+    return moves;
+  }
+
+};
diff --git a/client/src/variants/Monochrome.js b/client/src/variants/Monocolor.js
similarity index 99%
rename from client/src/variants/Monochrome.js
rename to client/src/variants/Monocolor.js
index 22242ed2..1e263699 100644
--- a/client/src/variants/Monochrome.js
+++ b/client/src/variants/Monocolor.js
@@ -1,6 +1,6 @@
 import { ChessRules } from "@/base_rules";
 
-export class MonochromeRules extends ChessRules {
+export class MonocolorRules extends ChessRules {
 
   static get HasEnpassant() {
     // Pawns would be on the same side
diff --git a/server/db/populate.sql b/server/db/populate.sql
index 7872515f..58af05d1 100644
--- a/server/db/populate.sql
+++ b/server/db/populate.sql
@@ -37,7 +37,8 @@ insert or ignore into Variants (name, description) values
   ('Bicolour', 'Harassed kings'),
   ('Bishopawns', 'Bishop versus pawns'),
   ('Brotherhood', 'Friendly pieces'),
-  ('Cannibal', 'Capture powers'),
+  ('Cannibal1', 'Capture powers (v1)'),
+  ('Cannibal2', 'Capture powers (v2)'),
   ('Capablanca', 'Capablanca Chess'),
   ('Capture', 'Mandatory captures'),
   ('Castle', 'Win by castling long'),
@@ -109,7 +110,7 @@ insert or ignore into Variants (name, description) values
   ('Mesmer', 'Mind control (v2)'),
   ('Minishogi', 'Shogi 5 x 5'),
   ('Minixiangqi', 'Xiangqi 7 x 7'),
-  ('Monochrome', 'All of the same color'),
+  ('Monocolor', 'All of the same color'),
   ('Monster', 'White move twice'),
   ('Musketeer', 'New fairy pieces'),
   ('Omega', 'A wizard in the corner'),