From 462947f0a6c5f33033bbee5d42d38149be6d51cb Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Fri, 1 Jul 2022 15:37:44 +0200
Subject: [PATCH] Animate castle moves + better Apocalypse draft

---
 TODO                         |  2 -
 base_rules.js                | 19 +++++++++
 variants/Apocalypse/class.js | 83 +++++++++++++++++++-----------------
 3 files changed, 63 insertions(+), 41 deletions(-)

diff --git a/TODO b/TODO
index c2ab9af..1e4eda3 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,3 @@
-Animate castle by both movements (and generalize? match vanishes with appears?)
-
 add variants :
 Dark Racing Kings ? Checkered-Teleport ?
 
diff --git a/base_rules.js b/base_rules.js
index beac0bb..ebf8f1e 100644
--- a/base_rules.js
+++ b/base_rules.js
@@ -2583,12 +2583,31 @@ export default class ChessRules {
         this.animateFading(arr, () => targetObj.increment());
       }
     }
+    targetObj.target +=
+      this.tryAnimateCastle(move, () => targetObj.increment());
     targetObj.target +=
       this.customAnimate(move, segments, () => targetObj.increment());
     if (targetObj.target == 0)
       callback();
   }
 
+  tryAnimateCastle(move, cb) {
+    if (
+      this.hasCastle &&
+      move.vanish.length == 2 &&
+      move.appear.length == 2 &&
+      this.isKing(0, 0, move.vanish[0].p) &&
+      this.isKing(0, 0, move.appear[0].p)
+    ) {
+      const start = {x: move.vanish[1].x, y: move.vanish[1].y},
+            end = {x: move.appear[1].x, y: move.appear[1].y};
+      const segments = [ [[start.x, start.y], [end.x, end.y]] ];
+      this.animateMoving(start, end, null, segments, cb);
+      return 1;
+    }
+    return 0;
+  }
+
   // Potential other animations (e.g. for Suction variant)
   customAnimate(move, segments, cb) {
     return 0; //nb of targets
diff --git a/variants/Apocalypse/class.js b/variants/Apocalypse/class.js
index e91cf81..c0cd8ee 100644
--- a/variants/Apocalypse/class.js
+++ b/variants/Apocalypse/class.js
@@ -1,4 +1,5 @@
 import ChessRules from "/base_rules.js";
+import {ArrayFun} from "/utils/array.js";
 
 export class ApocalypseRules extends ChessRules {
 
@@ -14,6 +15,13 @@ export class ApocalypseRules extends ChessRules {
     return {x: 5, y: 5};
   }
 
+  setOtherVariables(fenParsed) {
+    super.setOtherVariables(fenParsed);
+    this.whiteMove = fenParsed.whiteMove != "-"
+      ? JSON.parse(fenParsed.whiteMove)
+      : null;
+  }
+
   genRandInitBaseFen() {
     return {
       fen: "npppn/p3p/5/P3P/NPPPN w 0",
@@ -28,46 +36,21 @@ export class ApocalypseRules extends ChessRules {
   }
 
   getFlagsFen() {
-    return (
-      this.penaltyFlags['w'].toString() + this.penaltyFlags['b'].toString()
-    );
-  }
-
-  setOtherVariables(fen) {
-    const parsedFen = V.ParseFen(fen);
-    this.setFlags(parsedFen.flags);
-    // Also init whiteMove
-    this.whiteMove =
-      parsedFen.whiteMove != "-"
-        ? JSON.parse(parsedFen.whiteMove)
-        : null;
+    return Object.values(this.penaltyFlags).join("");
   }
 
   setFlags(fenflags) {
-    this.penaltyFlags = {
-      'w': parseInt(fenflags[0], 10),
-      'b': parseInt(fenflags[1], 10)
-    };
+    this.penaltyFlags = ArrayFun.toObject(
+      ['w', 'b'], [0, 1].map(i => parseInt(fenflags.charAt(i), 10)));
   }
 
-  // TODO: could be a stack of 2 (pawn promote + relocation)
   getWhitemoveFen() {
-    if (!this.whiteMove) return "-";
-    return JSON.stringify({
-      start: this.whiteMove.start,
-      end: this.whiteMove.end,
-      appear: this.whiteMove.appear,
-      vanish: this.whiteMove.vanish
-    });
+    return !this.whiteMove ? "-" : JSON.stringify(this.whiteMove);
   }
 
-  // allow pawns to move diagonally and capture vertically --> only purpose illegal
-  // allow capture self --> same purpose
-  // ---> MARK such moves : move.illegal = true
-
-  // simpler: allow all moves, including "capturing nothing"
-  // flag every pawn capture as "illegal" (potentially)
-
+  // Allow pawns to move diagonally and capture vertically,
+  // because some of these moves might be valid a posteriori.
+  // They will be flagged as 'illegal' in a first time, however.
   pieces(color, x, y) {
     const pawnShift = (color == "w" ? -1 : 1);
     return {
@@ -84,6 +67,8 @@ export class ApocalypseRules extends ChessRules {
     };
   }
 
+  // Allow self-captures, because they might be valid
+  // if opponent takes on the same square (luck...)
   canTake() {
     return true;
   }
@@ -132,6 +117,9 @@ export class ApocalypseRules extends ChessRules {
     return moves;
   }
 
+
+//TODO: from here
+
   // White and black (partial) moves were played: merge
   // + animate both at the same time !
   resolveSynchroneMove(move) {
@@ -139,7 +127,7 @@ export class ApocalypseRules extends ChessRules {
   }
 
   play(move) {
-    // Do not play on board (would reveal the move...)
+    if (this.subTurn...) //TODO: detect (mark?) if pawn move arriving on last rank (=> subTurn++)
     this.turn = V.GetOppCol(this.turn);
     this.movesCount++;
     this.postPlay(move);
@@ -156,21 +144,38 @@ export class ApocalypseRules extends ChessRules {
     }
     else {
       // A full turn just ended:
-      const smove = this.resolveSynchroneMove(move);
+      const [wMove, bMove] = this.resolveSynchroneMove(move);
       V.PlayOnBoard(this.board, smove); //----> ici : animate both !
       this.whiteMove = null;
     }
   }
 
-  atLeastOneLegalMove(...) {
-    // TODO
+//until here
+
+
+  atLeastOneLegalMove(color) {
+    for (let i=0; i<this.size.x; i++) {
+      for (let j=0; j<this.size.y; j++) {
+        if (
+          this.board[i][j] != "" &&
+          this.getColor(i, j) == color &&
+          this.getPotentialMoves([i, j]).some(m => !m.illegal)
+        ) {
+          return true;
+        }
+      }
+    }
+    return false;
   }
 
   getCurrentScore() {
-    if (this.turn == 'b')
-      // Turn (white + black) not over yet. Could be stalemate if black cannot move (legally)
-      // TODO: check. If so, return "1/2".
+    if (this.turn == 'b') {
+      // Turn (white + black) not over yet.
+      // Could be stalemate if black cannot move (legally):
+      if (!this.atLeastOneLegalMove('b'))
+        return "1/2";
       return "*";
+    }
     // Count footmen: if a side has none, it loses
     let fmCount = { 'w': 0, 'b': 0 };
     for (let i=0; i<5; i++) {
-- 
2.44.0