Draft of problems section
[vchess.git] / client / src / base_rules.js
index 5fb0027..924f737 100644 (file)
@@ -2,7 +2,7 @@
 // Variants generally inherit from it, and modify some parts.
 
 import { ArrayFun } from "@/utils/array";
-import { randInt, sample, shuffle } from "@/utils/alea";
+import { randInt, shuffle } from "@/utils/alea";
 
 export const PiPo = class PiPo //Piece+Position
 {
@@ -59,7 +59,7 @@ export const ChessRules = class ChessRules
     return (f.charCodeAt()<=90 ? "w"+f.toLowerCase() : "b"+f);
   }
 
-  // Check if FEN describe a position
+  // Check if FEN describe a board situation correctly
   static IsGoodFen(fen)
   {
     const fenParsed = V.ParseFen(fen);
@@ -192,7 +192,7 @@ export const ChessRules = class ChessRules
     // Argument is a move:
     const move = moveOrSquare;
     const [sx,sy,ex] = [move.start.x,move.start.y,move.end.x];
-    // TODO: next conditions are first for Atomic, and last for Checkered
+    // NOTE: next conditions are first for Atomic, and last for Checkered
     if (move.appear.length > 0 && Math.abs(sx - ex) == 2
       && move.appear[0].p == V.PAWN && ["w","b"].includes(move.appear[0].c))
     {
@@ -512,12 +512,6 @@ export const ChessRules = class ChessRules
     return (color=="w" ? "b" : "w");
   }
 
-  // Get next color (for compatibility with 3 and 4 players games)
-  static GetNextCol(color)
-  {
-    return V.GetOppCol(color);
-  }
-
   // Pieces codes (for a clearer code)
   static get PAWN() { return 'p'; }
   static get ROOK() { return 'r'; }
@@ -754,10 +748,11 @@ export const ChessRules = class ChessRules
         continue;
       // If this code is reached, rooks and king are on initial position
 
-      // Nothing on the path of the king ?
-      // (And no checks; OK also if y==finalSquare)
-      let step = finalSquares[castleSide][0] < y ? -1 : 1;
-      for (i=y; i!=finalSquares[castleSide][0]; i+=step)
+      // Nothing on the path of the king ? (and no checks)
+      const finDist = finalSquares[castleSide][0] - y;
+      let step = finDist / Math.max(1, Math.abs(finDist));
+      i = y;
+      do
       {
         if (this.isAttacked([x,i], [oppCol]) || (this.board[x][i] != V.EMPTY &&
           // NOTE: next check is enough, because of chessboard constraints
@@ -766,10 +761,12 @@ export const ChessRules = class ChessRules
         {
           continue castlingCheck;
         }
+        i += step;
       }
+      while (i!=finalSquares[castleSide][0]);
 
       // Nothing on the path to the rook?
-      step = castleSide == 0 ? -1 : 1;
+      step = (castleSide == 0 ? -1 : 1);
       for (i = y + step; i != this.INIT_COL_ROOK[c][castleSide]; i += step)
       {
         if (this.board[x][i] != V.EMPTY)
@@ -1128,7 +1125,6 @@ export const ChessRules = class ChessRules
   // Search depth: 2 for high branching factor, 4 for small (Loser chess, eg.)
   static get SEARCH_DEPTH() { return 3; }
 
-  // Assumption: at least one legal move
   // NOTE: works also for extinction chess because depth is 3...
   getComputerMove()
   {
@@ -1137,6 +1133,8 @@ export const ChessRules = class ChessRules
     // Some variants may show a bigger moves list to the human (Switching),
     // thus the argument "computer" below (which is generally ignored)
     let moves1 = this.getAllValidMoves("computer");
+    if (moves1.length == 0) //TODO: this situation should not happen
+      return null;
 
     // Can I mate in 1 ? (for Magnetic & Extinction)
     for (let i of shuffle(ArrayFun.range(moves1.length)))
@@ -1197,7 +1195,7 @@ export const ChessRules = class ChessRules
     let candidates = [0]; //indices of candidates moves
     for (let j=1; j<moves1.length && moves1[j].eval == moves1[0].eval; j++)
       candidates.push(j);
-    let currentBest = moves1[sample(candidates)];
+    let currentBest = moves1[candidates[randInt(candidates.length)]];
 
     // Skip depth 3+ if we found a checkmate (or if we are checkmated in 1...)
     if (V.SEARCH_DEPTH >= 3 && Math.abs(moves1[0].eval) < V.THRESHOLD_MATE)