Fix parseInt() usage, rename Doubleorda --> Ordamirror, implement Clorange variant
[vchess.git] / client / src / variants / Apocalypse.js
index 031f22c..77d17c0 100644 (file)
@@ -13,6 +13,10 @@ export class ApocalypseRules extends ChessRules {
     );
   }
 
+  static get SomeHiddenMoves() {
+    return true;
+  }
+
   static get HasCastle() {
     return false;
   }
@@ -22,7 +26,7 @@ export class ApocalypseRules extends ChessRules {
   }
 
   static get CanAnalyze() {
-    return true; //false;
+    return false;
   }
 
   static get ShowMoves() {
@@ -51,7 +55,7 @@ export class ApocalypseRules extends ChessRules {
         if (['P','p'].includes(row[i])) pawns[row[i]]++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
@@ -69,12 +73,12 @@ export class ApocalypseRules extends ChessRules {
     // 4) Check whiteMove
     if (
       (
-        fenParsed.turn == "w" &&
+        fenParsed.turn == "b" &&
         // NOTE: do not check really JSON stringified move...
         (!fenParsed.whiteMove || fenParsed.whiteMove == "-")
       )
       ||
-      (fenParsed.turn == "b" && fenParsed.whiteMove != "-")
+      (fenParsed.turn == "w" && fenParsed.whiteMove != "-")
     ) {
       return false;
     }
@@ -135,8 +139,8 @@ export class ApocalypseRules extends ChessRules {
 
   setFlags(fenflags) {
     this.penaltyFlags = {
-      'w': parseInt(fenflags[0]),
-      'b': parseInt(fenflags[1])
+      'w': parseInt(fenflags[0], 10),
+      'b': parseInt(fenflags[1], 10)
     };
   }
 
@@ -146,8 +150,7 @@ export class ApocalypseRules extends ChessRules {
       start: this.whiteMove.start,
       end: this.whiteMove.end,
       appear: this.whiteMove.appear,
-      vanish: this.whiteMove.vanish,
-      illegal: this.whiteMove.illegal
+      vanish: this.whiteMove.vanish
     });
   }
 
@@ -177,7 +180,7 @@ export class ApocalypseRules extends ChessRules {
         const mHash = "m" + vm.start.x + vm.start.y + vm.end.x + vm.end.y;
         if (!moveSet[mHash]) {
           moveSet[mHash] = true;
-          vm.illegal = true; //potentially illegal!
+          vm.end.illegal = true; //potentially illegal!
           speculations.push(vm);
         }
       });
@@ -274,40 +277,55 @@ export class ApocalypseRules extends ChessRules {
       return (
         (
           m.vanish[0].p == V.KNIGHT &&
-          (m.vanish.length == 1 || m.vanish[1].c != m.vanish[0].c)
-        )
-        ||
-        (
-          // Promotion attempt
-          m.end.x == (m.vanish[0].c == "w" ? 0 : V.size.x - 1) &&
-          other.vanish.length == 2 &&
-          other.vanish[1].p == V.KNIGHT &&
-          other.vanish[1].c == m.vanish[0].c
-        )
-        ||
-        (
-          // Moving attempt
-          !movingLikeCapture(m) &&
-          other.start.x == m.end.x &&
-          other.start.y == m.end.y
+          (
+            m.vanish.length == 1 ||
+            m.vanish[1].c != m.vanish[0].c ||
+            // Self-capture attempt
+            (
+              !other.end.illegal &&
+              other.end.x == m.end.x &&
+              other.end.y == m.end.y
+            )
+          )
         )
         ||
         (
-          // Capture attempt
-          movingLikeCapture(m) &&
-          other.end.x == m.end.x &&
-          other.end.y == m.end.y
+          m.vanish[0].p == V.PAWN &&
+          !other.end.illegal &&
+          (
+            (
+              // Promotion attempt
+              m.end.x == (m.vanish[0].c == "w" ? 0 : V.size.x - 1) &&
+              other.vanish.length == 2 &&
+              other.vanish[1].p == V.KNIGHT &&
+              other.vanish[1].c == m.vanish[0].c
+            )
+            ||
+            (
+              // Moving attempt
+              !movingLikeCapture(m) &&
+              other.start.x == m.end.x &&
+              other.start.y == m.end.y
+            )
+            ||
+            (
+              // Capture attempt
+              movingLikeCapture(m) &&
+              other.end.x == m.end.x &&
+              other.end.y == m.end.y
+            )
+          )
         )
       );
     };
-    if (!!m1.illegal && !isPossible(m1, m2)) {
+    if (!!m1.end.illegal && !isPossible(m1, m2)) {
       // Either an anticipated capture of something which didn't move
       // (or not to the right square), or a push through blocus.
       // ==> Just discard the move, and add a penalty point
       this.penaltyFlags[m1.vanish[0].c]++;
       m1.isNull = true;
     }
-    if (!!m2.illegal && !isPossible(m2, m1)) {
+    if (!!m2.end.illegal && !isPossible(m2, m1)) {
       this.penaltyFlags[m2.vanish[0].c]++;
       m2.isNull = true;
     }
@@ -322,7 +340,7 @@ export class ApocalypseRules extends ChessRules {
       vanish: []
     };
     if (!m1 && !m2) return smove;
-    // Both move are now legal:
+    // Both moves are now legal or at least possible:
     smove.vanish.push(m1.vanish[0]);
     smove.vanish.push(m2.vanish[0]);
     if ((m1.end.x != m2.end.x) || (m1.end.y != m2.end.y)) {
@@ -356,8 +374,8 @@ export class ApocalypseRules extends ChessRules {
       let remain = null;
       const p1 = m1.vanish[0].p;
       const p2 = m2.vanish[0].p;
-      if (!!m1.illegal && !m2.illegal) remain = { c: 'w', p: p1 };
-      else if (!!m2.illegal && !m1.illegal) remain = { c: 'b', p: p2 };
+      if (!!m1.end.illegal && !m2.end.illegal) remain = { c: 'w', p: p1 };
+      else if (!!m2.end.illegal && !m1.end.illegal) remain = { c: 'b', p: p2 };
       if (!remain) {
         // Either both are illegal or both are legal
         if (p1 == V.KNIGHT && p2 == V.PAWN) remain = { c: 'w', p: p1 };
@@ -377,10 +395,6 @@ export class ApocalypseRules extends ChessRules {
   }
 
   play(move) {
-    if (!this.states) this.states = [];
-    const stateFen = this.getFen();
-    this.states.push(stateFen);
-
     // Do not play on board (would reveal the move...)
     move.flags = JSON.stringify(this.aggregateFlags());
     this.turn = V.GetOppCol(this.turn);
@@ -410,10 +424,6 @@ export class ApocalypseRules extends ChessRules {
     this.turn = V.GetOppCol(this.turn);
     this.movesCount--;
     this.postUndo(move);
-
-    const stateFen = this.getFen();
-    if (stateFen != this.states[this.states.length-1]) debugger;
-    this.states.pop();
   }
 
   postUndo(move) {
@@ -421,7 +431,7 @@ export class ApocalypseRules extends ChessRules {
     else this.whiteMove = move.whiteMove;
   }
 
-  getCheckSquares(color) {
+  getCheckSquares() {
     return [];
   }
 
@@ -462,30 +472,42 @@ export class ApocalypseRules extends ChessRules {
       // TODO: this situation should not happen
       return null;
 
-    if (Math.random() < 0.5)
-      // Return a random move
-      return moves[randInt(moves.length)];
-
     // Rank moves at depth 1:
-    // try to capture something (not re-capturing)
+    let validMoves = [];
+    let illegalMoves = [];
     moves.forEach(m => {
-      V.PlayOnBoard(this.board, m);
-      m.eval = this.evalPosition();
-      V.UndoOnBoard(this.board, m);
+      // Warning: m might be illegal!
+      if (!m.end.illegal) {
+        V.PlayOnBoard(this.board, m);
+        m.eval = this.evalPosition();
+        V.UndoOnBoard(this.board, m);
+        validMoves.push(m);
+      } else illegalMoves.push(m);
     });
-    moves.sort((a, b) => {
+
+    const illegalRatio = illegalMoves.length / moves.length;
+    if (Math.random() < illegalRatio)
+      // Return a random illegal move
+      return illegalMoves[randInt(illegalMoves.length)];
+
+    validMoves.sort((a, b) => {
       return (color == "w" ? 1 : -1) * (b.eval - a.eval);
     });
     let candidates = [0];
-    for (let i = 1; i < moves.length && moves[i].eval == moves[0].eval; i++)
+    for (
+      let i = 1;
+      i < validMoves.length && validMoves[i].eval == moves[0].eval;
+      i++
+    ) {
       candidates.push(i);
-    return moves[candidates[randInt(candidates.length)]];
+    }
+    return validMoves[candidates[randInt(candidates.length)]];
   }
 
   getNotation(move) {
     // Basic system: piece + init + dest square
     return (
-      move.vanish[0].p.toUpperCase() +
+      (move.vanish[0].p == V.KNIGHT ? "N" : "") +
       V.CoordsToSquare(move.start) +
       V.CoordsToSquare(move.end)
     );