Several small improvements + integrate options + first working draft of Cwda
[vchess.git] / client / src / variants / Perfect.js
index a0c75c5..65334e2 100644 (file)
@@ -3,6 +3,7 @@ import { ArrayFun } from "@/utils/array";
 import { randInt } from "@/utils/alea";
 
 export class PerfectRules extends ChessRules {
+
   static get PawnSpecs() {
     return Object.assign(
       {},
@@ -57,19 +58,19 @@ export class PerfectRules extends ChessRules {
 
   getPotentialAmazonMoves(sq) {
     return super.getPotentialQueenMoves(sq).concat(
-      this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
+      this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], 1)
     );
   }
 
   getPotentialEmpressMoves(sq) {
     return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat(
-      this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
+      this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], 1)
     );
   }
 
   getPotentialPrincessMoves(sq) {
     return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
-      this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
+      this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], 1)
     );
   }
 
@@ -84,40 +85,23 @@ export class PerfectRules extends ChessRules {
 
   isAttackedByAmazon(sq, color) {
     return (
-      super.isAttackedByQueen(sq, color) ||
-      this.isAttackedBySlideNJump(
-        sq,
-        color,
-        V.MARSHALL,
-        V.steps[V.KNIGHT],
-        "oneStep"
-      )
+      this.isAttackedBySlideNJump(sq, color, V.AMAZON, V.steps[V.BISHOP]) ||
+      this.isAttackedBySlideNJump(sq, color, V.AMAZON, V.steps[V.ROOK]) ||
+      this.isAttackedBySlideNJump(sq, color, V.AMAZON, V.steps[V.KNIGHT], 1)
     );
   }
 
   isAttackedByEmpress(sq, color) {
     return (
-      this.isAttackedBySlideNJump(sq, color, V.MARSHALL, V.steps[V.ROOK]) ||
-      this.isAttackedBySlideNJump(
-        sq,
-        color,
-        V.MARSHALL,
-        V.steps[V.KNIGHT],
-        "oneStep"
-      )
+      this.isAttackedBySlideNJump(sq, color, V.EMPRESS, V.steps[V.ROOK]) ||
+      this.isAttackedBySlideNJump(sq, color, V.EMPRESS, V.steps[V.KNIGHT], 1)
     );
   }
 
   isAttackedByPrincess(sq, color) {
     return (
-      this.isAttackedBySlideNJump(sq, color, V.CARDINAL, V.steps[V.BISHOP]) ||
-      this.isAttackedBySlideNJump(
-        sq,
-        color,
-        V.CARDINAL,
-        V.steps[V.KNIGHT],
-        "oneStep"
-      )
+      this.isAttackedBySlideNJump(sq, color, V.PRINCESS, V.steps[V.BISHOP]) ||
+      this.isAttackedBySlideNJump(sq, color, V.PRINCESS, V.steps[V.KNIGHT], 1)
     );
   }
 
@@ -132,71 +116,55 @@ export class PerfectRules extends ChessRules {
     return 2;
   }
 
-  static GenRandInitFen(randomness) {
-    if (randomness == 0)
+  static GenRandInitFen(options) {
+    if (options.randomness == 0)
       return "esqakbnr/pppppppp/8/8/8/8/PPPPPPPP/ESQAKBNR w 0 ahah -";
 
-    let pieces = { w: new Array(8), b: new Array(8) };
-    let flags = "";
-    let whiteBishopPos = -1;
-    for (let c of ["w", "b"]) {
-      if (c == 'b' && randomness == 1) {
-        pieces['b'] = pieces['w'];
-        flags += flags;
-        break;
+    const baseFen = ChessRules.GenRandInitFen(options);
+    const fenParts = baseFen.split(' ');
+    const posParts = fenParts[0].split('/');
+
+    // Replace a random rook per side by an empress,
+    // a random knight by a princess, and a bishop by an amazon
+    // (Constraint: the two remaining bishops on different colors).
+
+    let newPos = { 0: "", 7: "" };
+    let amazonOddity = -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 == amazonOddity) ||
+            (
+              (curChar != 'b' || rank == 0) &&
+              replaced[curChar] == -2 &&
+              randInt(2) == 0
+            )
+          ) {
+            replaced[curChar] = i;
+            if (curChar == 'b') {
+              if (amazonOddity < 0) amazonOddity = i % 2;
+              newPos[rank] += 'a';
+            }
+            else if (curChar == 'r') newPos[rank] += 'e';
+            else newPos[rank] += 's';
+          }
+          else {
+            if (replaced[curChar] == -2) replaced[curChar]++;
+            newPos[rank] += curChar;
+          }
+        }
+        else newPos[rank] += curChar;
       }
-
-      let positions = ArrayFun.range(8);
-
-      // Get random squares for bishop: if black, pick a different color
-      // than where the white one stands.
-      let randIndex =
-        c == 'w'
-          ? randInt(8)
-          : 2 * randInt(4) + (1 - whiteBishopPos % 2);
-      if (c == 'w') whiteBishopPos = randIndex;
-      const bishopPos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(7);
-      const knightPos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(6);
-      const queenPos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(5);
-      const amazonPos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      randIndex = randInt(4);
-      const princessPos = positions[randIndex];
-      positions.splice(randIndex, 1);
-
-      // Rook, empress and king positions are now almost fixed,
-      // only the ordering rook->empress or empress->rook must be decided.
-      let rookPos = positions[0];
-      let empressPos = positions[2];
-      const kingPos = positions[1];
-      flags += V.CoordToColumn(rookPos) + V.CoordToColumn(empressPos);
-      if (Math.random() < 0.5) [rookPos, empressPos] = [empressPos, rookPos];
-
-      pieces[c][rookPos] = "r";
-      pieces[c][knightPos] = "n";
-      pieces[c][bishopPos] = "b";
-      pieces[c][queenPos] = "q";
-      pieces[c][kingPos] = "k";
-      pieces[c][amazonPos] = "a";
-      pieces[c][princessPos] = "s";
-      pieces[c][empressPos] = "e";
     }
-    // Add turn + flags + enpassant
+
     return (
-      pieces["b"].join("") +
-      "/pppppppp/8/8/8/8/PPPPPPPP/" +
-      pieces["w"].join("").toUpperCase() +
-      " w 0 " + flags + " -"
+      newPos[0] + "/" + posParts.slice(1, 7).join('/') + "/" +
+      newPos[7].toUpperCase() + " " + fenParts.slice(1, 5).join(' ') + " -"
     );
   }
+
 };