Small fixes
[vchess.git] / client / src / variants / Pacosako.js
index 5eb96b6..ae4fe6f 100644 (file)
@@ -34,6 +34,11 @@ export class PacosakoRules extends ChessRules {
     };
   }
 
+  static fen2board(f) {
+    // Underscore is character 95, in file w_
+    return f.charCodeAt() <= 95 ? "w" + f.toLowerCase() : "b" + f;
+  }
+
   static IsGoodPosition(position) {
     if (position.length == 0) return false;
     const rows = position.split("/");
@@ -508,6 +513,8 @@ export class PacosakoRules extends ChessRules {
     castlingCheck: for (let castleSide = 0; castleSide < 2; castleSide++) {
       if (this.castleFlags[c][castleSide] >= 8) continue;
       const rookPos = this.castleFlags[c][castleSide];
+      const castlingColor = this.board[x][rookPos].charAt(0);
+      const castlingPiece = this.board[x][rookPos].charAt(1);
 
       // Nothing on the path of the king ?
       const finDist = finalSquares[castleSide][0] - y;
@@ -561,14 +568,14 @@ export class PacosakoRules extends ChessRules {
             new PiPo({
               x: x,
               y: finalSquares[castleSide][1],
-              p: V.ROOK,
-              c: c
+              p: castlingPiece,
+              c: castlingColor
             })
           ],
           vanish: [
             // King might be initially disguised (Titan...)
             new PiPo({ x: x, y: y, p: V.KING, c: c }),
-            new PiPo({ x: x, y: rookPos, p: V.ROOK, c: c })
+            new PiPo({ x: x, y: rookPos, p: castlingPiece, c: castlingColor })
           ],
           end:
             Math.abs(y - rookPos) <= 2
@@ -581,6 +588,14 @@ export class PacosakoRules extends ChessRules {
     return moves;
   }
 
+  getEnpassantCaptures(sq, shiftX) {
+    // HACK: when artificially change turn, do not consider en-passant
+    const mcMod2 = this.movesCount % 2;
+    const c = this.turn;
+    if ((c == 'w' && mcMod2 == 1) || (c == 'b' && mcMod2 == 0)) return [];
+    return super.getEnpassantCaptures(sq, shiftX);
+  }
+
   isAttacked_aux(files, color, positions, fromSquare, released) {
     // "positions" = array of FENs to detect infinite loops. Example:
     // r1q1k2r/p1Pb1ppp/5n2/1f1p4/AV5P/P1eDP3/3B1PP1/R3K1NR,
@@ -661,8 +676,47 @@ export class PacosakoRules extends ChessRules {
     return moves.filter(m => !this.oppositeMoves(this.umoves[L - 1], m));
   }
 
+  updateCastleFlags(move, piece) {
+    const c = this.turn;
+    const firstRank = (c == "w" ? 7 : 0);
+    if (piece == V.KING && move.appear.length > 0)
+      this.castleFlags[c] = [V.size.y, V.size.y];
+    else if (
+      move.start.x == firstRank &&
+      this.castleFlags[c].includes(move.start.y)
+    ) {
+      const flagIdx = (move.start.y == this.castleFlags[c][0] ? 0 : 1);
+      this.castleFlags[c][flagIdx] = V.size.y;
+    }
+    else if (
+      move.end.x == firstRank &&
+      this.castleFlags[c].includes(move.end.y)
+    ) {
+      // Move to our rook: necessary normal piece, to union, releasing
+      // (or the rook was moved before!)
+      const flagIdx = (move.end.y == this.castleFlags[c][0] ? 0 : 1);
+      this.castleFlags[c][flagIdx] = V.size.y;
+    }
+  }
+
+  prePlay(move) {
+    // Easier before move is played in this case (flags are saved)
+    const c = this.turn;
+    const L = this.lastMoveEnd.length;
+    const lm = this.lastMoveEnd[L-1];
+    const piece = (!!lm ? lm.p : move.vanish[0].p);
+    if (piece == V.KING)
+      this.kingPos[c] = [move.appear[0].x, move.appear[0].y];
+    this.updateCastleFlags(move, piece);
+    const pawnFirstRank = (c == 'w' ? 6 : 1);
+    if (move.start.x == pawnFirstRank)
+      // This move (potentially) turns off a 2-squares pawn flag
+      this.pawnFlags[c][move.start.y] = false;
+  }
+
   play(move) {
     move.flags = JSON.stringify(this.aggregateFlags());
+    this.prePlay(move);
     this.epSquares.push(this.getEpSquare(move));
     // Check if the move is the last of the turn: all cases except releases
     if (!move.released) {
@@ -674,34 +728,6 @@ export class PacosakoRules extends ChessRules {
     else this.lastMoveEnd.push(Object.assign({ p: move.released }, move.end));
     V.PlayOnBoard(this.board, move);
     this.umoves.push(this.getUmove(move));
-    this.postPlay(move);
-  }
-
-  postPlay(move) {
-    if (move.vanish.length == 0)
-      // A released piece just moved. Cannot be the king.
-      return;
-    const c = move.vanish[0].c;
-    const piece = move.vanish[0].p;
-    if (piece == V.KING)
-      this.kingPos[c] = [move.appear[0].x, move.appear[0].y];
-    this.updateCastleFlags(move, piece);
-    if (
-      [1, 6].includes(move.start.x) &&
-      move.vanish.length >= 1 &&
-      move.appear.length == 1
-    ) {
-      // Does this move turn off a 2-squares pawn flag?
-      if (
-        move.vanish[0].p == V.PAWN ||
-        (
-          !(ChessRules.PIECES.includes(move.vanish[0].p)) &&
-          this.getUnionPieces(move.vanish[0].c, move.vanish[0].p)[c] == V.PAWN
-        )
-      ) {
-        this.pawnFlags[move.start.x == 6 ? "w" : "b"][move.start.y] = false;
-      }
-    }
   }
 
   undo(move) {