Add Brotherhood, Maharajah (special version) + Dobutsu variants
[vchess.git] / client / src / variants / Maharajah.js
diff --git a/client/src/variants/Maharajah.js b/client/src/variants/Maharajah.js
new file mode 100644 (file)
index 0000000..a49828b
--- /dev/null
@@ -0,0 +1,185 @@
+import { ChessRules } from "@/base_rules";
+
+export class MaharajahRules extends ChessRules {
+
+  static get HasEnpassant() {
+    return false;
+  }
+
+  static get MAHARAJAH() {
+    return 'm';
+  }
+
+  getPpath(b) {
+    return b.charAt(0) == 'w' ? b : "Maharajah/bm";
+  }
+
+  static get PIECES() {
+    return ChessRules.PIECES.concat([V.MAHARAJAH]);
+  }
+
+  static get M_EXTRA_STEPS() {
+    return [
+      // Jumping options:
+      [-2, -2],
+      [-2, 0],
+      [-2, 2],
+      [0, -2],
+      [0, 2],
+      [2, -2],
+      [2, 0],
+      [2, 2]
+    ];
+  }
+
+  static IsGoodPosition(position) {
+    if (position.length == 0) return false;
+    const rows = position.split("/");
+    if (rows.length != V.size.x) return false;
+    let wKingCount = 0;
+    for (let row of rows) {
+      let sumElts = 0;
+      for (let i = 0; i < row.length; i++) {
+        const lowR = row[i].toLowerCase();
+        if (!!lowR.match(/[a-z]/)) {
+          if (row[i] == lowR && row[i] != 'm') return false;
+          if (row[i] == 'K') wKingCount++;
+          if (V.PIECES.includes(lowR)) sumElts++;
+        }
+        else {
+          const num = parseInt(row[i], 10);
+          if (isNaN(num) || num <= 0) return false;
+          sumElts += num;
+        }
+      }
+      if (sumElts != V.size.y) return false;
+    }
+    if (wKingCount != 1) return false;
+    return true;
+  }
+
+  static IsGoodFlags(flags) {
+    // Only white can castle
+    return !!flags.match(/^[a-z]{2,2}$/);
+  }
+
+  scanKings(fen) {
+    // Square of white king only:
+    this.kingPos = { w: [-1, -1], b: [-1, -1] };
+    const fenRows = V.ParseFen(fen).position.split("/");
+    for (let i = 0; i < fenRows.length; i++) {
+      let k = 0; //column index on board
+      for (let j = 0; j < fenRows[i].length; j++) {
+        switch (fenRows[i].charAt(j)) {
+          case "K":
+            this.kingPos["w"] = [i, k];
+            break;
+          default: {
+            const num = parseInt(fenRows[i].charAt(j), 10);
+            if (!isNaN(num)) k += num - 1;
+          }
+        }
+        k++;
+      }
+    }
+  }
+
+  static GenRandInitFen(randomness) {
+    const sFen = ChessRules.GenRandInitFen(Math.max(randomness, 1));
+    return "3mm3/8/" + sFen.substring(18, 50);
+  }
+
+  getFlagsFen() {
+    return this.castleFlags['w'].map(V.CoordToColumn).join("");
+  }
+
+  setFlags(fenflags) {
+    this.castleFlags = { 'w': [-1, -1] };
+    for (let i = 0; i < 2; i++)
+      this.castleFlags['w'][i] = V.ColumnToCoord(fenflags.charAt(i));
+  }
+
+  getPotentialMovesFrom(sq) {
+    if (this.turn == 'w') return super.getPotentialMovesFrom(sq);
+    return this.getPotentialMaharajahMoves(sq);
+  }
+
+  getPotentialMaharajahMoves(sq) {
+    let moves = super.getPotentialQueenMoves(sq);
+    moves = moves.concat(super.getPotentialKnightMoves(sq));
+    const otherJumpMoves =
+      super.getSlideNJumpMoves(sq, V.M_EXTRA_STEPS, "oneStep")
+      .filter(m =>
+        moves.every(mv => mv.end.x != m.end.x || mv.end.y != m.end.y));
+    return moves.concat(otherJumpMoves);
+  }
+
+  isAttacked() {
+    return false;
+  }
+  getCheckSquares() {
+    return [];
+  }
+  filterValid(moves) {
+    return moves;
+  }
+
+  updateCastleFlags(move, piece) {
+    // Only white can castle:
+    const firstRank = 7;
+    if (piece == V.KING && move.appear[0].c == 'w')
+      this.castleFlags['w'] = [8, 8];
+    else if (
+      move.start.x == firstRank &&
+      this.castleFlags['w'].includes(move.start.y)
+    ) {
+      const flagIdx = (move.start.y == this.castleFlags['w'][0] ? 0 : 1);
+      this.castleFlags['w'][flagIdx] = 8;
+    }
+    else if (
+      move.end.x == firstRank &&
+      this.castleFlags['w'].includes(move.end.y)
+    ) {
+      const flagIdx = (move.end.y == this.castleFlags['w'][0] ? 0 : 1);
+      this.castleFlags['w'][flagIdx] = 8;
+    }
+  }
+
+  postPlay(move) {
+    if (this.turn == 'b') super.postPlay(move);
+    else {
+      // After a black move: white king may have disappeared
+      if (move.vanish.length == 2 && move.vanish[1].p == V.KING)
+        this.kingPos['w'] = [-1, -1];
+    }
+  }
+
+  postUndo(move) {
+    if (this.turn == 'w') super.postUndo(move);
+    else {
+      // After undoing a black move (may have captured king)
+      if (move.vanish.length == 2 && move.vanish[1].p == V.KING)
+        this.kingPos['w'] = [move.end.x, move.end.y];
+    }
+  }
+
+  getCurrentScore() {
+    if (this.turn == 'w' && this.kingPos['w'][0] < 0) return "0-1";
+    if (
+      this.turn == 'b' &&
+      this.board.every(row => row.every(cell => cell.charAt(0) != 'b'))
+    ) {
+      return "1-0";
+    }
+    return "*";
+  }
+
+  static get VALUES() {
+    return Object.assign({ m: 15 }, ChessRules.VALUES);
+  }
+
+  static get SEARCH_DEPTH() {
+    return 2;
+  }
+
+};