Fix Progressive2. Fixing attempt on Doublemove1
[vchess.git] / client / src / variants / Doublemove1.js
index 7d1ee4d..95d94d7 100644 (file)
@@ -1,5 +1,4 @@
 import { ChessRules } from "@/base_rules";
-import { randInt } from "@/utils/alea";
 
 export class Doublemove1Rules extends ChessRules {
   static IsGoodEnpassant(enpassant) {
@@ -77,29 +76,65 @@ export class Doublemove1Rules extends ChessRules {
     return moves;
   }
 
+  atLeastOneMove() {
+    const color = this.turn;
+    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 && this.getColor(i, j) == color) {
+          const moves = this.getPotentialMovesFrom([i, j]);
+          if (moves.length > 0) {
+            for (let k = 0; k < moves.length; k++) {
+              const m = moves[k];
+              // NOTE: not using play() here (=> infinite loop)
+              V.PlayOnBoard(this.board, m);
+              if (m.vanish[0].p == V.KING)
+                this.kingPos[color] = [m.appear[0].x, m.appear[0].y];
+              const res = !this.underCheck(color);
+              V.UndoOnBoard(this.board, m);
+              if (m.vanish[0].p == V.KING)
+                this.kingPos[color] = [m.start.x, m.start.y];
+              if (res) return true;
+            }
+          }
+        }
+      }
+    }
+    return false;
+  }
+
   play(move) {
     move.flags = JSON.stringify(this.aggregateFlags());
-    move.turn = this.turn + this.subTurn;
+    move.turn = [this.turn, this.subTurn];
     V.PlayOnBoard(this.board, move);
     const epSq = this.getEpSquare(move);
+    const oppCol = V.GetOppCol(this.turn);
     if (this.movesCount == 0) {
       // First move in game
       this.turn = "b";
       this.epSquares.push([epSq]);
       this.movesCount = 1;
     }
-    // Does this move give check on subturn 1? If yes, skip subturn 2
-    else if (this.subTurn == 1 && this.underCheck(V.GetOppCol(this.turn))) {
-      this.turn = V.GetOppCol(this.turn);
+    // Does this move give check on subturn 1 or reach stalemate?
+    // If yes, skip subturn 2
+    else if (
+      this.subTurn == 1 &&
+      (
+        this.underCheck(V.GetOppCol(this.turn)) ||
+        !this.atLeastOneMove()
+      )
+    ) {
+      this.turn = oppCol;
       this.epSquares.push([epSq]);
       move.checkOnSubturn1 = true;
       this.movesCount++;
-    } else {
+    }
+    else {
       if (this.subTurn == 2) {
-        this.turn = V.GetOppCol(this.turn);
+        this.turn = oppCol;
         let lastEpsq = this.epSquares[this.epSquares.length - 1];
         lastEpsq.push(epSq);
-      } else {
+      }
+      else {
         this.epSquares.push([epSq]);
         this.movesCount++;
       }
@@ -109,13 +144,12 @@ export class Doublemove1Rules extends ChessRules {
   }
 
   postPlay(move) {
-    const c = move.turn.charAt(0);
+    const c = move.turn[0];
     const piece = move.vanish[0].p;
     const firstRank = c == "w" ? V.size.x - 1 : 0;
 
-    if (piece == V.KING && move.appear.length > 0) {
-      this.kingPos[c][0] = move.appear[0].x;
-      this.kingPos[c][1] = move.appear[0].y;
+    if (piece == V.KING) {
+      this.kingPos[c] = [move.appear[0].x, move.appear[0].y];
       this.castleFlags[c] = [V.size.y, V.size.y];
       return;
     }
@@ -127,7 +161,8 @@ export class Doublemove1Rules extends ChessRules {
     ) {
       const flagIdx = (move.start.y == this.castleFlags[c][0] ? 0 : 1);
       this.castleFlags[c][flagIdx] = V.size.y;
-    } else if (
+    }
+    if (
       move.end.x == oppFirstRank && //we took opponent rook?
       this.castleFlags[oppCol].includes(move.end.y)
     ) {
@@ -144,13 +179,14 @@ export class Doublemove1Rules extends ChessRules {
       this.epSquares.pop();
       // Moves counter was just incremented:
       this.movesCount--;
-    } else {
+    }
+    else {
       // Undo the second half of a move
       let lastEpsq = this.epSquares[this.epSquares.length - 1];
       lastEpsq.pop();
     }
     this.turn = move.turn[0];
-    this.subTurn = parseInt(move.turn[1]);
+    this.subTurn = move.turn[1];
     super.postUndo(move);
   }
 
@@ -201,42 +237,40 @@ export class Doublemove1Rules extends ChessRules {
       return res;
     };
 
-    let moves11 = this.getAllValidMoves();
-    let doubleMoves = [];
+    const moves11 = this.getAllValidMoves();
+    let doubleMove = null;
+    let bestEval = Number.POSITIVE_INFINITY * (color == 'w' ? -1 : 1);
     // Rank moves using a min-max at depth 2
     for (let i = 0; i < moves11.length; i++) {
       this.play(moves11[i]);
       if (this.turn != color) {
         // We gave check with last move: search the best opponent move
-        doubleMoves.push({ moves: [moves11[i]], eval: getBestMoveEval() });
-      } else {
+        const evalM = getBestMoveEval() + 0.05 - Math.random() / 10;
+        if (
+          (color == 'w' && evalM > bestEval) ||
+          (color == 'b' && evalM < bestEval)
+        ) {
+          doubleMove = moves11[i];
+          bestEval = evalM;
+        }
+      }
+      else {
         let moves12 = this.getAllValidMoves();
         for (let j = 0; j < moves12.length; j++) {
           this.play(moves12[j]);
-          doubleMoves.push({
-            moves: [moves11[i], moves12[j]],
-            eval: getBestMoveEval()
-          });
+          const evalM  = getBestMoveEval() + 0.05 - Math.random() / 10
+          if (
+            (color == 'w' && evalM > bestEval) ||
+            (color == 'b' && evalM < bestEval)
+          ) {
+            doubleMove = [moves11[i], moves12[j]];
+            bestEval = evalM;
+          }
           this.undo(moves12[j]);
         }
       }
       this.undo(moves11[i]);
     }
-
-    doubleMoves.sort((a, b) => {
-      return (color == "w" ? 1 : -1) * (b.eval - a.eval);
-    });
-    let candidates = [0]; //indices of candidates moves
-    for (
-      let i = 1;
-      i < doubleMoves.length && doubleMoves[i].eval == doubleMoves[0].eval;
-      i++
-    ) {
-      candidates.push(i);
-    }
-
-    const selected = doubleMoves[randInt(candidates.length)].moves;
-    if (selected.length == 1) return selected[0];
-    return selected;
+    return doubleMove;
   }
 };