Draft Ball variant + some fixes, enhancements and code cleaning
[vchess.git] / client / src / variants / Suction.js
index bfb9fa0..2038e4f 100644 (file)
@@ -1,6 +1,46 @@
 import { ChessRules, PiPo, Move } from "@/base_rules";
 
-export const VariantRules = class AntimatterRules extends ChessRules {
+export class SuctionRules extends ChessRules {
+  static get HasFlags() {
+    return false;
+  }
+
+  setOtherVariables(fen) {
+    super.setOtherVariables(fen);
+    // Local stack of "captures"
+    this.cmoves = [];
+    const cmove = V.ParseFen(fen).cmove;
+    if (cmove == "-") this.cmoves.push(null);
+    else {
+      this.cmoves.push({
+        start: ChessRules.SquareToCoords(cmove.substr(0, 2)),
+        end: ChessRules.SquareToCoords(cmove.substr(2))
+      });
+    }
+  }
+
+  static ParseFen(fen) {
+    return Object.assign(
+      ChessRules.ParseFen(fen),
+      { cmove: fen.split(" ")[4] }
+    );
+  }
+
+  static IsGoodFen(fen) {
+    if (!ChessRules.IsGoodFen(fen)) return false;
+    const fenParts = fen.split(" ");
+    if (fenParts.length != 6) return false;
+    if (fenParts[5] != "-" && !fenParts[5].match(/^([a-h][1-8]){2}$/))
+      return false;
+    return true;
+  }
+
+  getCmove(move) {
+    if (move.vanish.length == 2)
+      return { start: move.start, end: move.end };
+    return null;
+  }
+
   getBasicMove([sx, sy], [ex, ey]) {
     const startColor = this.getColor(sx, sy);
     const startPiece = this.getPiece(sx, sy);
@@ -46,50 +86,8 @@ export const VariantRules = class AntimatterRules extends ChessRules {
     return mv;
   }
 
-  getPotentialPawnMoves([x, y]) {
-    const color = this.turn;
+  getEnpassantCaptures([x, y], shiftX) {
     let moves = [];
-    const [sizeX, sizeY] = [V.size.x, V.size.y];
-    const shiftX = color == "w" ? -1 : 1;
-    const startRank = color == "w" ? sizeX - 2 : 1;
-    const firstRank = color == "w" ? sizeX - 1 : 0;
-
-    if (x + shiftX >= 0 && x + shiftX < sizeX) {
-      // One square forward
-      if (this.board[x + shiftX][y] == V.EMPTY) {
-        moves.push(
-          this.getBasicMove([x, y], [x + shiftX, y], {
-            c: color,
-            p: "p"
-          })
-        );
-        if (
-          [startRank,firstRank].includes(x) &&
-          this.board[x + 2 * shiftX][y] == V.EMPTY
-        ) {
-          // Two squares jump
-          moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
-        }
-      }
-      // Swaps
-      for (let shiftY of [-1, 1]) {
-        if (
-          y + shiftY >= 0 &&
-          y + shiftY < sizeY &&
-          this.board[x + shiftX][y + shiftY] != V.EMPTY &&
-          this.canTake([x, y], [x + shiftX, y + shiftY])
-        ) {
-          moves.push(
-            this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
-              c: color,
-              p: "p"
-            })
-          );
-        }
-      }
-    }
-
-    // En passant
     const Lep = this.epSquares.length;
     const epSquare = this.epSquares[Lep - 1]; //always at least one element
     if (
@@ -113,7 +111,6 @@ export const VariantRules = class AntimatterRules extends ChessRules {
       });
       moves.push(enpassantMove);
     }
-
     return moves;
   }
 
@@ -121,32 +118,64 @@ export const VariantRules = class AntimatterRules extends ChessRules {
     return [];
   }
 
-  updateVariables(move) {
-    super.updateVariables(move);
+  // Does m2 un-do m1 ? (to disallow undoing captures)
+  oppositeMoves(m1, m2) {
+    return (
+      m1 &&
+      m2.vanish.length == 2 &&
+      m1.start.x == m2.start.x &&
+      m1.end.x == m2.end.x &&
+      m1.start.y == m2.start.y &&
+      m1.end.y == m2.end.y
+    );
+  }
+
+  filterValid(moves) {
+    if (moves.length == 0) return [];
+    const color = this.turn;
+    return moves.filter(m => {
+      const L = this.cmoves.length; //at least 1: init from FEN
+      return !this.oppositeMoves(this.cmoves[L - 1], m);
+    });
+  }
+
+  static GenRandInitFen(randomness) {
+    // Add empty cmove:
+    return ChessRules.GenRandInitFen(randomness).slice(0, -6) + "- -";
+  }
+
+  getFen() {
+    const L = this.cmoves.length;
+    const cmoveFen = !this.cmoves[L - 1]
+      ? "-"
+      : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) +
+        ChessRules.CoordsToSquare(this.cmoves[L - 1].end);
+    return super.getFen() + " " + cmoveFen;
+  }
+
+  postPlay(move) {
+    super.postPlay(move);
     if (move.vanish.length == 2) {
       // Was opponent king swapped?
       if (move.vanish[1].p == V.KING)
         this.kingPos[this.turn] = [move.appear[1].x, move.appear[1].y];
     }
+    this.cmoves.push(this.getCmove(move));
   }
 
-  unupdateVariables(move) {
-    super.unupdateVariables(move);
+  postUndo(move) {
+    super.postUndo(move);
     if (move.appear.length == 2) {
-      // Was opponent king swapped?
       if (move.appear[1].p == V.KING)
-        this.kingPos[move.vanish[1].c] = [move.vanish[1].x,move.vanish[1].y];
+        this.kingPos[move.vanish[1].c] = [move.vanish[1].x, move.vanish[1].y];
     }
+    this.cmoves.pop();
   }
 
   atLeastOneMove() {
     return true;
   }
 
-  filterValid(moves) {
-    return moves;
-  }
-
   getCheckSquares() {
     return [];
   }
@@ -154,10 +183,8 @@ export const VariantRules = class AntimatterRules extends ChessRules {
   getCurrentScore() {
     const color = this.turn;
     const kp = this.kingPos[color];
-    if (color == "w" && kp[0] == 0)
-      return "0-1";
-    if (color == "b" && kp[0] == V.size.x - 1)
-      return "1-0";
+    if (color == "w" && kp[0] == 0) return "0-1";
+    if (color == "b" && kp[0] == V.size.x - 1) return "1-0";
     // King is not on the opposite edge: game not over
     return "*";
   }
@@ -166,4 +193,28 @@ export const VariantRules = class AntimatterRules extends ChessRules {
     // Very simple criterion for now: kings position
     return this.kingPos["w"][0] + this.kingPos["b"][0];
   }
+
+  getNotation(move) {
+    // Translate final square
+    const finalSquare = V.CoordsToSquare(move.end);
+
+    const piece = this.getPiece(move.start.x, move.start.y);
+    if (piece == V.PAWN) {
+      // Pawn move
+      let notation = "";
+      if (move.vanish.length == 2) {
+        // Capture
+        const startColumn = V.CoordToColumn(move.start.y);
+        notation = startColumn + "x" + finalSquare;
+      }
+      else notation = finalSquare;
+      return notation;
+    }
+    // Piece movement
+    return (
+      piece.toUpperCase() +
+      (move.vanish.length == 2 ? "x" : "") +
+      finalSquare
+    );
+  }
 };