Several small improvements + integrate options + first working draft of Cwda
[vchess.git] / client / src / variants / Football.js
index 2410f0a..7829c2d 100644 (file)
@@ -104,13 +104,13 @@ export class FootballRules extends ChessRules {
     }
   }
 
-  static GenRandInitFen(randomness) {
-    if (randomness == 0)
+  static GenRandInitFen(options) {
+    if (options.randomness == 0)
       return "rnbq1knbr/9/9/9/4a4/9/9/9/RNBQ1KNBR w 0";
 
     let pieces = { w: new Array(8), b: new Array(8) };
     for (let c of ["w", "b"]) {
-      if (c == 'b' && randomness == 1) {
+      if (c == 'b' && options.randomness == 1) {
         pieces['b'] = pieces['w'];
         break;
       }
@@ -191,36 +191,98 @@ export class FootballRules extends ChessRules {
       let [i, j] = [bp[0] + step[0], bp[1] + step[1]];
       const horizontalStepOnGoalRow =
         ([0, 8].includes(bp[0]) && step.some(s => s == 0));
-      if (emptySquare(i, j) && (!horizontalStepOnGoalRow || j != 4)) {
+      if (
+        emptySquare(i, j) &&
+        (this.movesCount >= 2 || j != 4 || ![0, 8].includes(i)) &&
+        (!horizontalStepOnGoalRow || j != 4)
+      ) {
         moves.push(super.getBasicMove(bp, [i, j]));
         if (!oneStep) {
           do {
             i += step[0];
             j += step[1];
             if (!emptySquare(i, j)) break;
-            if (!horizontalStepOnGoalRow || j != 4)
+            if (
+              (this.movesCount >= 2 || j != 4 || ![0, 8].includes(i)) &&
+              (!horizontalStepOnGoalRow || j != 4)
+            ) {
               moves.push(super.getBasicMove(bp, [i, j]));
+            }
+          } while (true);
+        }
+      }
+      // Try the other direction (TODO: experimental)
+      [i, j] = [bp[0] - 2*step[0], bp[1] - 2*step[1]];
+      if (
+        emptySquare(i, j) &&
+        (this.movesCount >= 2 || j != 4 || ![0, 8].includes(i)) &&
+        (!horizontalStepOnGoalRow || j != 4)
+      ) {
+        moves.push(super.getBasicMove(bp, [i, j]));
+        if (!oneStep) {
+          do {
+            i -= step[0];
+            j -= step[1];
+            if (!emptySquare(i, j)) break;
+            if (
+              (this.movesCount >= 2 || j != 4 || ![0, 8].includes(i)) &&
+              (!horizontalStepOnGoalRow || j != 4)
+            ) {
+              moves.push(super.getBasicMove(bp, [i, j]));
+            }
           } while (true);
         }
       }
     }
     const kickedFrom = x + "-" + y;
-    moves.forEach(m => m.by = kickedFrom)
+    moves.forEach(m => m.start.by = kickedFrom)
     return moves;
   }
 
   getPotentialMovesFrom([x, y], computer) {
-    if (V.PIECES.includes(this.getPiece(x, y))) {
+    const piece = this.getPiece(x, y);
+    if (V.PIECES.includes(piece)) {
       if (this.subTurn > 1) return [];
-      return (
-        super.getPotentialMovesFrom([x, y])
-        .filter(m => m.end.y != 4 || ![0, 8].includes(m.end.x))
-      );
+      const moves = super.getPotentialMovesFrom([x, y])
+                    .filter(m => m.end.y != 4 || ![0, 8].includes(m.end.x));
+      // If bishop stuck in a corner: allow to jump over the next obstacle
+      if (moves.length == 0 && piece == V.BISHOP) {
+        if (
+          x == 0 && y == 0 &&
+          this.board[1][1] != V.EMPTY &&
+          this.board[2][2] == V.EMPTY
+        ) {
+          return [super.getBasicMove([x, y], [2, 2])];
+        }
+        if (
+          x == 0 && y == 8 &&
+          this.board[1][7] != V.EMPTY &&
+          this.board[2][6] == V.EMPTY
+        ) {
+          return [super.getBasicMove([x, y], [2, 6])];
+        }
+        if (
+          x == 8 && y == 0 &&
+          this.board[7][1] != V.EMPTY &&
+          this.board[6][2] == V.EMPTY
+        ) {
+          return [super.getBasicMove([x, y], [6, 2])];
+        }
+        if (
+          x == 8 && y == 8 &&
+          this.board[7][7] != V.EMPTY &&
+          this.board[6][6] == V.EMPTY
+        ) {
+          return [super.getBasicMove([x, y], [6, 6])];
+        }
+      }
+      return moves;
     }
     // Kicking the ball: look for adjacent pieces.
     const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
     const c = this.turn;
     let moves = [];
+    let kicks = {};
     for (let s of steps) {
       const [i, j] = [x + s[0], y + s[1]];
       if (
@@ -228,37 +290,32 @@ export class FootballRules extends ChessRules {
         this.board[i][j] != V.EMPTY &&
         this.getColor(i, j) == c
       ) {
-        Array.prototype.push.apply(moves, this.tryKickFrom([i, j]));
+        const kmoves = this.tryKickFrom([i, j]);
+        kmoves.forEach(km => {
+          const key = V.CoordsToSquare(km.start) + V.CoordsToSquare(km.end);
+          if (!kicks[km]) {
+            moves.push(km);
+            kicks[km] = true;
+          }
+        });
       }
     }
-    // And, always add the "end" move. For computer, keep only one
-    outerLoop: 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) == c) {
-          moves.push(super.getBasicMove([x, y], [i, j]));
-          if (!!computer) break outerLoop;
+    if (Object.keys(kicks).length > 0) {
+      // And, always add the "end" move. For computer, keep only one
+      outerLoop: 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) == c) {
+            moves.push(super.getBasicMove([x, y], [i, j]));
+            if (!!computer) break outerLoop;
+          }
         }
       }
     }
     return moves;
   }
 
-  // No captures:
-  getSlideNJumpMoves([x, y], steps, oneStep) {
-    let moves = [];
-    outerLoop: for (let step of steps) {
-      let i = x + step[0];
-      let j = y + step[1];
-      let stepCount = 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];
-        stepCount++;
-      }
-    }
-    return moves;
+  canTake() {
+    return false;
   }
 
   // Extra arg "computer" to avoid trimming all redundant pass moves:
@@ -285,7 +342,7 @@ export class FootballRules extends ChessRules {
   filterValid(moves) {
     const L = this.kickedBy.length;
     const kb = this.kickedBy[L-1];
-    return moves.filter(m => !m.by || !kb[m.by]);
+    return moves.filter(m => !m.start.by || !kb[m.start.by]);
   }
 
   getCheckSquares() {
@@ -332,9 +389,9 @@ export class FootballRules extends ChessRules {
     }
     else {
       this.subTurn++;
-      if (!!move.by) {
+      if (!!move.start.by) {
         const L = this.kickedBy.length;
-        this.kickedBy[L-1][move.by] = true;
+        this.kickedBy[L-1][move.start.by] = true;
       }
     }
   }
@@ -348,9 +405,9 @@ export class FootballRules extends ChessRules {
     }
     else {
       this.subTurn--;
-      if (!!move.by) {
+      if (!!move.start.by) {
         const L = this.kickedBy.length;
-        delete this.kickedBy[L-1][move.by];
+        delete this.kickedBy[L-1][move.start.by];
       }
     }
     if (!passesOver) {