Fix games download/upload + Dynamo variant
[vchess.git] / client / src / variants / Dynamo.js
index 91920e0..5955f64 100644 (file)
@@ -9,7 +9,7 @@ export class DynamoRules extends ChessRules {
 
   canIplay(side, [x, y]) {
     // Sometimes opponent's pieces can be moved directly
-    return true;
+    return this.turn == side;
   }
 
   setOtherVariables(fen) {
@@ -158,7 +158,6 @@ export class DynamoRules extends ChessRules {
   }
 
   // There was something on x2,y2, maybe our color, pushed/pulled.
-  // Also, the pushed/pulled piece must exit the board.
   isAprioriValidExit([x1, y1], [x2, y2], color2) {
     const color1 = this.getColor(x1, y1);
     const pawnShift = (color1 == 'w' ? -1 : 1);
@@ -208,11 +207,28 @@ export class DynamoRules extends ChessRules {
     return false;
   }
 
+  isAprioriValidVertical([x1, y1], x2) {
+    const piece = this.getPiece(x1, y1);
+    const deltaX = Math.abs(x1 - x2);
+    const startRank = (this.getColor(x1, y1) == 'w' ? 6 : 1);
+    return (
+      [V.QUEEN, V.ROOK].includes(piece) ||
+      (
+        [V.KING, V.PAWN].includes(piece) &&
+        (
+          deltaX == 1 ||
+          (deltaX == 2 && piece == V.PAWN && x1 == startRank)
+        )
+      )
+    );
+  }
+
   // NOTE: for pushes, play the pushed piece first.
   //       for pulls: play the piece doing the action first
   // NOTE: to push a piece out of the board, make it slide until its king
   getPotentialMovesFrom([x, y]) {
     const color = this.turn;
+    const sqCol = this.getColor(x, y);
     if (this.subTurn == 1) {
       const getMoveHash = (m) => {
         return V.CoordsToSquare(m.start) + V.CoordsToSquare(m.end);
@@ -225,10 +241,20 @@ export class DynamoRules extends ChessRules {
         Array.prototype.push.apply(moves, newMoves);
       };
       // Free to play any move (if piece of my color):
-      const moves =
-        this.getColor(x, y) == color
+      let moves =
+        sqCol == color
           ? super.getPotentialMovesFrom([x, y])
           : [];
+      // There may be several suicide moves: keep only one
+      let hasExit = false;
+      moves = moves.filter(m => {
+        const suicide = (m.appear.length == 0);
+        if (suicide) {
+          if (hasExit) return false;
+          hasExit = true;
+        }
+        return true;
+      });
       const pawnShift = (color == 'w' ? -1 : 1);
       const pawnStartRank = (color == 'w' ? 6 : 1);
       // Structure to avoid adding moves twice (can be action & move)
@@ -259,7 +285,6 @@ export class DynamoRules extends ChessRules {
         ) {
           const deltaX = Math.abs(i - x);
           const deltaY = Math.abs(j - y);
-          // Can a priori go both ways, except with pawns
           switch (this.getPiece(i, j)) {
             case V.PAWN:
               if (
@@ -267,13 +292,12 @@ export class DynamoRules extends ChessRules {
                 deltaX <= 2 &&
                 deltaY <= 1
               ) {
-                const pColor = this.getColor(x, y);
-                if (pColor == color && deltaY == 0) {
+                if (sqCol == color && deltaY == 0) {
                   // Pushed forward
                   const maxSteps = (i == pawnStartRank && deltaX == 1 ? 2 : 1);
                   addMoves(step, maxSteps);
                 }
-                else if (pColor != color && deltaY == 1 && deltaX == 1)
+                else if (sqCol != color && deltaY == 1 && deltaX == 1)
                   // Pushed diagonally
                   addMoves(step, 1);
               }
@@ -285,8 +309,8 @@ export class DynamoRules extends ChessRules {
               if (deltaX == deltaY) addMoves(step);
               break;
             case V.QUEEN:
-              if (deltaX == 0 || deltaY == 0 || deltaX == deltaY)
-                addMoves(step);
+              // All steps are valid for a queen:
+              addMoves(step);
               break;
             case V.KING:
               if (deltaX <= 1 && deltaY <= 1) addMoves(step, 1);
@@ -302,13 +326,19 @@ export class DynamoRules extends ChessRules {
     // naturally limited in those cases.
     const L = this.firstMove.length;
     const fm = this.firstMove[L-1];
-    if (fm.appear.length == 2 && fm.vanish.length == 2)
-      // Castle: no real move playable then.
+    if (
+      (fm.appear.length == 2 && fm.vanish.length == 2) ||
+      (fm.vanish[0].c == sqCol && sqCol != color)
+    ) {
+      // Castle or again opponent color: no move playable then.
       return [];
+    }
     if (fm.appear.length == 0) {
       // Piece at subTurn 1 just exited the board.
       // Can I be a piece which caused the exit?
       if (
+        // Only "turn" color can do actions
+        sqCol == color &&
         this.isAprioriValidExit(
           [x, y],
           [fm.start.x, fm.start.y],
@@ -318,7 +348,9 @@ export class DynamoRules extends ChessRules {
         // Seems so:
         const dir = this.getNormalizedDirection(
           [fm.start.x - x, fm.start.y - y]);
-        return this.getMovesInDirection([x, y], dir);
+        const nbSteps =
+          ([V.PAWN,V.KING,V.KNIGHT].includes(this.getPiece(x, y)) ? 1 : null);
+        return this.getMovesInDirection([x, y], dir, nbSteps);
       }
     }
     else {
@@ -328,6 +360,15 @@ export class DynamoRules extends ChessRules {
         [fm.start.x - x, fm.start.y - y]);
       // Normalized directions should match
       if (dir[0] == dirM[0] && dir[1] == dirM[1]) {
+        // If first move is a pawn move, only a queen, rook, or maybe king or
+        // pawn can follow (need vertical movement option).
+        if (
+          fm.vanish[0].p == V.PAWN &&
+          fm.vanish[0].c == color &&
+          !this.isAprioriValidVertical([x, y], fm.start.x)
+        ) {
+          return [];
+        }
         // And nothing should stand between [x, y] and the square fm.start
         let [i, j] = [x + dir[0], y + dir[1]];
         while (
@@ -344,6 +385,45 @@ export class DynamoRules extends ChessRules {
     return [];
   }
 
+  getSlideNJumpMoves([x, y], steps, oneStep) {
+    let moves = [];
+    const c = this.getColor(x, y);
+    const piece = this.getPiece(x, y);
+    outerLoop: for (let step of steps) {
+      let i = x + step[0];
+      let j = y + step[1];
+      while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
+        moves.push(this.getBasicMove([x, y], [i, j]));
+        if (oneStep) continue outerLoop;
+        i += step[0];
+        j += step[1];
+      }
+      if (V.OnBoard(i, j)) {
+        if (this.canTake([x, y], [i, j]))
+          moves.push(this.getBasicMove([x, y], [i, j]));
+      }
+      else {
+        // Add potential board exit (suicide), except for the king
+        if (piece != V.KING) {
+          moves.push({
+            start: { x: x, y: y},
+            end: { x: this.kingPos[c][0], y: this.kingPos[c][1] },
+            appear: [],
+            vanish: [
+              new PiPo({
+                x: x,
+                y: y,
+                c: c,
+                p: piece
+              })
+            ]
+          });
+        }
+      }
+    }
+    return moves;
+  }
+
   // Does m2 un-do m1 ? (to disallow undoing actions)
   oppositeMoves(m1, m2) {
     const isEqual = (av1, av2) => {