loseOnRepetition: getter seems enough
[vchess.git] / client / src / variants / Shogi.js
index bca3762..95be2d1 100644 (file)
@@ -24,7 +24,7 @@ export class ShogiRules extends ChessRules {
     return true;
   }
 
-  loseOnRepetition() {
+  get loseOnRepetition() {
     // If current side is under check: lost
     return this.underCheck(this.turn);
   }
@@ -113,8 +113,8 @@ export class ShogiRules extends ChessRules {
     );
   }
 
-  static GenRandInitFen(randomness) {
-    if (randomness == 0) {
+  static GenRandInitFen(options) {
+    if (options.randomness == 0) {
       return (
         "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL " +
         "w 0 00000000000000"
@@ -125,7 +125,7 @@ export class ShogiRules extends ChessRules {
     let pieces1 = { w: new Array(4), b: new Array(4) };
     let positions2 = { w: new Array(2), b: new Array(2) };
     for (let c of ["w", "b"]) {
-      if (c == 'b' && randomness == 1) {
+      if (c == 'b' && options.randomness == 1) {
         pieces1['b'] = JSON.parse(JSON.stringify(pieces1['w'])).reverse();
         positions2['b'] =
           JSON.parse(JSON.stringify(positions2['w'])).reverse()
@@ -335,7 +335,7 @@ export class ShogiRules extends ChessRules {
   }
 
   // Modified to take promotions into account
-  getSlideNJumpMoves([x, y], steps, options) {
+  getSlideNJumpMoves_opt([x, y], steps, options) {
     options = options || {};
     const color = this.turn;
     const oneStep = options.oneStep;
@@ -375,7 +375,7 @@ export class ShogiRules extends ChessRules {
 
   getPotentialGoldMoves(sq) {
     const forward = (this.turn == 'w' ? -1 : 1);
-    return this.getSlideNJumpMoves(
+    return this.getSlideNJumpMoves_opt(
       sq,
       V.steps[V.ROOK].concat([ [forward, 1], [forward, -1] ]),
       { oneStep: true }
@@ -385,7 +385,7 @@ export class ShogiRules extends ChessRules {
   getPotentialPawnMoves(sq) {
     const forward = (this.turn == 'w' ? -1 : 1);
     return (
-      this.getSlideNJumpMoves(
+      this.getSlideNJumpMoves_opt(
         sq,
         [[forward, 0]],
         {
@@ -399,7 +399,7 @@ export class ShogiRules extends ChessRules {
 
   getPotentialSilverMoves(sq) {
     const forward = (this.turn == 'w' ? -1 : 1);
-    return this.getSlideNJumpMoves(
+    return this.getSlideNJumpMoves_opt(
       sq,
       V.steps[V.BISHOP].concat([ [forward, 0] ]),
       {
@@ -411,7 +411,7 @@ export class ShogiRules extends ChessRules {
 
   getPotentialKnightMoves(sq) {
     const forward = (this.turn == 'w' ? -2 : 2);
-    return this.getSlideNJumpMoves(
+    return this.getSlideNJumpMoves_opt(
       sq,
       [ [forward, 1], [forward, -1] ],
       {
@@ -424,9 +424,9 @@ export class ShogiRules extends ChessRules {
 
   getPotentialLanceMoves(sq) {
     const forward = (this.turn == 'w' ? -1 : 1);
-    return this.getSlideNJumpMoves(
+    return this.getSlideNJumpMoves_opt(
       sq,
-      [[forward, 0]],
+      [ [forward, 0] ],
       {
         promote: V.P_LANCE,
         force: true
@@ -435,26 +435,26 @@ export class ShogiRules extends ChessRules {
   }
 
   getPotentialRookMoves(sq) {
-    return this.getSlideNJumpMoves(
+    return this.getSlideNJumpMoves_opt(
       sq, V.steps[V.ROOK], { promote: V.P_ROOK });
   }
 
   getPotentialBishopMoves(sq) {
-    return this.getSlideNJumpMoves(
+    return this.getSlideNJumpMoves_opt(
       sq, V.steps[V.BISHOP], { promote: V.P_BISHOP });
   }
 
   getPotentialDragonMoves(sq) {
     return (
-      this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat(
-      this.getSlideNJumpMoves(sq, V.steps[V.BISHOP], { oneStep: true }))
+      this.getSlideNJumpMoves_opt(sq, V.steps[V.ROOK]).concat(
+      this.getSlideNJumpMoves_opt(sq, V.steps[V.BISHOP], { oneStep: true }))
     );
   }
 
   getPotentialHorseMoves(sq) {
     return (
-      this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
-      this.getSlideNJumpMoves(sq, V.steps[V.ROOK], { oneStep: true }))
+      this.getSlideNJumpMoves_opt(sq, V.steps[V.BISHOP]).concat(
+      this.getSlideNJumpMoves_opt(sq, V.steps[V.ROOK], { oneStep: true }))
     );
   }
 
@@ -490,37 +490,21 @@ export class ShogiRules extends ChessRules {
     return false;
   }
 
-  isAttackedBySilver([x, y], color) {
+  isAttackedBySilver(sq, color) {
     const shift = (color == 'w' ? 1 : -1);
-    for (let step of V.steps[V.BISHOP].concat([[shift, 0]])) {
-      const [i, j] = [x + step[0], y + step[1]];
-      if (
-        V.OnBoard(i, j) &&
-        this.board[i][j] != V.EMPTY &&
-        this.getColor(i, j) == color &&
-        this.getPiece(i, j) == V.SILVER_G
-      ) {
-        return true;
-      }
-    }
-    return false;
+    return this.isAttackedBySlideNJump(
+      sq, color, V.SILVER, V.steps[V.BISHOP].concat([ [shift, 0] ]), 1);
   }
 
-  isAttackedByPawn([x, y], color) {
+  isAttackedByPawn(sq, color) {
     const shift = (color == 'w' ? 1 : -1);
-    const [i, j] = [x + shift, y];
-    return (
-      V.OnBoard(i, j) &&
-      this.board[i][j] != V.EMPTY &&
-      this.getColor(i, j) == color &&
-      this.getPiece(i, j) == V.PAWN
-    );
+    return this.isAttackedBySlideNJump(sq, color, V.PAWN, [ [shift, 0] ], 1);
   }
 
   isAttackedByKnight(sq, color) {
     const forward = (color == 'w' ? 2 : -2);
     return this.isAttackedBySlideNJump(
-      sq, color, V.KNIGHT, [[forward, 1], [forward, -1]], "oneStep");
+      sq, color, V.KNIGHT, [ [forward, 1], [forward, -1] ], 1);
   }
 
   isAttackedByLance(sq, color) {
@@ -531,19 +515,36 @@ export class ShogiRules extends ChessRules {
   isAttackedByDragon(sq, color) {
     return (
       this.isAttackedBySlideNJump(sq, color, V.P_ROOK, V.steps[V.ROOK]) ||
-      this.isAttackedBySlideNJump(
-        sq, color, V.P_ROOK, V.steps[V.BISHOP], "oneStep")
+      this.isAttackedBySlideNJump(sq, color, V.P_ROOK, V.steps[V.BISHOP], 1)
     );
   }
 
   isAttackedByHorse(sq, color) {
     return (
       this.isAttackedBySlideNJump(sq, color, V.P_BISHOP, V.steps[V.BISHOP]) ||
-      this.isAttackedBySlideNJump(
-        sq, color, V.P_BISHOP, V.steps[V.ROOK], "oneStep")
+      this.isAttackedBySlideNJump(sq, color, V.P_BISHOP, V.steps[V.ROOK], 1)
     );
   }
 
+  filterValid(moves) {
+    if (moves.length == 0) return [];
+    const color = this.turn;
+    const lastRanks = (color == 'w' ? [0, 1] : [8, 7]);
+    return moves.filter(m => {
+      if (
+        (m.appear[0].p == V.KNIGHT && lastRanks.includes(m.end.x)) ||
+        ([V.PAWN, V.LANCE].includes(m.appear[0].p) && lastRanks[0] == m.end.x)
+      ) {
+        // Forbid moves resulting in a blocked piece
+        return false;
+      }
+      this.play(m);
+      const res = !this.underCheck(color);
+      this.undo(m);
+      return res;
+    });
+  }
+
   getAllValidMoves() {
     let moves = super.getAllPotentialMoves();
     const color = this.turn;