Fix Maxima (immobilize kings too)
[vchess.git] / client / src / variants / Maxima.js
index ab97a21..d8347ac 100644 (file)
@@ -3,6 +3,11 @@ import { ArrayFun } from "@/utils/array";
 import { shuffle } from "@/utils/alea";
 
 export class MaximaRules extends ChessRules {
+
+  static get Options() {
+    return null;
+  }
+
   static get HasFlags() {
     return false;
   }
@@ -49,7 +54,7 @@ export class MaximaRules extends ChessRules {
         if (['K','k'].includes(row[i])) kings[row[i]]++;
         if (['x'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
@@ -76,7 +81,7 @@ export class MaximaRules extends ChessRules {
             this.kingPos["w"] = [i, k];
             break;
           default: {
-            const num = parseInt(position[i].charAt(j));
+            const num = parseInt(position[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
@@ -140,8 +145,9 @@ export class MaximaRules extends ChessRules {
     // Pre-check: is thing on this square immobilized?
     const imSq = this.isImmobilized([x, y]);
     const piece = this.getPiece(x, y);
-    if (!!imSq && piece != V.KING) {
-      // Only option is suicide, if I'm not a king:
+    if (!!imSq) {
+      if (piece == V.KING) return [];
+      // Only option is suicide
       return [
         new Move({
           start: { x: x, y: y },
@@ -177,11 +183,11 @@ export class MaximaRules extends ChessRules {
       return moves;
     // Filter out moves resulting in self palace occupation:
     // NOTE: cannot invade own palace but still check the king there.
-    const pY = (this.board[pX][3] == V.EMPTY ? 4 : 3);
+    const pY = (this.board[pX][3] != V.EMPTY ? 4 : 3);
     return moves.filter(m => m.end.x != pX || m.end.y != pY);
   }
 
-  getSlideNJumpMoves([x, y], steps, oneStep, mageInitSquare, onlyTake) {
+  getSlideNJumpMoves([x, y], steps, oneStep, mageInitSquare) {
     const piece = !mageInitSquare ? this.getPiece(x, y) : V.MAGE;
     const initSquare = mageInitSquare || [x, y];
     let moves = [];
@@ -190,21 +196,16 @@ export class MaximaRules extends ChessRules {
       let j = y + step[1];
       if (piece == V.KING) j = j % V.size.y;
       while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
-        if (!onlyTake) moves.push(this.getBasicMove(initSquare, [i, j]));
-        if (!!oneStep) continue outerLoop;
+        moves.push(this.getBasicMove(initSquare, [i, j]));
+        if (oneStep) continue outerLoop;
         i += step[0];
         j += step[1];
       }
-      // Only king, guard and mage + chameleon can take on occupied square:
+      // Only king, guard and mage (+ chameleon) can take on occupied square:
       if (
-        V.OnBoard(i, j)
-        &&
+        V.OnBoard(i, j) &&
+        [V.KING, V.GUARD, V.MAGE].includes(piece) &&
         this.canTake(initSquare, [i, j])
-        &&
-        (
-          [V.KING, V.GUARD, V.MAGE].includes(piece) ||
-          (piece == V.BISHOP && this.getPiece(i, j) === onlyTake)
-        )
       ) {
         moves.push(this.getBasicMove(initSquare, [i, j]));
       }
@@ -366,12 +367,22 @@ export class MaximaRules extends ChessRules {
     let moves = super
       .getPotentialQueenMoves([x, y])
       .concat(this.getKnightCaptures([x, y], "asChameleon"))
-      .concat(this.getPotentialGuardMoves([x, y], "asChameleon"))
-      .concat(this.getPotentialMageMoves([x, y], "asChameleon"));
     // No "king capture" because king cannot remain under check
     this.addPawnCaptures(moves, "asChameleon");
     this.addRookCaptures(moves, "asChameleon");
     this.addQueenCaptures(moves, "asChameleon");
+    // Manually add Guard and Mage captures (since cannot move like a Mage)
+    V.steps[V.ROOK].concat(V.steps[V.BISHOP]).forEach(step => {
+      const [i, j] = [x + step[0], y + step[1]];
+      if (
+        V.OnBoard(i, j) &&
+        this.board[i][j] != V.EMPTY &&
+        this.canTake([x, y], [i, j]) &&
+        [V.GUARD, V.MAGE].includes(this.getPiece(i, j))
+      ) {
+        moves.push(this.getBasicMove([x, y], [i, j]));
+      }
+    });
     // Post-processing: merge similar moves, concatenating vanish arrays
     let mergedMoves = {};
     moves.forEach(m => {
@@ -443,17 +454,9 @@ export class MaximaRules extends ChessRules {
     return this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep");
   }
 
-  getPotentialGuardMoves(sq, byChameleon) {
-    const onlyTake = !byChameleon ? null : V.GUARD;
-    return (
-      this.getSlideNJumpMoves(
-        sq,
-        V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
-        "oneStep",
-        null,
-        onlyTake
-      )
-    );
+  getPotentialGuardMoves(sq) {
+    return this.getSlideNJumpMoves(
+      sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
   }
 
   getNextMageSteps(step) {
@@ -465,29 +468,24 @@ export class MaximaRules extends ChessRules {
     return [[1, 0], [0, 1]];
   }
 
-  getPotentialMageMoves([x, y], byChameleon) {
+  getPotentialMageMoves([x, y]) {
     const oppCol = V.GetOppCol(this.turn);
-    const onlyTake = !byChameleon ? null : V.MAGE;
     let moves = [];
     for (let step of V.steps[V.BISHOP]) {
       let [i, j] = [x + step[0], y + step[1]];
       if (!V.OnBoard(i, j)) continue;
       if (this.board[i][j] != V.EMPTY) {
-        if (
-          this.getColor(i, j) == oppCol &&
-          (!onlyTake || this.getPiece(i, j) == V.MAGE)
-        ) {
+        if (this.getColor(i, j) == oppCol)
           // Capture
           moves.push(this.getBasicMove([x, y], [i, j]));
-        }
       }
       else {
-        if (!onlyTake) moves.push(this.getBasicMove([x, y], [i, j]));
+        moves.push(this.getBasicMove([x, y], [i, j]));
         // Continue orthogonally:
         const stepO = this.getNextMageSteps(step);
         Array.prototype.push.apply(
           moves,
-          this.getSlideNJumpMoves([i, j], stepO, null, [x, y], onlyTake)
+          this.getSlideNJumpMoves([i, j], stepO, null, [x, y])
         );
       }
     }
@@ -680,15 +678,8 @@ export class MaximaRules extends ChessRules {
   }
 
   isAttackedByGuard(sq, color) {
-    return (
-      super.isAttackedBySlideNJump(
-        sq,
-        color,
-        V.GUARD,
-        V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
-        "oneStep"
-      )
-    );
+    return super.isAttackedBySlideNJump(
+      sq, color, V.GUARD, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), 1);
   }
 
   getNextMageCheck(step) {
@@ -829,4 +820,5 @@ export class MaximaRules extends ChessRules {
     if (move.vanish.length > 1 && move.appear[0].p != V.KING) notation += "X";
     return notation;
   }
+
 };