Fix parseInt() usage, rename Doubleorda --> Ordamirror, implement Clorange variant
[vchess.git] / client / src / variants / Baroque.js
index 246f511..4ff23a0 100644 (file)
@@ -1,8 +1,8 @@
 import { ChessRules, PiPo, Move } from "@/base_rules";
 import { ArrayFun } from "@/utils/array";
-import { randInt } from "@/utils/alea";
+import { shuffle } from "@/utils/alea";
 
-export const VariantRules = class BaroqueRules extends ChessRules {
+export class BaroqueRules extends ChessRules {
   static get HasFlags() {
     return false;
   }
@@ -38,7 +38,7 @@ export const VariantRules = class BaroqueRules 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;
           }
         }
@@ -87,7 +87,8 @@ export const VariantRules = class BaroqueRules extends ChessRules {
           }
           return true; //immobilizer isn't neutralized
         }
-        // Chameleons can't be immobilized twice, because there is only one immobilizer
+        // Chameleons can't be immobilized twice,
+        // because there is only one immobilizer
         if (oppPiece == V.BISHOP && piece == V.IMMOBILIZER) return true;
       }
     }
@@ -130,7 +131,9 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     const color = this.turn;
     const oppCol = V.GetOppCol(color);
     moves.forEach(m => {
-      if (!!byChameleon && m.start.x != m.end.x && m.start.y != m.end.y) return; //chameleon not moving as pawn
+      if (!!byChameleon && m.start.x != m.end.x && m.start.y != m.end.y)
+        // Chameleon not moving as pawn
+        return;
       // Try capturing in every direction
       for (let step of steps) {
         const sq2 = [m.end.x + 2 * step[0], m.end.y + 2 * step[1]];
@@ -224,10 +227,11 @@ export const VariantRules = class BaroqueRules extends ChessRules {
       ) {
         continue;
       }
-      // last(thing), cur(thing) : stop if "cur" is our color, or beyond board limits,
-      // or if "last" isn't empty and cur neither. Otherwise, if cur is empty then
-      // add move until cur square; if cur is occupied then stop if !!byChameleon and
-      // the square not occupied by a leaper.
+      // last(thing), cur(thing) : stop if "cur" is our color,
+      // or beyond board limits, or if "last" isn't empty and cur neither.
+      // Otherwise, if cur is empty then add move until cur square;
+      // if cur is occupied then stop if !!byChameleon and the square not
+      // occupied by a leaper.
       let last = [i, j];
       let cur = [i + step[0], j + step[1]];
       let vanished = [new PiPo({ x: x, y: y, c: color, p: piece })];
@@ -289,12 +293,7 @@ export const VariantRules = class BaroqueRules extends ChessRules {
           mergedMoves[key].vanish.push(m.vanish[i]);
       }
     });
-    // Finally return an array
-    moves = [];
-    Object.keys(mergedMoves).forEach(k => {
-      moves.push(mergedMoves[k]);
-    });
-    return moves;
+    return Object.values(mergedMoves);
   }
 
   addQueenCaptures(moves, byChameleon) {
@@ -352,17 +351,9 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     return super.getPotentialQueenMoves(sq);
   }
 
-  getPotentialKingMoves(sq) {
-    return this.getSlideNJumpMoves(
-      sq,
-      V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
-      "oneStep"
-    );
-  }
-
   // isAttacked() is OK because the immobilizer doesn't take
 
-  isAttackedByPawn([x, y], colors) {
+  isAttackedByPawn([x, y], color) {
     // Square (x,y) must be surroundable by two enemy pieces,
     // and one of them at least should be a pawn (moving).
     const dirs = [
@@ -375,12 +366,17 @@ export const VariantRules = class BaroqueRules extends ChessRules {
       const [i2, j2] = [x + dir[0], y + dir[1]]; //"after"
       if (V.OnBoard(i1, j1) && V.OnBoard(i2, j2)) {
         if (
-          (this.board[i1][j1] != V.EMPTY &&
-            colors.includes(this.getColor(i1, j1)) &&
-            this.board[i2][j2] == V.EMPTY) ||
-          (this.board[i2][j2] != V.EMPTY &&
-            colors.includes(this.getColor(i2, j2)) &&
-            this.board[i1][j1] == V.EMPTY)
+          (
+            this.board[i1][j1] != V.EMPTY &&
+            this.getColor(i1, j1) == color &&
+            this.board[i2][j2] == V.EMPTY
+          )
+          ||
+          (
+            this.board[i2][j2] != V.EMPTY &&
+            this.getColor(i2, j2) == color &&
+            this.board[i1][j1] == V.EMPTY
+          )
         ) {
           // Search a movable enemy pawn landing on the empty square
           for (let step of steps) {
@@ -392,7 +388,7 @@ export const VariantRules = class BaroqueRules extends ChessRules {
             }
             if (
               V.OnBoard(i3, j3) &&
-              colors.includes(this.getColor(i3, j3)) &&
+              this.getColor(i3, j3) == color &&
               this.getPiece(i3, j3) == V.PAWN &&
               !this.isImmobilized([i3, j3])
             ) {
@@ -405,31 +401,33 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     return false;
   }
 
-  isAttackedByRook([x, y], colors) {
+  isAttackedByRook([x, y], color) {
     // King must be on same column or row,
     // and a rook should be able to reach a capturing square
-    // colors contains only one element, giving the oppCol and thus king position
-    const sameRow = x == this.kingPos[colors[0]][0];
-    const sameColumn = y == this.kingPos[colors[0]][1];
+    const sameRow = x == this.kingPos[color][0];
+    const sameColumn = y == this.kingPos[color][1];
     if (sameRow || sameColumn) {
       // Look for the enemy rook (maximum 1)
       for (let i = 0; i < V.size.x; i++) {
         for (let j = 0; j < V.size.y; j++) {
           if (
             this.board[i][j] != V.EMPTY &&
-            colors.includes(this.getColor(i, j)) &&
+            this.getColor(i, j) == color &&
             this.getPiece(i, j) == V.ROOK
           ) {
-            if (this.isImmobilized([i, j])) return false; //because only one rook
-            // Can it reach a capturing square?
-            // Easy but quite suboptimal way (TODO): generate all moves (turn is OK)
+            if (this.isImmobilized([i, j]))
+              // Because only one rook:
+              return false;
+            // Can it reach a capturing square? Easy but quite suboptimal way
+            // (TODO: generate all moves (turn is OK))
             const moves = this.getPotentialMovesFrom([i, j]);
             for (let move of moves) {
               if (
                 (sameRow && move.end.y == y) ||
                 (sameColumn && move.end.x == x)
-              )
+              ) {
                 return true;
+              }
             }
           }
         }
@@ -438,7 +436,7 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     return false;
   }
 
-  isAttackedByKnight([x, y], colors) {
+  isAttackedByKnight([x, y], color) {
     // Square (x,y) must be on same line as a knight,
     // and there must be empty square(s) behind.
     const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
@@ -453,15 +451,17 @@ export const VariantRules = class BaroqueRules extends ChessRules {
             j -= step[1];
           }
           if (V.OnBoard(i, j)) {
-            if (colors.includes(this.getColor(i, j))) {
+            if (this.getColor(i, j) == color) {
               if (
                 this.getPiece(i, j) == V.KNIGHT &&
                 !this.isImmobilized([i, j])
-              )
+              ) {
                 return true;
+              }
               continue outerLoop;
             }
-            // [else] Our color, could be captured *if there was an empty space*
+            // [else] Our color,
+            // could be captured *if there was an empty space*
             if (this.board[i + step[0]][j + step[1]] != V.EMPTY)
               continue outerLoop;
             i -= step[0];
@@ -473,7 +473,7 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     return false;
   }
 
-  isAttackedByBishop([x, y], colors) {
+  isAttackedByBishop([x, y], color) {
     // We cheat a little here: since this function is used exclusively for
     // the king, it's enough to check the immediate surrounding of the square.
     const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
@@ -482,16 +482,17 @@ export const VariantRules = class BaroqueRules extends ChessRules {
       if (
         V.OnBoard(i, j) &&
         this.board[i][j] != V.EMPTY &&
-        colors.includes(this.getColor(i, j)) &&
-        this.getPiece(i, j) == V.BISHOP
+        this.getColor(i, j) == color &&
+        this.getPiece(i, j) == V.BISHOP &&
+        !this.isImmobilized([i, j])
       ) {
-        return true; //bishops are never immobilized
+        return true;
       }
     }
     return false;
   }
 
-  isAttackedByQueen([x, y], colors) {
+  isAttackedByQueen([x, y], color) {
     // Square (x,y) must be adjacent to a queen, and the queen must have
     // some free space in the opposite direction from (x,y)
     const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
@@ -501,7 +502,7 @@ export const VariantRules = class BaroqueRules extends ChessRules {
         const sq1 = [x + step[0], y + step[1]];
         if (
           this.board[sq1[0]][sq1[1]] != V.EMPTY &&
-          colors.includes(this.getColor(sq1[0], sq1[1])) &&
+          this.getColor(sq1[0], sq1[1]) == color &&
           this.getPiece(sq1[0], sq1[1]) == V.QUEEN &&
           !this.isImmobilized(sq1)
         ) {
@@ -512,7 +513,7 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     return false;
   }
 
-  isAttackedByKing([x, y], colors) {
+  isAttackedByKing([x, y], color) {
     const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
     for (let step of steps) {
       let rx = x + step[0],
@@ -520,7 +521,7 @@ export const VariantRules = class BaroqueRules extends ChessRules {
       if (
         V.OnBoard(rx, ry) &&
         this.getPiece(rx, ry) === V.KING &&
-        colors.includes(this.getColor(rx, ry)) &&
+        this.getColor(rx, ry) == color &&
         !this.isImmobilized([rx, ry])
       ) {
         return true;
@@ -529,26 +530,10 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     return false;
   }
 
-  static get VALUES() {
-    return {
-      p: 1,
-      r: 2,
-      n: 5,
-      b: 3,
-      q: 3,
-      m: 5,
-      k: 1000
-    };
-  }
-
-  static get SEARCH_DEPTH() {
-    return 2;
-  }
-
   static GenRandInitFen(randomness) {
     if (randomness == 0)
       // Deterministic:
-      return "rnbqkbnrm/pppppppp/8/8/8/8/PPPPPPPP/MNBKQBNR w 0";
+      return "rnbkqbnm/pppppppp/8/8/8/8/PPPPPPPP/MNBQKBNR w 0";
 
     let pieces = { w: new Array(8), b: new Array(8) };
     // Shuffle pieces on first and last rank
@@ -558,46 +543,10 @@ export const VariantRules = class BaroqueRules extends ChessRules {
         break;
       }
 
-      let positions = ArrayFun.range(8);
       // Get random squares for every piece, totally freely
-
-      let randIndex = randInt(8);
-      const bishop1Pos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(7);
-      const bishop2Pos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(6);
-      const knight1Pos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(5);
-      const knight2Pos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(4);
-      const queenPos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(3);
-      const kingPos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(2);
-      const rookPos = positions[randIndex];
-      positions.splice(randIndex, 1);
-      const immobilizerPos = positions[0];
-
-      pieces[c][bishop1Pos] = "b";
-      pieces[c][bishop2Pos] = "b";
-      pieces[c][knight1Pos] = "n";
-      pieces[c][knight2Pos] = "n";
-      pieces[c][queenPos] = "q";
-      pieces[c][kingPos] = "k";
-      pieces[c][rookPos] = "r";
-      pieces[c][immobilizerPos] = "m";
+      let positions = shuffle(ArrayFun.range(8));
+      const composition = ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'm'];
+      for (let i = 0; i < 8; i++) pieces[c][positions[i]] = composition[i];
     }
     return (
       pieces["b"].join("") +
@@ -607,6 +556,22 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     );
   }
 
+  static get VALUES() {
+    return {
+      p: 1,
+      r: 2,
+      n: 5,
+      b: 3,
+      q: 3,
+      m: 5,
+      k: 1000
+    };
+  }
+
+  static get SEARCH_DEPTH() {
+    return 2;
+  }
+
   getNotation(move) {
     const initialSquare = V.CoordsToSquare(move.start);
     const finalSquare = V.CoordsToSquare(move.end);