Add Tencubed and Omega variants + some fixes (updateCastleFlags()) + cleaner FEN...
[vchess.git] / client / src / variants / Tencubed.js
diff --git a/client/src/variants/Tencubed.js b/client/src/variants/Tencubed.js
new file mode 100644 (file)
index 0000000..99bff13
--- /dev/null
@@ -0,0 +1,245 @@
+import { ChessRules } from "@/base_rules";
+import { ArrayFun } from "@/utils/array";
+import { shuffle } from "@/utils/alea";
+
+export class TencubedRules extends ChessRules {
+  static get PawnSpecs() {
+    return Object.assign(
+      {},
+      ChessRules.PawnSpecs,
+      {
+        initShift: { w: 2, b: 2 },
+        promotions: [V.QUEEN, V.MARSHALL, V.ARCHBISHOP]
+      }
+    );
+  }
+
+  static get HasFlags() {
+    return false;
+  }
+
+  getPpath(b) {
+    return (
+      [V.MARSHALL, V.ARCHBISHOP, V.CHAMPION, V.WIZARD].includes(b[1])
+        ? "Tencubed/"
+        : ""
+    ) + b;
+  }
+
+  static get size() {
+    return { x: 10, y: 10 };
+  }
+
+  // Rook + knight:
+  static get MARSHALL() {
+    return "m";
+  }
+
+  // Bishop + knight
+  static get ARCHBISHOP() {
+    return "a";
+  }
+
+  // Dabbabah + alfil + wazir
+  static get CHAMPION() {
+    return "c";
+  }
+
+  // Camel + ferz
+  static get WIZARD() {
+    return "w";
+  }
+
+  static get PIECES() {
+    return (
+      ChessRules.PIECES
+      .concat([V.MARSHALL, V.ARCHBISHOP, V.CHAMPION, V.WIZARD])
+    );
+  }
+
+  static get steps() {
+    return Object.assign(
+      {},
+      ChessRules.steps,
+      {
+        w: [
+          [-3, -1],
+          [-3, 1],
+          [-1, -3],
+          [-1, 3],
+          [1, -3],
+          [1, 3],
+          [3, -1],
+          [3, 1],
+          [-1, -1],
+          [-1, 1],
+          [1, -1],
+          [1, 1]
+        ],
+        c: [
+          [1, 0],
+          [-1, 0],
+          [0, 1],
+          [0, -1],
+          [2, 2],
+          [2, -2],
+          [-2, 2],
+          [-2, -2],
+          [-2, 0],
+          [0, -2],
+          [2, 0],
+          [0, 2]
+        ]
+      }
+    );
+  }
+
+  static GenRandInitFen(randomness) {
+    if (randomness == 0) {
+      return (
+        "2cwamwc2/1rnbqkbnr1/pppppppppp/91/91/" +
+        "91/91/PPPPPPPPPP/1RNBQKBNR1/2CWAMWC2/ " +
+        "w 0 bibi -"
+      );
+    }
+
+    const baseFen = V.ParseFen(ChessRules.GenRandInitFen(randomness));
+    const positionParts = baseFen.position.split("/");
+    const bFen = (
+      "1" + positionParts[0] +
+      "1/pppppppppp/91/91/91/91/PPPPPPPPPP/1" +
+      positionParts[7] + "1"
+    );
+    // Now just obtain randomized new pieces placements:
+    let pieces = { w: new Array(6), b: new Array(6) };
+    for (let c of ["w", "b"]) {
+      if (c == 'b' && randomness == 1) {
+        pieces['b'] = pieces['w'];
+        break;
+      }
+
+      let positions = shuffle(ArrayFun.range(6));
+      const composition = ['w', 'w', 'c', 'c', 'a', 'm'];
+      let rem2 = positions[0] % 2;
+      if (rem2 == positions[1] % 2) {
+        // Fix wizards (on different colors)
+        for (let i=4; i<6; i++) {
+          if (positions[i] % 2 != rem2)
+            [positions[1], positions[i]] = [positions[i], positions[1]];
+        }
+      }
+      rem2 = positions[2] % 2;
+      if (rem2 == positions[3] % 2) {
+        // Fix champions too: [NOTE: positions[4] & [5] should do]
+        for (let i=4; i<6; i++) {
+          if (positions[i] % 2 != rem2)
+            [positions[3], positions[i]] = [positions[i], positions[3]];
+        }
+      }
+      for (let i = 0; i < 9; i++) pieces[c][positions[i]] = composition[i];
+    }
+    return (
+      "2" + pieces["b"].join("") + "2/" +
+      bFen +
+      "/2" + pieces["w"].join("").toUpperCase() + "2" +
+      " w 0 -"
+    );
+  }
+
+  getPotentialMovesFrom([x, y]) {
+    switch (this.getPiece(x, y)) {
+      case V.MARSHALL:
+        return this.getPotentialMarshallMoves([x, y]);
+      case V.ARCHBISHOP:
+        return this.getPotentialArchbishopMoves([x, y]);
+      case V.CHAMPION:
+        return this.getPotentialChampionMoves([x, y]);
+      case V.WIZARD:
+        return this.getPotentialWizardMoves([x, y]);
+      default:
+        return super.getPotentialMovesFrom([x, y]);
+    }
+  }
+
+  getPotentialMarshallMoves(sq) {
+    return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat(
+      this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
+    );
+  }
+
+  getPotentialArchbishopMoves(sq) {
+    return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
+      this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
+    );
+  }
+
+  getPotentialChampionMoves(sq) {
+    return this.getSlideNJumpMoves(sq, V.steps[V.CHAMPION], "oneStep");
+  }
+
+  getPotentialWizardMoves(sq) {
+    return this.getSlideNJumpMoves(sq, V.steps[V.WIZARD], "oneStep");
+  }
+
+  isAttacked(sq, color) {
+    return (
+      super.isAttacked(sq, color) ||
+      this.isAttackedByMarshall(sq, color) ||
+      this.isAttackedByArchbishop(sq, color) ||
+      this.isAttackedByChampion(sq, color) ||
+      this.isAttackedByWizard(sq, color)
+    );
+  }
+
+  isAttackedByMarshall(sq, color) {
+    return (
+      this.isAttackedBySlideNJump(sq, color, V.MARSHALL, V.steps[V.ROOK]) ||
+      this.isAttackedBySlideNJump(
+        sq,
+        color,
+        V.MARSHALL,
+        V.steps[V.KNIGHT],
+        "oneStep"
+      )
+    );
+  }
+
+  isAttackedByArchbishop(sq, color) {
+    return (
+      this.isAttackedBySlideNJump(sq, color, V.CARDINAL, V.steps[V.BISHOP]) ||
+      this.isAttackedBySlideNJump(
+        sq,
+        color,
+        V.CARDINAL,
+        V.steps[V.KNIGHT],
+        "oneStep"
+      )
+    );
+  }
+
+  isAttackedByWizard(sq, color) {
+    return (
+      this.isAttackedBySlideNJump(
+        sq, color, V.WIZARD, V.steps[V.WIZARD], "oneStep")
+    );
+  }
+
+  isAttackedByChampion(sq, color) {
+    return (
+      this.isAttackedBySlideNJump(
+        sq, color, V.CHAMPION, V.steps[V.CHAMPION], "oneStep")
+    );
+  }
+
+  static get SEARCH_DEPTH() {
+    return 2;
+  }
+
+  static get VALUES() {
+    return Object.assign(
+      {},
+      ChessRules.VALUES,
+      { c: 4, w: 3, a: 6, m: 8 }
+    );
+  }
+};