Attempt to fix Eightpieces
[vchess.git] / client / src / variants / Eightpieces.js
index 1fbc5d0..dc7580b 100644 (file)
@@ -1,4 +1,4 @@
-import { randInt } from "@/utils/alea";
+import { randInt, sample } from "@/utils/alea";
 import { ChessRules, PiPo, Move } from "@/base_rules";
 
 export class EightpiecesRules extends ChessRules {
@@ -167,58 +167,54 @@ export class EightpiecesRules extends ChessRules {
     }
   }
 
-  static GenRandInitFen(randomness) {
-    if (randomness == 0)
+  static GenRandInitFen(options) {
+    if (options.randomness == 0)
       return "jfsqkbnr/pppppppp/8/8/8/8/PPPPPPPP/JDSQKBNR w 0 ahah - -";
 
-    const baseFen = ChessRules.GenRandInitFen(randomness);
+    const baseFen = ChessRules.GenRandInitFen(options);
     const fenParts = baseFen.split(' ');
     const posParts = fenParts[0].split('/');
 
     // Replace one bishop by sentry, so that sentries on different colors
     // Also replace one random rook by jailer,
     // and one random knight by lancer (facing north/south)
-
-    // "replaced" array contains -2 initially, then either -1 if skipped,
-    // or (eventually) the index of replacement:
-    let newPos = { 0: "", 7: "" };
-    let sentryOddity = -1;
-    for (let rank of [0, 7]) {
-      let replaced = { 'b': -2, 'n': -2, 'r': -2 };
-      for (let i = 0; i < 8; i++) {
-        const curChar = posParts[rank].charAt(i).toLowerCase();
-        if (['b', 'n', 'r'].includes(curChar)) {
-          if (
-            replaced[curChar] == -1 ||
-            (curChar == 'b' && rank == 7 && i % 2 == sentryOddity) ||
-            (
-              (curChar != 'b' || rank == 0) &&
-              replaced[curChar] == -2 &&
-              randInt(2) == 0
-            )
-          ) {
-            replaced[curChar] = i;
-            if (curChar == 'b') {
-              if (sentryOddity < 0) sentryOddity = i % 2;
-              newPos[rank] += 's';
-            }
-            else if (curChar == 'r') newPos[rank] += 'j';
-            else
-              // Lancer: orientation depends on side
-              newPos[rank] += (rank == 0 ? 'g' : 'c');
-          }
-          else {
-            if (replaced[curChar] == -2) replaced[curChar]++;
-            newPos[rank] += curChar;
-          }
-        }
-        else newPos[rank] += curChar;
+    let pieceLine = { b: posParts[0], w: posParts[7].toLowerCase() };
+    let posBlack = { r: -1, n: -1, b: -1 };
+    const mapP = { r: 'j', n: 'l', b: 's' };
+    ['w', 'b'].forEach(c => {
+      ['r', 'n', 'b'].forEach(p => {
+        let pl = pieceLine[c];
+        let pos = -1;
+        if (options.randomness == 2 || c == 'b')
+          pos = (randInt(2) == 0 ? pl.indexOf(p) : pl.lastIndexOf(p));
+        else pos = posBlack[p];
+        pieceLine[c] =
+          pieceLine[c].substr(0, pos) + mapP[p] + pieceLine[c].substr(pos+1);
+        if (options.randomness == 1 && c == 'b') posBlack[p] = pos;
+      });
+    });
+    // Rename 'l' into 'g' (black) or 'c' (white)
+    pieceLine['w'] = pieceLine['w'].replace('l', 'c');
+    pieceLine['b'] = pieceLine['b'].replace('l', 'g');
+    if (options.randomness == 2) {
+      const ws = pieceLine['w'].indexOf('s');
+      const bs = pieceLine['b'].indexOf('s');
+      if (ws % 2 != bs % 2) {
+        // Fix sentry: should be on different colors.
+        // => move sentry on other bishop for random color
+        const c = sample(['w', 'b'], 1);
+        pieceLine[c] = pieceLine[c]
+                       .replace('b', 't'); //tmp
+                       .replace('s', 'b');
+                       .replace('t', 's');
       }
     }
 
     return (
-      newPos[0] + "/" + posParts.slice(1, 7).join('/') + "/" +
-      newPos[7].toUpperCase() + " " + fenParts.slice(1, 5).join(' ') + " -"
+      pieceLine['b'] + "/" +
+      posParts.slice(1, 7).join('/') + "/" +
+      pieceLine['w'].toUpperCase() + " " +
+      fenParts.slice(1, 5).join(' ') + " -"
     );
   }
 
@@ -246,45 +242,6 @@ export class EightpiecesRules extends ChessRules {
     return null;
   }
 
-  // Because of the lancers, getPiece() could be wrong:
-  // use board[x][y][1] instead (always valid).
-  getBasicMove([sx, sy], [ex, ey], tr) {
-    const initColor = this.getColor(sx, sy);
-    const initPiece = this.board[sx][sy].charAt(1);
-    let mv = new Move({
-      appear: [
-        new PiPo({
-          x: ex,
-          y: ey,
-          c: tr ? tr.c : initColor,
-          p: tr ? tr.p : initPiece
-        })
-      ],
-      vanish: [
-        new PiPo({
-          x: sx,
-          y: sy,
-          c: initColor,
-          p: initPiece
-        })
-      ]
-    });
-
-    // The opponent piece disappears if we take it
-    if (this.board[ex][ey] != V.EMPTY) {
-      mv.vanish.push(
-        new PiPo({
-          x: ex,
-          y: ey,
-          c: this.getColor(ex, ey),
-          p: this.board[ex][ey].charAt(1)
-        })
-      );
-    }
-
-    return mv;
-  }
-
   canIplay(side, [x, y]) {
     return (
       (this.subTurn == 1 && this.turn == side && this.getColor(x, y) == side)
@@ -710,10 +667,7 @@ export class EightpiecesRules extends ChessRules {
 
   getPotentialKingMoves(sq) {
     const moves = this.getSlideNJumpMoves(
-      sq,
-      V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
-      "oneStep"
-    );
+      sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), 1);
     return (
       this.subTurn == 1
         ? moves.concat(this.getCastleMoves(sq))
@@ -863,8 +817,8 @@ export class EightpiecesRules extends ChessRules {
     const oppCol = V.GetOppCol(color);
     const sliderAttack = (allowedSteps, lancer) => {
       const deltaX = x2 - x1,
-            absDeltaX = Math.abs(deltaX);
-      const deltaY = y2 - y1,
+            deltaY = y2 - y1;
+      const absDeltaX = Math.abs(deltaX),
             absDeltaY = Math.abs(deltaY);
       const step = [ deltaX / absDeltaX || 0, deltaY / absDeltaY || 0 ];
       if (
@@ -876,12 +830,18 @@ export class EightpiecesRules extends ChessRules {
       }
       let sq = [ x1 + step[0], y1 + step[1] ];
       while (sq[0] != x2 || sq[1] != y2) {
-        if (
-          // NOTE: no need to check OnBoard in this special case
-          (!lancer && this.board[sq[0]][sq[1]] != V.EMPTY) ||
-          (!!lancer && this.getColor(sq[0], sq[1]) == oppCol)
-        ) {
-          return false;
+        // NOTE: no need to check OnBoard in this special case
+        if (this.board[sq[0]][sq[1]] != V.EMPTY) {
+          const p = this.getPiece(sq[0], sq[1]);
+          const pc = this.getColor(sq[0], sq[1]);
+          if (
+            // Enemy sentry on the way will be gone:
+            (p != V.SENTRY || pc != oppCol) &&
+            // Lancer temporarily "changed color":
+            (!lancer || pc == color)
+          ) {
+            return false;
+          }
         }
         sq[0] += step[0];
         sq[1] += step[1];