Fix Koopa variant: always allow castlin with a non-stunned rook
[vchess.git] / client / src / base_rules.js
index e70b9de..acf6eff 100644 (file)
@@ -158,7 +158,7 @@ export const ChessRules = class ChessRules {
     // 2) Check turn
     if (!fenParsed.turn || !V.IsGoodTurn(fenParsed.turn)) return false;
     // 3) Check moves count
-    if (!fenParsed.movesCount || !(parseInt(fenParsed.movesCount) >= 0))
+    if (!fenParsed.movesCount || !(parseInt(fenParsed.movesCount, 10) >= 0))
       return false;
     // 4) Check flags
     if (V.HasFlags && (!fenParsed.flags || !V.IsGoodFlags(fenParsed.flags)))
@@ -185,7 +185,7 @@ export const ChessRules = class ChessRules {
         if (['K','k'].includes(row[i])) kings[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;
         }
@@ -232,7 +232,7 @@ export const ChessRules = class ChessRules {
     return {
       // NOTE: column is always one char => max 26 columns
       // row is counted from black side => subtraction
-      x: V.size.x - parseInt(sq.substr(1)),
+      x: V.size.x - parseInt(sq.substr(1), 10),
       y: sq[0].charCodeAt() - 97
     };
   }
@@ -480,7 +480,7 @@ export const ChessRules = class ChessRules {
       let j = 0;
       for (let indexInRow = 0; indexInRow < rows[i].length; indexInRow++) {
         const character = rows[i][indexInRow];
-        const num = parseInt(character);
+        const num = parseInt(character, 10);
         // If num is a number, just shift j:
         if (!isNaN(num)) j += num;
         // Else: something at position i,j
@@ -512,7 +512,7 @@ export const ChessRules = class ChessRules {
     const fenParsed = V.ParseFen(fen);
     this.board = V.GetBoard(fenParsed.position);
     this.turn = fenParsed.turn;
-    this.movesCount = parseInt(fenParsed.movesCount);
+    this.movesCount = parseInt(fenParsed.movesCount, 10);
     this.setOtherVariables(fen);
   }
 
@@ -536,7 +536,7 @@ export const ChessRules = class ChessRules {
             this.INIT_COL_KING["w"] = k;
             break;
           default: {
-            const num = parseInt(fenRows[i].charAt(j));
+            const num = parseInt(fenRows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
@@ -766,6 +766,7 @@ export const ChessRules = class ChessRules {
     const [sizeX, sizeY] = [V.size.x, V.size.y];
     const pawnShiftX = V.PawnSpecs.directions[color];
     const firstRank = (color == "w" ? sizeX - 1 : 0);
+    const forward = (color == 'w' ? -1 : 1);
 
     // Pawn movements in shiftX direction:
     const getPawnMoves = (shiftX) => {
@@ -773,7 +774,7 @@ export const ChessRules = class ChessRules {
       // NOTE: next condition is generally true (no pawn on last rank)
       if (x + shiftX >= 0 && x + shiftX < sizeX) {
         if (this.board[x + shiftX][y] == V.EMPTY) {
-          // One square forward
+          // One square forward (or backward)
           this.addPawnMoves([x, y], [x + shiftX, y], moves, promotions);
           // Next condition because pawns on 1st rank can generally jump
           if (
@@ -784,7 +785,10 @@ export const ChessRules = class ChessRules {
               (color == 'b' && x <= V.PawnSpecs.initShift['b'])
             )
           ) {
-            if (this.board[x + 2 * shiftX][y] == V.EMPTY) {
+            if (
+              shiftX == forward &&
+              this.board[x + 2 * shiftX][y] == V.EMPTY
+            ) {
               // Two squares jump
               moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
               if (
@@ -811,13 +815,13 @@ export const ChessRules = class ChessRules {
                 );
               }
               if (
-                V.PawnSpecs.captureBackward &&
+                V.PawnSpecs.captureBackward && shiftX == forward &&
                 x - shiftX >= 0 && x - shiftX < V.size.x &&
                 this.board[x - shiftX][y + shiftY] != V.EMPTY &&
                 this.canTake([x, y], [x - shiftX, y + shiftY])
               ) {
                 this.addPawnMoves(
-                  [x, y], [x + shiftX, y + shiftY],
+                  [x, y], [x - shiftX, y + shiftY],
                   moves, promotions
                 );
               }
@@ -880,7 +884,7 @@ export const ChessRules = class ChessRules {
   }
 
   // "castleInCheck" arg to let some variants castle under check
-  getCastleMoves([x, y], castleInCheck) {
+  getCastleMoves([x, y], castleInCheck, castleWith) {
     const c = this.getColor(x, y);
     if (x != (c == "w" ? V.size.x - 1 : 0) || y != this.INIT_COL_KING[c])
       return []; //x isn't first rank, or king has moved (shortcut)
@@ -904,9 +908,14 @@ export const ChessRules = class ChessRules {
 
       // NOTE: in some variants this is not a rook
       const rookPos = this.castleFlags[c][castleSide];
-      if (this.board[x][rookPos] == V.EMPTY || this.getColor(x, rookPos) != c)
+      if (
+        this.board[x][rookPos] == V.EMPTY ||
+        this.getColor(x, rookPos) != c ||
+        (!!castleWith && !castleWith.includes(this.getPiece(x, rookPos)))
+      ) {
         // Rook is not here, or changed color (see Benedict)
         continue;
+      }
 
       // Nothing on the path of the king ? (and no checks)
       const castlingPiece = this.getPiece(x, rookPos);
@@ -1165,8 +1174,8 @@ export const ChessRules = class ChessRules {
     this.postPlay(move);
   }
 
-  updateCastleFlags(move, piece) {
-    const c = V.GetOppCol(this.turn);
+  updateCastleFlags(move, piece, color) {
+    const c = color || V.GetOppCol(this.turn);
     const firstRank = (c == "w" ? V.size.x - 1 : 0);
     // Update castling flags if rooks are moved
     const oppCol = this.turn;