Teleport2 (no king repositioning) + do not relay some challenges
[vchess.git] / client / src / variants / Teleport.js
diff --git a/client/src/variants/Teleport.js b/client/src/variants/Teleport.js
deleted file mode 100644 (file)
index cbf6a78..0000000
+++ /dev/null
@@ -1,329 +0,0 @@
-import { ChessRules, Move, PiPo } from "@/base_rules";
-import { randInt } from "@/utils/alea";
-
-export class TeleportRules extends ChessRules {
-
-  hoverHighlight([x, y]) {
-    // Testing move validity results in an infinite update loop.
-    // TODO: find a way to test validity anyway.
-    return (this.subTurn == 2 && this.board[x][y] == V.EMPTY);
-  }
-
-  setOtherVariables(fen) {
-    super.setOtherVariables(fen);
-    this.subTurn = 1;
-    this.firstMove = [];
-  }
-
-  canTake([x1, y1], [x2, y2]) {
-    return this.subTurn == 1;
-  }
-
-  canIplay(side, [x, y]) {
-    if (this.subTurn == 2) return (this.board[x][y] == V.EMPTY);
-    return super.canIplay(side, [x, y]);
-  }
-
-  getPPpath(m) {
-    if (
-      m.vanish.length == 2 &&
-      m.appear.length == 1 &&
-      m.vanish[0].c == m.vanish[1].c &&
-      m.appear[0].p == V.KING
-    ) {
-      // Rook teleportation with the king
-      return this.getPpath(m.vanish[1].c + m.vanish[1].p);
-    }
-    return this.getPpath(m.appear[0].c + m.appear[0].p);
-  }
-
-  getPotentialMovesFrom([x, y]) {
-    if (this.subTurn == 1) return super.getPotentialMovesFrom([x, y]);
-    // subTurn == 2: a move is a click, not handled here
-    return [];
-  }
-
-  filterValid(moves) {
-    if (this.subTurn == 2) return super.filterValid(moves);
-    const color = this.turn;
-    return moves.filter(m => {
-      this.play(m);
-      let res = false;
-      if (
-        m.vanish.length == 1 ||
-        m.appear.length == 2 ||
-        m.vanish[0].c != m.vanish[1].c
-      ) {
-        // Standard check:
-        res = !this.underCheck(color);
-      }
-      else {
-        // Self-capture: find landing square not resulting in check
-        outerLoop: for (let i=0; i<8; i++) {
-          for (let j=0; j<8; j++) {
-            if (
-              this.board[i][j] == V.EMPTY &&
-              (
-                m.vanish[1].p != V.PAWN ||
-                i != (color == 'w' ? 0 : 7)
-              )
-            ) {
-              const tMove = new Move({
-                appear: [
-                  new PiPo({
-                    x: i,
-                    y: j,
-                    c: color,
-                    // The dropped piece nature has no importance:
-                    p: V.KNIGHT
-                  })
-                ],
-                vanish: [],
-                start: { x: -1, y: -1 }
-              });
-              this.play(tMove);
-              const moveOk = !this.underCheck(color);
-              this.undo(tMove);
-              if (moveOk) {
-                res = true;
-                break outerLoop;
-              }
-            }
-          }
-        }
-      }
-      this.undo(m);
-      return res;
-    });
-  }
-
-  getAllValidMoves() {
-    if (this.subTurn == 1) return super.getAllValidMoves();
-    // Subturn == 2: only teleportations
-    let moves = [];
-    const L = this.firstMove.length;
-    const color = this.turn;
-    for (let i=0; i<8; i++) {
-      for (let j=0; j<8; j++) {
-        if (
-          this.board[i][j] == V.EMPTY &&
-          (
-            this.firstMove[L-1].vanish[1].p != V.PAWN ||
-            i != (color == 'w' ? 0 : 7)
-          )
-        ) {
-          const tMove = new Move({
-            appear: [
-              new PiPo({
-                x: i,
-                y: j,
-                c: color,
-                p: this.firstMove[L-1].vanish[1].p
-              })
-            ],
-            vanish: [],
-            start: { x: -1, y: -1 }
-          });
-          this.play(tMove);
-          const moveOk = !this.underCheck(color);
-          this.undo(tMove);
-          if (moveOk) moves.push(tMove);
-        }
-      }
-    }
-    return moves;
-  }
-
-  underCheck(color) {
-    if (this.kingPos[color][0] < 0)
-      // King is being moved:
-      return false;
-    return super.underCheck(color);
-  }
-
-  doClick(square) {
-    if (isNaN(square[0])) return null;
-    // If subTurn == 2 && square is empty && !underCheck, then teleport
-    if (this.subTurn == 2 && this.board[square[0]][square[1]] == V.EMPTY) {
-      const L = this.firstMove.length;
-      const color = this.turn;
-      if (
-        this.firstMove[L-1].vanish[1].p == V.PAWN &&
-        square[0] == (color == 'w' ? 0 : 7)
-      ) {
-        // Pawns cannot be teleported on last rank
-        return null;
-      }
-      const tMove = new Move({
-        appear: [
-          new PiPo({
-            x: square[0],
-            y: square[1],
-            c: color,
-            p: this.firstMove[L-1].vanish[1].p
-          })
-        ],
-        vanish: [],
-        start: { x: -1, y: -1 }
-      });
-      this.play(tMove);
-      const moveOk = !this.underCheck(color);
-      this.undo(tMove);
-      if (moveOk) return tMove;
-    }
-    return null;
-  }
-
-  play(move) {
-    move.flags = JSON.stringify(this.aggregateFlags());
-    if (move.vanish.length > 0) {
-      this.epSquares.push(this.getEpSquare(move));
-      this.firstMove.push(move);
-    }
-    V.PlayOnBoard(this.board, move);
-    if (
-      this.subTurn == 2 ||
-      move.vanish.length == 1 ||
-      move.appear.length == 2 ||
-      move.vanish[0].c != move.vanish[1].c
-    ) {
-      this.turn = V.GetOppCol(this.turn);
-      this.subTurn = 1;
-      this.movesCount++;
-    }
-    else this.subTurn = 2;
-    this.postPlay(move);
-  }
-
-  postPlay(move) {
-    if (move.vanish.length == 2 && move.vanish[1].p == V.KING)
-      // A king is moved: temporarily off board
-      this.kingPos[move.vanish[1].c] = [-1, -1];
-    else if (move.appear[0].p == V.KING)
-      this.kingPos[move.appear[0].c] = [move.appear[0].x, move.appear[0].y];
-    this.updateCastleFlags(move);
-  }
-
-  // NOTE: no need to update if castleFlags already off
-  updateCastleFlags(move) {
-    if (move.vanish.length == 0) return;
-    const c = move.vanish[0].c;
-    if (
-      move.vanish.length == 2 &&
-      move.appear.length == 1 &&
-      move.vanish[0].c == move.vanish[1].c
-    ) {
-      // Self-capture: of the king or a rook?
-      if (move.vanish[1].p == V.KING)
-        this.castleFlags[c] = [V.size.y, V.size.y];
-      else if (move.vanish[1].p == V.ROOK) {
-        const firstRank = (c == "w" ? V.size.x - 1 : 0);
-        if (
-          move.end.x == firstRank &&
-          this.castleFlags[c].includes(move.end.y)
-        ) {
-          const flagIdx = (move.end.y == this.castleFlags[c][0] ? 0 : 1);
-          this.castleFlags[c][flagIdx] = V.size.y;
-        }
-      }
-    }
-    // Normal check:
-    super.updateCastleFlags(move, move.vanish[0].p, c);
-  }
-
-  undo(move) {
-    this.disaggregateFlags(JSON.parse(move.flags));
-    if (move.vanish.length > 0) {
-      this.epSquares.pop();
-      this.firstMove.pop();
-    }
-    V.UndoOnBoard(this.board, move);
-    if (this.subTurn == 2) this.subTurn = 1;
-    else {
-      this.turn = V.GetOppCol(this.turn);
-      this.movesCount--;
-      this.subTurn = (move.vanish.length > 0 ? 1 : 2);
-    }
-    this.postUndo(move);
-  }
-
-  postUndo(move) {
-    if (move.vanish.length == 0) {
-      if (move.appear[0].p == V.KING)
-        // A king was teleported
-        this.kingPos[move.appear[0].c] = [-1, -1];
-    }
-    else if (move.vanish.length == 2 && move.vanish[1].p == V.KING)
-      // A king was (self-)taken
-      this.kingPos[move.vanish[1].c] = [move.end.x, move.end.y];
-    else super.postUndo(move);
-  }
-
-  getComputerMove() {
-    let moves = this.getAllValidMoves();
-    if (moves.length == 0) return null;
-    // Custom "search" at depth 1 (for now. TODO?)
-    const maxeval = V.INFINITY;
-    const color = this.turn;
-    const initEval = this.evalPosition();
-    moves.forEach(m => {
-      this.play(m);
-      m.eval = (color == "w" ? -1 : 1) * maxeval;
-      if (
-        m.vanish.length == 2 &&
-        m.appear.length == 1 &&
-        m.vanish[0].c == m.vanish[1].c
-      ) {
-        const moves2 = this.getAllValidMoves();
-        m.next = moves2[0];
-        moves2.forEach(m2 => {
-          this.play(m2);
-          const score = this.getCurrentScore();
-          let mvEval = 0;
-          if (["1-0", "0-1"].includes(score))
-            mvEval = (score == "1-0" ? 1 : -1) * maxeval;
-          else if (score == "*")
-            // Add small fluctuations to avoid dropping pieces always on the
-            // first square available.
-            mvEval = initEval + 0.05 - Math.random() / 10;
-          if (
-            (color == 'w' && mvEval > m.eval) ||
-            (color == 'b' && mvEval < m.eval)
-          ) {
-            m.eval = mvEval;
-            m.next = m2;
-          }
-          this.undo(m2);
-        });
-      }
-      else {
-        const score = this.getCurrentScore();
-        if (score != "1/2") {
-          if (score != "*") m.eval = (score == "1-0" ? 1 : -1) * maxeval;
-          else m.eval = this.evalPosition();
-        }
-      }
-      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.vanish.length > 0) return super.getNotation(move);
-    // Teleportation:
-    const piece =
-      move.appear[0].p != V.PAWN ? move.appear[0].p.toUpperCase() : "";
-    return piece + "@" + V.CoordsToSquare(move.end);
-  }
-
-};