Add unambiguous section in the PGN + some fixes + code formatting and fix typos
[vchess.git] / client / src / variants / Baroque.js
index a860fe7..016f7b7 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;
   }
@@ -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 })];
@@ -352,17 +356,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 +371,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 +393,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,24 +406,25 @@ 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 (
@@ -438,7 +440,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,7 +455,7 @@ 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])
@@ -461,7 +463,8 @@ export const VariantRules = class BaroqueRules extends ChessRules {
                 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 +476,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,7 +485,7 @@ 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.getColor(i, j) == color &&
         this.getPiece(i, j) == V.BISHOP
       ) {
         return true; //bishops are never immobilized
@@ -491,7 +494,7 @@ export const VariantRules = class BaroqueRules extends ChessRules {
     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 +504,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 +515,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 +523,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;
@@ -546,7 +549,6 @@ export const VariantRules = class BaroqueRules extends ChessRules {
   }
 
   static GenRandInitFen(randomness) {
-    if (!randomness) randomness = 2;
     if (randomness == 0)
       // Deterministic:
       return "rnbqkbnrm/pppppppp/8/8/8/8/PPPPPPPP/MNBKQBNR w 0";
@@ -559,46 +561,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("") +