From 939e06bf9febef0a7935c7f6a58c5e28dee4dedc Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Fri, 5 Jan 2024 09:58:16 +0100
Subject: [PATCH] Start working on Dynamo

---
 base_rules.js            |  22 ++-
 variants/Dynamo/class.js | 289 +++++----------------------------------
 2 files changed, 52 insertions(+), 259 deletions(-)

diff --git a/base_rules.js b/base_rules.js
index 9a364e8..3d8e463 100644
--- a/base_rules.js
+++ b/base_rules.js
@@ -175,6 +175,22 @@ export default class ChessRules {
     return Object.values(cd).map(c => c.toString(36)).join("");
   }
 
+  // c10 --> 02 (assuming 10 rows)
+  static SquareFromUsual(sq) {
+    return (
+      (this.size.x - parseInt(sq.substring(1), 10)).toString(36) +
+      (sq.charCodeAt(0) - 97).toString(36)
+    );
+  }
+
+  // 02 --> c10
+  static UsualFromSquare(sq) {
+    return (
+      String.fromCharCode(parseInt(sq.charAt(1), 36) + 97) +
+      (this.size.x - parseInt(sq.charAt(0), 36)).toString(10)
+    );
+  }
+
   coordsToId(cd) {
     if (typeof cd.x == "number") {
       return (
@@ -651,10 +667,8 @@ export default class ChessRules {
         this[arrName] = ArrayFun.init(this.size.x, this.size.y, null);
       if (arrName == "d_pieces")
         this.marks.forEach((m) => {
-          const formattedSquare =
-            (this.size.x - parseInt(m.substring(1), 10)).toString(36) +
-            (m.charCodeAt(0) - 97).toString(36);
-          const mCoords = V.SquareToCoords(formattedSquare);
+          const formattedSquare = C.SquareFromUsual(m);
+          const mCoords = C.SquareToCoords(formattedSquare);
           addPiece(mCoords.x, mCoords.y, arrName, "mark");
         });
     };
diff --git a/variants/Dynamo/class.js b/variants/Dynamo/class.js
index 0996a70..05f2aed 100644
--- a/variants/Dynamo/class.js
+++ b/variants/Dynamo/class.js
@@ -2,110 +2,51 @@ import ChessRules from "/base_rules.js";
 
 export default class DynamoRules extends ChessRules {
 
-  // TODO? later, allow to push out pawns on a and h files
-  get hasEnpassant() {
-    return false;
+  static get Options() {
+    // TODO
   }
 
-/// TODO:::
+  get hasEnpassant() {
+    return this.options["enpassant"];
+  }
 
-  canIplay(side, [x, y]) {
+  canIplay(x, y) {
     // Sometimes opponent's pieces can be moved directly
-    return this.turn == side;
+    return this.playerColor == this.turn;
+  }
+
+  canTake() {
+    // Captures don't occur (only pulls & pushes)
+    return false;
   }
 
-  setOtherVariables(fen) {
-    super.setOtherVariables(fen);
+  setOtherVariables(fenParsed) {
+    super.setOtherVariables(fenParsed);
     this.subTurn = 1;
-    // Local stack of "action moves"
-    this.amoves = [];
-    const amove = V.ParseFen(fen).amove;
-    if (amove != "-") {
-      const amoveParts = amove.split("/");
-      let move = {
-        // No need for start & end
-        appear: [],
-        vanish: []
-      };
-      [0, 1].map(i => {
-        if (amoveParts[i] != "-") {
-          amoveParts[i].split(".").forEach(av => {
-            // Format is "bpe3"
-            const xy = V.SquareToCoords(av.substr(2));
-            move[i == 0 ? "appear" : "vanish"].push(
-              new PiPo({
-                x: xy.x,
-                y: xy.y,
-                c: av[0],
-                p: av[1]
-              })
-            );
-          });
-        }
+    // Last action format: e2h5/d1g4 for queen on d1 pushing pawn to h5
+    // for example, and moving herself to g4. If just move: e2h5
+    this.lastAction = [];
+    if (fenParsed.amove != '-') {
+      this.lastAction = fenParsed.amove.split('/').map(a => {
+        return {
+          c1: C.SquareToCoords(C.SquareFromUsual(a.substr(0, 2))),
+          c2: C.SquareToCoords(C.SquareFromUsual(a.substr(2, 2)))
+        };
       });
-      this.amoves.push(move);
     }
-    // Stack "first moves" (on subTurn 1) to merge and check opposite moves
-    this.firstMove = [];
-  }
-
-  static ParseFen(fen) {
-    return Object.assign(
-      ChessRules.ParseFen(fen),
-      { amove: fen.split(" ")[4] }
-    );
   }
 
-  static IsGoodFen(fen) {
-    if (!ChessRules.IsGoodFen(fen)) return false;
-    const fenParts = fen.split(" ");
-    if (fenParts.length != 5) return false;
-    if (fenParts[4] != "-") {
-      // TODO: a single regexp instead.
-      // Format is [bpa2[.wpd3]] || '-'/[bbc3[.wrd5]] || '-'
-      const amoveParts = fenParts[4].split("/");
-      if (amoveParts.length != 2) return false;
-      for (let part of amoveParts) {
-        if (part != "-") {
-          for (let psq of part.split("."))
-            if (!psq.match(/^[a-z]{3}[1-8]$/)) return false;
-        }
-      }
+  getPartFen(o) {
+    let res = super.getPartFen(o);
+    if (o.init)
+      res["amove"] = '-';
+    else {
+      res["amove"] = this.lastAction.map(a => {
+        C.UsualFromSquare(C.CoordsToSquare(a.c1)) +
+        C.UsualFromSquare(C.CoordsToSquare(a.c2))
+      }).join('/');
     }
-    return true;
-  }
-
-  getFen() {
-    return super.getFen() + " " + this.getAmoveFen();
-  }
-
-  getFenForRepeat() {
-    return super.getFenForRepeat() + "_" + this.getAmoveFen();
-  }
-
-  getAmoveFen() {
-    const L = this.amoves.length;
-    if (L == 0) return "-";
-    return (
-      ["appear","vanish"].map(
-        mpart => {
-          if (this.amoves[L-1][mpart].length == 0) return "-";
-          return (
-            this.amoves[L-1][mpart].map(
-              av => {
-                const square = V.CoordsToSquare({ x: av.x, y: av.y });
-                return av.c + av.p + square;
-              }
-            ).join(".")
-          );
-        }
-      ).join("/")
-    );
-  }
-
-  canTake() {
-    // Captures don't occur (only pulls & pushes)
-    return false;
+    return res;
   }
 
   // Step is right, just add (push/pull) moves in this direction
@@ -590,6 +531,7 @@ export default class DynamoRules extends ChessRules {
     );
   }
 
+  // TODO: just stack in this.lastAction instead
   getAmove(move1, move2) {
     // Just merge (one is action one is move, one may be empty)
     return {
@@ -643,105 +585,6 @@ export default class DynamoRules extends ChessRules {
     );
   }
 
-  isAttackedBySlideNJump([x, y], color, piece, steps, oneStep) {
-    for (let step of steps) {
-      let rx = x + step[0],
-          ry = y + step[1];
-      while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) {
-        rx += step[0];
-        ry += step[1];
-      }
-      if (
-        V.OnBoard(rx, ry) &&
-        this.getPiece(rx, ry) == piece &&
-        this.getColor(rx, ry) == color
-      ) {
-        // Continue some steps in the same direction (pull)
-        rx += step[0];
-        ry += step[1];
-        while (
-          V.OnBoard(rx, ry) &&
-          this.board[rx][ry] == V.EMPTY &&
-          !oneStep
-        ) {
-          rx += step[0];
-          ry += step[1];
-        }
-        if (!V.OnBoard(rx, ry)) return true;
-        // Step in the other direction (push)
-        rx = x - step[0];
-        ry = y - step[1];
-        while (
-          V.OnBoard(rx, ry) &&
-          this.board[rx][ry] == V.EMPTY &&
-          !oneStep
-        ) {
-          rx -= step[0];
-          ry -= step[1];
-        }
-        if (!V.OnBoard(rx, ry)) return true;
-      }
-    }
-    return false;
-  }
-
-  isAttackedByPawn([x, y], color) {
-    // The king can be pushed out by a pawn on last rank or near the edge
-    const pawnShift = (color == "w" ? 1 : -1);
-    for (let i of [-1, 1]) {
-      if (
-        V.OnBoard(x + pawnShift, y + i) &&
-        this.board[x + pawnShift][y + i] != V.EMPTY &&
-        this.getPiece(x + pawnShift, y + i) == V.PAWN &&
-        this.getColor(x + pawnShift, y + i) == color
-      ) {
-        if (!V.OnBoard(x - pawnShift, y - i)) return true;
-      }
-    }
-    return false;
-  }
-
-  static OnTheEdge(x, y) {
-    return (x == 0 || x == 7 || y == 0 || y == 7);
-  }
-
-  isAttackedByKing([x, y], color) {
-    // Attacked if I'm on the edge and the opponent king just next,
-    // but not on the edge.
-    if (V.OnTheEdge(x, y)) {
-      for (let step of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) {
-        const [i, j] = [x + step[0], y + step[1]];
-        if (
-          V.OnBoard(i, j) &&
-          !V.OnTheEdge(i, j) &&
-          this.board[i][j] != V.EMPTY &&
-          this.getPiece(i, j) == V.KING
-          // NOTE: since only one king of each color, and (x, y) is occupied
-          // by our king, no need to check other king's color.
-        ) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
-  // No consideration of color: all pieces could be played
-  getAllPotentialMoves() {
-    let potentialMoves = [];
-    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) {
-          Array.prototype.push.apply(
-            potentialMoves,
-            this.getPotentialMovesFrom([i, j])
-          );
-        }
-      }
-    }
-    return potentialMoves;
-  }
-
   getEmptyMove() {
     return new Move({
       start: { x: -1, y: -1 },
@@ -854,68 +697,4 @@ export default class DynamoRules extends ChessRules {
       if (v.p == V.KING) this.kingPos[v.c] = [v.x, v.y];
   }
 
-  getComputerMove() {
-    let moves = this.getAllValidMoves();
-    if (moves.length == 0) return null;
-    // "Search" at depth 1 for now
-    const maxeval = V.INFINITY;
-    const color = this.turn;
-    const emptyMove = {
-      start: { x: -1, y: -1 },
-      end: { x: -1, y: -1 },
-      appear: [],
-      vanish: []
-    };
-    moves.forEach(m => {
-      this.play(m);
-      if (this.turn != color) m.eval = this.evalPosition();
-      else {
-        m.eval = (color == "w" ? -1 : 1) * maxeval;
-        const moves2 = this.getAllValidMoves().concat([emptyMove]);
-        m.next = moves2[0];
-        moves2.forEach(m2 => {
-          this.play(m2);
-          const score = this.getCurrentScore();
-          let mvEval = 0;
-          if (score != "1/2") {
-            if (score != "*") mvEval = (score == "1-0" ? 1 : -1) * maxeval;
-            else mvEval = this.evalPosition();
-          }
-          if (
-            (color == 'w' && mvEval > m.eval) ||
-            (color == 'b' && mvEval < m.eval)
-          ) {
-            m.eval = mvEval;
-            m.next = m2;
-          }
-          this.undo(m2);
-        });
-      }
-      this.undo(m);
-    });
-    moves.sort((a, b) => {
-      return (color == "w" ? 1 : -1) * (b.eval - a.eval);
-    });
-    let candidates = [0];
-    for (let i = 1; i < moves.length && moves[i].eval == moves[0].eval; i++)
-      candidates.push(i);
-    const mIdx = candidates[randInt(candidates.length)];
-    if (!moves[mIdx].next) return moves[mIdx];
-    const move2 = moves[mIdx].next;
-    delete moves[mIdx]["next"];
-    return [moves[mIdx], move2];
-  }
-
-  getNotation(move) {
-    if (move.start.x < 0)
-      // A second move is always required, but may be empty
-      return "-";
-    const initialSquare = V.CoordsToSquare(move.start);
-    const finalSquare = V.CoordsToSquare(move.end);
-    if (move.appear.length == 0)
-      // Pushed or pulled out of the board
-      return initialSquare + "R";
-    return move.appear[0].p.toUpperCase() + initialSquare + finalSquare;
-  }
-
 };
-- 
2.44.0