Draft Hiddenqueen, Grasshopper and Knightmate chess (rules unwritten)
[vchess.git] / client / src / variants / Enpassant.js
index 50f9738..3f8f3b2 100644 (file)
@@ -67,6 +67,52 @@ export const VariantRules = class EnpassantRules extends ChessRules {
     return res.slice(0, -1); //remove last comma
   }
 
+  getPotentialMovesFrom([x, y]) {
+    let moves = super.getPotentialMovesFrom([x,y]);
+    // Add en-passant captures from this square:
+    const L = this.epSquares.length;
+    if (!this.epSquares[L - 1]) return moves;
+    const squares = this.epSquares[L - 1];
+    const S = squares.length;
+    // Object describing the removed opponent's piece:
+    const pipoV = new PiPo({
+      x: squares[S-1].x,
+      y: squares[S-1].y,
+      c: V.GetOppCol(this.turn),
+      p: this.getPiece(squares[S-1].x, squares[S-1].y)
+    });
+    // Check if existing non-capturing moves could also capture en passant
+    moves.forEach(m => {
+      if (
+        m.appear[0].p != V.PAWN && //special pawn case is handled elsewhere
+        m.vanish.length <= 1 &&
+        [...Array(S-1).keys()].some(i => {
+          return m.end.x == squares[i].x && m.end.y == squares[i].y;
+        })
+      ) {
+        m.vanish.push(pipoV);
+      }
+    });
+    // Special case of the king knight's movement:
+    if (this.getPiece(x, y) == V.KING) {
+      V.steps[V.KNIGHT].forEach(step => {
+        const endX = x + step[0];
+        const endY = y + step[1];
+        if (
+          V.OnBoard(endX, endY) &&
+          [...Array(S-1).keys()].some(i => {
+            return endX == squares[i].x && endY == squares[i].y;
+          })
+        ) {
+          let enpassantMove = this.getBasicMove([x, y], [endX, endY]);
+          enpassantMove.vanish.push(pipoV);
+          moves.push(enpassantMove);
+        }
+      });
+    }
+    return moves;
+  }
+
   // TODO: this getPotentialPawnMovesFrom() is mostly duplicated:
   // it could be split in "capture", "promotion", "enpassant"...
   getPotentialPawnMoves([x, y]) {
@@ -74,53 +120,47 @@ export const VariantRules = class EnpassantRules extends ChessRules {
     let moves = [];
     const [sizeX, sizeY] = [V.size.x, V.size.y];
     const shiftX = color == "w" ? -1 : 1;
-    const firstRank = color == "w" ? sizeX - 1 : 0;
     const startRank = color == "w" ? sizeX - 2 : 1;
     const lastRank = color == "w" ? 0 : sizeX - 1;
-    const pawnColor = this.getColor(x, y); //can be different for checkered
 
-    // NOTE: next condition is generally true (no pawn on last rank)
-    if (x + shiftX >= 0 && x + shiftX < sizeX) {
-      const finalPieces =
-        x + shiftX == lastRank
-          ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]
-          : [V.PAWN];
-      // One square forward
-      if (this.board[x + shiftX][y] == V.EMPTY) {
+    const finalPieces =
+      x + shiftX == lastRank
+        ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]
+        : [V.PAWN];
+    // One square forward
+    if (this.board[x + shiftX][y] == V.EMPTY) {
+      for (let piece of finalPieces) {
+        moves.push(
+          this.getBasicMove([x, y], [x + shiftX, y], {
+            c: color,
+            p: piece
+          })
+        );
+      }
+      if (
+        x == startRank &&
+        this.board[x + 2 * shiftX][y] == V.EMPTY
+      ) {
+        // Two squares jump
+        moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
+      }
+    }
+    // Captures
+    for (let shiftY of [-1, 1]) {
+      if (
+        y + shiftY >= 0 &&
+        y + shiftY < sizeY &&
+        this.board[x + shiftX][y + shiftY] != V.EMPTY &&
+        this.canTake([x, y], [x + shiftX, y + shiftY])
+      ) {
         for (let piece of finalPieces) {
           moves.push(
-            this.getBasicMove([x, y], [x + shiftX, y], {
-              c: pawnColor,
+            this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
+              c: color,
               p: piece
             })
           );
         }
-        // Next condition because pawns on 1st rank can generally jump
-        if (
-          [startRank, firstRank].includes(x) &&
-          this.board[x + 2 * shiftX][y] == V.EMPTY
-        ) {
-          // Two squares jump
-          moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
-        }
-      }
-      // Captures
-      for (let shiftY of [-1, 1]) {
-        if (
-          y + shiftY >= 0 &&
-          y + shiftY < sizeY &&
-          this.board[x + shiftX][y + shiftY] != V.EMPTY &&
-          this.canTake([x, y], [x + shiftX, y + shiftY])
-        ) {
-          for (let piece of finalPieces) {
-            moves.push(
-              this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
-                c: pawnColor,
-                p: piece
-              })
-            );
-          }
-        }
       }
     }
 
@@ -150,11 +190,19 @@ export const VariantRules = class EnpassantRules extends ChessRules {
   }
 
   // Remove the "onestep" condition: knight promote to knightrider:
-
   getPotentialKnightMoves(sq) {
     return this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT]);
   }
 
+  filterValid(moves) {
+    const filteredMoves = super.filterValid(moves);
+    // If at least one full move made, everything is allowed:
+    if (this.movesCount >= 2)
+      return filteredMoves;
+    // Else, forbid captures:
+    return filteredMoves.filter(m => m.vanish.length == 1);
+  }
+
   isAttackedByKnight(sq, colors) {
     return this.isAttackedBySlideNJump(
       sq,
@@ -164,52 +212,6 @@ export const VariantRules = class EnpassantRules extends ChessRules {
     );
   }
 
-  getPotentialMovesFrom([x, y]) {
-    let moves = super.getPotentialMovesFrom([x,y]);
-    // Add en-passant captures from this square:
-    const L = this.epSquares.length;
-    if (!this.epSquares[L - 1]) return moves;
-    const squares = this.epSquares[L - 1];
-    const S = squares.length;
-    // Object describing the removed opponent's piece:
-    const pipoV = new PiPo({
-      x: squares[S-1].x,
-      y: squares[S-1].y,
-      c: V.GetOppCol(this.turn),
-      p: this.getPiece(squares[S-1].x, squares[S-1].y)
-    });
-    // Check if existing non-capturing moves could also capture en passant
-    moves.forEach(m => {
-      if (
-        m.appear[0].p != V.PAWN && //special pawn case is handled elsewhere
-        m.vanish.length <= 1 &&
-        [...Array(S-1).keys()].some(i => {
-          return m.end.x == squares[i].x && m.end.y == squares[i].y;
-        })
-      ) {
-        m.vanish.push(pipoV);
-      }
-    });
-    // Special case of the king knight's movement:
-    if (this.getPiece(x, y) == V.KING) {
-      V.steps[V.KNIGHT].forEach(step => {
-        const endX = x + step[0];
-        const endY = y + step[1];
-        if (
-          V.OnBoard(endX, endY) &&
-          [...Array(S-1).keys()].some(i => {
-            return endX == squares[i].x && endY == squares[i].y;
-          })
-        ) {
-          let enpassantMove = this.getBasicMove([x, y], [endX, endY]);
-          enpassantMove.vanish.push(pipoV);
-          moves.push(enpassantMove);
-        }
-      });
-    }
-    return moves;
-  }
-
   static get VALUES() {
     return {
       p: 1,