Several small improvements + integrate options + first working draft of Cwda
[vchess.git] / client / src / variants / Pocketknight.js
index 6aa94aa..ad17f93 100644 (file)
@@ -2,7 +2,8 @@ import { ChessRules, Move, PiPo } from "@/base_rules";
 import { randInt } from "@/utils/alea";
 
 export class PocketknightRules extends ChessRules {
-  hoverHighlight(x, y) {
+
+  hoverHighlight([x, y]) {
     // Testing move validity results in an infinite update loop.
     // TODO: find a way to test validity anyway.
     return (this.subTurn == 2 && this.board[x][y] == V.EMPTY);
@@ -32,10 +33,9 @@ export class PocketknightRules extends ChessRules {
     this.subTurn = 1;
   }
 
-  static GenRandInitFen(randomness) {
+  static GenRandInitFen(options) {
     // Add 2 knight flags
-    return ChessRules.GenRandInitFen(randomness)
-      .slice(0, -2) + "11 -";
+    return ChessRules.GenRandInitFen(options).slice(0, -2) + "11 -";
   }
 
   getFlagsFen() {
@@ -44,6 +44,12 @@ export class PocketknightRules extends ChessRules {
     );
   }
 
+  canIplay(side, [x, y]) {
+    if (this.subTurn == 1) return super.canIplay(side, [x, y]);
+    // subturn == 2, drop the knight:
+    return side == this.turn && this.board[x][y] == V.EMPTY;
+  }
+
   getPotentialMovesFrom([x, y]) {
     if (this.subTurn == 1) {
       let moves = super.getPotentialMovesFrom([x, y]);
@@ -199,10 +205,32 @@ export class PocketknightRules extends ChessRules {
   getComputerMove() {
     let moves = this.getAllValidMoves();
     if (moves.length == 0) return null;
-    // Custom "search" at depth 1 (for now. TODO?)
     const maxeval = V.INFINITY;
     const color = this.turn;
-    const initEval = this.evalPosition();
+    const oppCol = V.GetOppCol(color);
+    const getOppEval = () => {
+      let evalOpp = this.evalPosition();
+      this.getAllValidMoves().forEach(m => {
+        // Do not consider knight landings here
+        if (m.appear.length > 0) {
+          this.play(m);
+          const score = this.getCurrentScore();
+          let mvEval = 0;
+          if (["1-0", "0-1"].includes(score))
+            mvEval = (score == "1-0" ? 1 : -1) * maxeval;
+          else if (score == "*") mvEval = this.evalPosition();
+          if (
+            (oppCol == 'w' && mvEval > evalOpp) ||
+            (oppCol == 'b' && mvEval < evalOpp)
+          ) {
+            evalOpp = mvEval;
+          }
+          this.undo(m);
+        }
+      });
+      return evalOpp;
+    };
+    // Custom "search" at depth 2
     moves.forEach(m => {
       this.play(m);
       m.eval = (color == "w" ? -1 : 1) * maxeval;
@@ -217,8 +245,8 @@ export class PocketknightRules extends ChessRules {
             mvEval = (score == "1-0" ? 1 : -1) * maxeval;
           else if (score == "*")
             // Add small fluctuations to avoid dropping pieces always on the
-            // first square available.
-            mvEval = initEval + 0.05 - Math.random() / 10;
+            // first available square.
+            mvEval = getOppEval() + 0.05 - Math.random() / 10;
           if (
             (color == 'w' && mvEval > m.eval) ||
             (color == 'b' && mvEval < m.eval)
@@ -233,7 +261,7 @@ export class PocketknightRules extends ChessRules {
         const score = this.getCurrentScore();
         if (score != "1/2") {
           if (score != "*") m.eval = (score == "1-0" ? 1 : -1) * maxeval;
-          else m.eval = this.evalPosition();
+          else m.eval = getOppEval();
         }
       }
       this.undo(m);
@@ -260,4 +288,5 @@ export class PocketknightRules extends ChessRules {
     // Knight landing:
     return "N@" + V.CoordsToSquare(move.end);
   }
+
 };