Add Alapo, Crossing, Kingsmaker, Squatter variants
[vchess.git] / client / src / variants / Kingsmaker.js
diff --git a/client/src/variants/Kingsmaker.js b/client/src/variants/Kingsmaker.js
new file mode 100644 (file)
index 0000000..a5d2104
--- /dev/null
@@ -0,0 +1,114 @@
+import { ChessRules } from "@/base_rules";
+
+export class KingsmakerRules extends ChessRules {
+
+  static IsGoodPosition(position) {
+    if (position.length == 0) return false;
+    const rows = position.split("/");
+    if (rows.length != V.size.x) return false;
+    let kings = { "k": 0, "K": 0 };
+    for (let row of rows) {
+      let sumElts = 0;
+      for (let i = 0; i < row.length; i++) {
+        if (['K','k'].includes(row[i])) kings[row[i]]++;
+        if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
+        else {
+          const num = parseInt(row[i], 10);
+          if (isNaN(num) || num <= 0) return false;
+          sumElts += num;
+        }
+      }
+      if (sumElts != V.size.y) return false;
+    }
+    // At least one king per color.
+    if (Object.values(kings).some(v => v == 0)) return false;
+    return true;
+  }
+
+  scanKings() {}
+
+  getPotentialMovesFrom([x, y]) {
+    const moves = super.getPotentialMovesFrom([x, y]);
+    if (this.getPiece(x, y) != V.PAWN) return moves;
+    const c = this.getColor(x, y);
+    const oppCol = V.GetOppCol(c);
+    const forward = (c == 'w' ? -1 : 1);
+    const lastRanks = (c == 'w' ? [0, 1] : [7, 6]);
+    let newKingMoves = [];
+    if (lastRanks.includes(x + forward)) {
+      // Manually add promotion into enemy king:
+      const trials = [
+        { step: [forward, 0] },
+        { step: [forward, 1], capture: true },
+        { step: [forward, -1], capture: true }
+      ];
+      for (let s of trials) {
+        const [i, j] = [x + s.step[0], y + s.step[1]];
+        if (
+          V.OnBoard(i, j) &&
+          (
+            (!s.capture && this.board[i][j] == V.EMPTY) ||
+            (
+              s.capture &&
+              this.board[i][j] != V.EMPTY &&
+              this.getColor(i, j) == oppCol
+            )
+          )
+        ) {
+          newKingMoves.push(
+            super.getBasicMove([x, y], [i, j], { c: oppCol, p: V.KING })
+          );
+        }
+      }
+    }
+    return moves.concat(newKingMoves);
+  }
+
+  underCheck(color) {
+    // First at first check found (if any)
+    const oppCol = V.GetOppCol(color);
+    for (let i=0; i<8; i++) {
+      for (let j=0; j<8; j++) {
+        if (
+          this.board[i][j] != V.EMPTY &&
+          this.getPiece(i, j) == V.KING &&
+          this.getColor(i, j) == color
+        ) {
+          if (super.isAttacked([i, j], oppCol)) return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  getCheckSquares() {
+    const color = this.turn;
+    const oppCol = V.GetOppCol(color);
+    let res = [];
+    // Scan all kings
+    for (let i=0; i<8; i++) {
+      for (let j=0; j<8; j++) {
+        if (
+          this.board[i][j] != V.EMPTY &&
+          this.getPiece(i, j) == V.KING &&
+          this.getColor(i, j) == color
+        ) {
+          if (super.isAttacked([i, j], oppCol)) res.push([i, j]);
+        }
+      }
+    }
+    return res;
+  }
+
+  postPlay(move) {
+    this.updateCastleFlags(move, move.vanish[0].p);
+  }
+
+  postUndo() {}
+
+  static get VALUES() {
+    // Assign -5 to the king, so that the bot sometimes promote into king
+    return Object.assign({}, ChessRules.VALUES, { k: -5 });
+  }
+
+};