Started code review + some fixes (unfinished)
[vchess.git] / client / src / variants / Dark.js
index c0bfb09..358362c 100644 (file)
@@ -1,52 +1,45 @@
 import { ChessRules } from "@/base_rules";
-import { ArrayFun} from "@/utils/array";
+import { ArrayFun } from "@/utils/array";
 import { randInt } from "@/utils/alea";
 
-export const VariantRules = class DarkRules extends ChessRules
-{
+export const VariantRules = class DarkRules extends ChessRules {
   // Standard rules, in the shadow
-  setOtherVariables(fen)
-  {
+  setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const [sizeX,sizeY] = [V.size.x,V.size.y];
+    const [sizeX, sizeY] = [V.size.x, V.size.y];
     this.enlightened = {
-      "w": ArrayFun.init(sizeX,sizeY),
-      "b": ArrayFun.init(sizeX,sizeY)
+      w: ArrayFun.init(sizeX, sizeY),
+      b: ArrayFun.init(sizeX, sizeY)
     };
     // Setup enlightened: squares reachable by each side
     // (TODO: one side would be enough ?)
     this.updateEnlightened();
   }
 
-  updateEnlightened()
-  {
-    for (let i=0; i<V.size.x; i++)
-    {
-      for (let j=0; j<V.size.y; j++)
-      {
+  updateEnlightened() {
+    for (let i = 0; i < V.size.x; i++) {
+      for (let j = 0; j < V.size.y; j++) {
         this.enlightened["w"][i][j] = false;
         this.enlightened["b"][i][j] = false;
       }
     }
-    const pawnShift = {"w":-1, "b":1};
+    const pawnShift = { w: -1, b: 1 };
     // Initialize with pieces positions (which are seen)
-    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)
-        {
-          const color = this.getColor(i,j);
+    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) {
+          const color = this.getColor(i, j);
           this.enlightened[color][i][j] = true;
           // Add potential squares visible by "impossible pawn capture"
-          if (this.getPiece(i,j) == V.PAWN)
-          {
-            for (let shiftY of [-1,1])
-            {
-              if (V.OnBoard(i+pawnShift[color],j+shiftY)
-                && this.board[i+pawnShift[color]][j+shiftY] == V.EMPTY)
-              {
-                this.enlightened[color][i+pawnShift[color]][j+shiftY] = true;
+          if (this.getPiece(i, j) == V.PAWN) {
+            for (let shiftY of [-1, 1]) {
+              if (
+                V.OnBoard(i + pawnShift[color], j + shiftY) &&
+                this.board[i + pawnShift[color]][j + shiftY] == V.EMPTY
+              ) {
+                this.enlightened[color][i + pawnShift[color]][
+                  j + shiftY
+                ] = true;
               }
             }
           }
@@ -66,64 +59,53 @@ export const VariantRules = class DarkRules extends ChessRules
   }
 
   // Has to be redefined to avoid an infinite loop
-  getAllValidMoves()
-  {
+  getAllValidMoves() {
     const color = this.turn;
-    const oppCol = V.GetOppCol(color);
     let potentialMoves = [];
-    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)
-          Array.prototype.push.apply(potentialMoves, this.getPotentialMovesFrom([i,j]));
+    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)
+          Array.prototype.push.apply(
+            potentialMoves,
+            this.getPotentialMovesFrom([i, j])
+          );
       }
     }
     return potentialMoves; //because there are no checks
   }
 
-  atLeastOneMove()
-  {
-    if (this.kingPos[this.turn][0] < 0)
-      return false;
+  atLeastOneMove() {
+    if (this.kingPos[this.turn][0] < 0) return false;
     return true; //TODO: is it right?
   }
 
-  underCheck(color)
-  {
+  underCheck() {
     return false; //there is no check
   }
 
-  getCheckSquares(color)
-  {
+  getCheckSquares() {
     return [];
   }
 
-  updateVariables(move)
-  {
+  updateVariables(move) {
     super.updateVariables(move);
-    if (move.vanish.length >= 2 && move.vanish[1].p == V.KING)
-    {
+    if (move.vanish.length >= 2 && move.vanish[1].p == V.KING) {
       // We took opponent king ! (because if castle vanish[1] is a rook)
-      this.kingPos[this.turn] = [-1,-1];
+      this.kingPos[this.turn] = [-1, -1];
     }
 
     // Update lights for both colors:
     this.updateEnlightened();
   }
 
-  unupdateVariables(move)
-  {
+  unupdateVariables(move) {
     super.unupdateVariables(move);
     const c = move.vanish[0].c;
     const oppCol = V.GetOppCol(c);
-    if (this.kingPos[oppCol][0] < 0)
-    {
+    if (this.kingPos[oppCol][0] < 0) {
       // Last move took opponent's king
-      for (let psq of move.vanish)
-      {
-        if (psq.p == 'k')
-        {
+      for (let psq of move.vanish) {
+        if (psq.p == "k") {
           this.kingPos[oppCol] = [psq.x, psq.y];
           break;
         }
@@ -134,96 +116,85 @@ export const VariantRules = class DarkRules extends ChessRules
     this.updateEnlightened();
   }
 
-  getCurrentScore()
-  {
+  getCurrentScore() {
     const color = this.turn;
     const kp = this.kingPos[color];
-    if (kp[0] < 0) //king disappeared
-      return (color == "w" ? "0-1" : "1-0");
-    if (this.atLeastOneMove()) // game not over
+    if (kp[0] < 0)
+      //king disappeared
+      return color == "w" ? "0-1" : "1-0";
+    if (this.atLeastOneMove())
+      // game not over
       return "*";
     return "1/2"; //no moves but kings still there (seems impossible)
   }
 
-  static get THRESHOLD_MATE()
-  {
+  static get THRESHOLD_MATE() {
     return 500; //checkmates evals may be slightly below 1000
   }
 
   // In this special situation, we just look 1 half move ahead
-  getComputerMove()
-  {
+  getComputerMove() {
     const maxeval = V.INFINITY;
     const color = this.turn;
     const oppCol = V.GetOppCol(color);
-    const pawnShift = (color == "w" ? -1 : 1);
+    const pawnShift = color == "w" ? -1 : 1;
 
     // Do not cheat: the current enlightment is all we can see
     const myLight = JSON.parse(JSON.stringify(this.enlightened[color]));
 
     // Can a slider on (i,j) apparently take my king?
     // NOTE: inaccurate because assume yes if some squares are shadowed
-    const sliderTake = ([i,j], piece) => {
+    const sliderTake = ([i, j], piece) => {
       const kp = this.kingPos[color];
       let step = undefined;
-      if (piece == V.BISHOP)
-      {
-        if (Math.abs(kp[0] - i) == Math.abs(kp[1] - j))
-        {
-          step =
-          [
-            (i-kp[0]) / Math.abs(i-kp[0]),
-            (j-kp[1]) / Math.abs(j-kp[1])
+      if (piece == V.BISHOP) {
+        if (Math.abs(kp[0] - i) == Math.abs(kp[1] - j)) {
+          step = [
+            (i - kp[0]) / Math.abs(i - kp[0]),
+            (j - kp[1]) / Math.abs(j - kp[1])
           ];
         }
+      } else if (piece == V.ROOK) {
+        if (kp[0] == i) step = [0, (j - kp[1]) / Math.abs(j - kp[1])];
+        else if (kp[1] == j) step = [(i - kp[0]) / Math.abs(i - kp[0]), 0];
       }
-      else if (piece == V.ROOK)
-      {
-        if (kp[0] == i)
-          step = [0, (j-kp[1]) / Math.abs(j-kp[1])];
-        else if (kp[1] == j)
-          step = [(i-kp[0]) / Math.abs(i-kp[0]), 0];
-      }
-      if (!step)
-        return false;
+      if (!step) return false;
       // Check for obstacles
       let obstacle = false;
       for (
-        let x=kp[0]+step[0], y=kp[1]+step[1];
+        let x = kp[0] + step[0], y = kp[1] + step[1];
         x != i && y != j;
-        x += step[0], y += step[1])
-      {
-        if (myLight[x][y] && this.board[x][y] != V.EMPTY)
-        {
+        x += step[0], y += step[1]
+      ) {
+        if (myLight[x][y] && this.board[x][y] != V.EMPTY) {
           obstacle = true;
           break;
         }
       }
-      if (!obstacle)
-        return true;
+      if (!obstacle) return true;
       return false;
     };
 
     // Do I see something which can take my king ?
     const kingThreats = () => {
       const kp = this.kingPos[color];
-      for (let i=0; i<V.size.x; i++)
-      {
-        for (let j=0; j<V.size.y; j++)
-        {
-          if (myLight[i][j] && this.board[i][j] != V.EMPTY
-            && this.getColor(i,j) != color)
-          {
-            switch (this.getPiece(i,j))
-            {
+      for (let i = 0; i < V.size.x; i++) {
+        for (let j = 0; j < V.size.y; j++) {
+          if (
+            myLight[i][j] &&
+            this.board[i][j] != V.EMPTY &&
+            this.getColor(i, j) != color
+          ) {
+            switch (this.getPiece(i, j)) {
               case V.PAWN:
-                if (kp[0] + pawnShift == i && Math.abs(kp[1]-j) == 1)
+                if (kp[0] + pawnShift == i && Math.abs(kp[1] - j) == 1)
                   return true;
                 break;
               case V.KNIGHT:
-                if ((Math.abs(kp[0] - i) == 2 && Math.abs(kp[1] - j) == 1) ||
-                  (Math.abs(kp[0] - i) == 1 && Math.abs(kp[1] - j) == 2))
-                {
+                if (
+                  (Math.abs(kp[0] - i) == 2 && Math.abs(kp[1] - j) == 1) ||
+                  (Math.abs(kp[0] - i) == 1 && Math.abs(kp[1] - j) == 2)
+                ) {
                   return true;
                 }
                 break;
@@ -232,15 +203,13 @@ export const VariantRules = class DarkRules extends ChessRules
                   return true;
                 break;
               case V.BISHOP:
-                if (sliderTake([i,j], V.BISHOP))
-                  return true;
+                if (sliderTake([i, j], V.BISHOP)) return true;
                 break;
               case V.ROOK:
-                if (sliderTake([i,j], V.ROOK))
-                  return true;
+                if (sliderTake([i, j], V.ROOK)) return true;
                 break;
               case V.QUEEN:
-                if (sliderTake([i,j], V.BISHOP) || sliderTake([i,j], V.ROOK))
+                if (sliderTake([i, j], V.BISHOP) || sliderTake([i, j], V.ROOK))
                   return true;
                 break;
             }
@@ -251,37 +220,33 @@ export const VariantRules = class DarkRules extends ChessRules
     };
 
     let moves = this.getAllValidMoves();
-    for (let move of moves)
-    {
+    for (let move of moves) {
       this.play(move);
-      if (this.kingPos[oppCol][0] >= 0 && kingThreats())
-      {
+      if (this.kingPos[oppCol][0] >= 0 && kingThreats()) {
         // We didn't take opponent king, and our king will be captured: bad
         move.eval = -maxeval;
       }
       this.undo(move);
 
-      if (!!move.eval)
-        continue;
+      if (move.eval) continue;
 
       move.eval = 0; //a priori...
 
       // Can I take something ? If yes, do it if it seems good...
-      if (move.vanish.length == 2 && move.vanish[1].c != color) //avoid castle
-      {
+      if (move.vanish.length == 2 && move.vanish[1].c != color) {
+        //avoid castle
         const myPieceVal = V.VALUES[move.appear[0].p];
         const hisPieceVal = V.VALUES[move.vanish[1].p];
-        if (myPieceVal <= hisPieceVal)
-          move.eval = hisPieceVal - myPieceVal + 2; //favor captures
-        else
-        {
+        if (myPieceVal <= hisPieceVal) move.eval = hisPieceVal - myPieceVal + 2;
+        //favor captures
+        else {
           // Taking a pawn with minor piece,
           // or minor piece or pawn with a rook,
           // or anything but a queen with a queen,
           // or anything with a king.
           // ==> Do it at random, although
           //     this is clearly inferior to what a human can deduce...
-          move.eval = (Math.random() < 0.5 ? 1 : -1);
+          move.eval = Math.random() < 0.5 ? 1 : -1;
         }
       }
     }
@@ -289,10 +254,10 @@ export const VariantRules = class DarkRules extends ChessRules
     // TODO: also need to implement the case when an opponent piece (in light)
     // is threatening something - maybe not the king, but e.g. pawn takes rook.
 
-    moves.sort((a,b) => b.eval - a.eval);
+    moves.sort((a, b) => b.eval - a.eval);
     let candidates = [0];
-    for (let j=1; j<moves.length && moves[j].eval == moves[0].eval; j++)
+    for (let j = 1; j < moves.length && moves[j].eval == moves[0].eval; j++)
       candidates.push(j);
     return moves[candidates[randInt(candidates.length)]];
   }
-}
+};