If new live game starts in background, "new game" notify OK but not first move.
NEW VARIANTS:
-https://www.chessvariants.com/mvopponent.dir/hypnotic-chess.html
-https://www.chessvariants.com/mvopponent.dir/mesmer-chess.html
https://www.reddit.com/r/TotemChess/comments/imi3v7/totem_rules/
--> replaced by "Joker" chess --> start on bishop of our color (instead),
moves like a Bishop + Dabbabah, can swap with a piece *on same color* (as a move) at anytime. hmm
--- /dev/null
+../Maxima/bg.svg
\ No newline at end of file
--- /dev/null
+../Maxima/wg.svg
\ No newline at end of file
// Check if FEN describes a board situation correctly
static IsGoodFen(fen) {
-console.log("ddd");
const fenParsed = V.ParseFen(fen);
// 1) Check position
if (!V.IsGoodPosition(fenParsed.position)) return false;
"Mate the knight": "Mate the knight",
"Meet the Mammoth": "Meet the Mammoth",
"Middle battle": "Middle battle",
+ "Mind control (v1)": "Mind control (v1)",
+ "Mind control (v2)": "Mind control (v2)",
"Mongolian Horde (v1)": "Mongolian Horde (v1)",
"Mongolian Horde (v2)": "Mongolian Horde (v2)",
"Move like a knight (v1)": "Move like a knight (v1)",
"Mate the knight": "Matar el caballo",
"Meet the Mammoth": "Conoce al Mamut",
"Middle battle": "Batalla media",
+ "Mind control (v1)": "Control telepático(v1)",
+ "Mind control (v2)": "Control telepático(v2)",
"Mongolian Horde (v1)": "Horda mongol (v1)",
"Mongolian Horde (v2)": "Horda mongol (v2)",
"Move like a knight (v1)": "Moverse como un caballo (v1)",
"Mate the knight": "Matez le cavalier",
"Meet the Mammoth": "Rencontrez le Mammouth",
"Middle battle": "Bataille du milieu",
+ "Mind control (v1)": "Contrôle télépathique (v1)",
+ "Mind control (v2)": "Contrôle télépathique (v2)",
"Mongolian Horde (v1)": "Horde mongole (v1)",
"Mongolian Horde (v2)": "Horde mongole (v2)",
"Move like a knight (v1)": "Bouger comme un cavalier (v1)",
-p.boxed TODO
+p.boxed
+ | You can control enemy pieces which are attacked.
+
+p.
+ Rather than moving one of his own pieces, a player may elect to move any
+ enemy piece that is attacked. The move must be a legal move for the enemy
+ piece, except that the (hypnotized) piece now captures its friends.
+
+p.
+ The hypnotized piece is temporarily frozen and thus cannot be moved by its
+ owner on the next turn.
+
+figure.diagram-container
+ .diagram.diag12
+ | fen:r1bqk1nr/pppp1ppp/2n5/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQK2R:
+ .diagram.diag22
+ | fen:r1bnk1nr/pppp1ppp/8/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQK2R:
+ figcaption Before and after Nxd8 (controlled by bishop on b5).
+
+h3 Source
+
+p
+ | Hypnotic Chess on
+ a(href="https://www.chessvariants.com/mvopponent.dir/hypnotic-chess.html")
+ | chessvariants.com
+ | .
+
+p Inventor: W. D. Troyka (2003)
-p.boxed TODO
+p.boxed
+ | Puedes controlar las piezas enemigas qué son atacadas.
+
+p.
+ En lugar de mover una de sus piezas, un jugador puede decidir mover
+ una pieza del oponente que está atacando. La jugada debe ser legal al punto
+ de vista del adversario, con el detalle que la pieza (hipnotizada)
+ ahora captura sus amigos.
+
+p.
+ La pieza hipnotizada está temporalmente inmovilizada y, por lo tanto,
+ no puede movido por su dueño en el siguiente turno.
+
+figure.diagram-container
+ .diagram.diag12
+ | fen:r1bqk1nr/pppp1ppp/2n5/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQK2R:
+ .diagram.diag22
+ | fen:r1bnk1nr/pppp1ppp/8/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQK2R:
+ figcaption Antes y después de Nxd8 (controlado por el alfil en b5).
+
+h3 Fuente
+
+p
+ | Hypnotic Chess en
+ a(href="https://www.chessvariants.com/mvopponent.dir/hypnotic-chess.html")
+ | chessvariants.com
+ | .
+
+p Inventor: W. D. Troyka (2003)
-p.boxed TODO
+p.boxed
+ | Vous pouvez contrôler les pièces ennemies qui sont attaquées.
+
+p.
+ Plutôt que de déplacer une de ses pièces, un joueur peut décider de
+ déplacer une pièce adverse qu'il attaque. Le coup doit être légal du point
+ de vue de l'adversaire, au détail près que la pièce (hypnotisée) capture
+ désormais ses amis.
+
+p.
+ La pièce hypnotisée est temporairement immobilisée et ne peut donc pas être
+ déplacée par son propriétaire au tour suivant.
+
+figure.diagram-container
+ .diagram.diag12
+ | fen:r1bqk1nr/pppp1ppp/2n5/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQK2R:
+ .diagram.diag22
+ | fen:r1bnk1nr/pppp1ppp/8/1Bb1p3/4P3/5N2/PPPP1PPP/RNBQK2R:
+ figcaption Avant et après Nxd8 (contrôlé par le fou en b5).
+
+h3 Source
+
+p
+ | Hypnotic Chess sur
+ a(href="https://www.chessvariants.com/mvopponent.dir/hypnotic-chess.html")
+ | chessvariants.com
+ | .
+
+p Inventeur : W. D. Troyka (2003)
-p.boxed TODO
+p.boxed
+ | Pieces attacked by the Mesmerist can be controlled.
+
+p.
+ A new piece — the Mesmerist — has the power of mind control,
+ and may elect to move any enemy piece which he observes.
+ The Mesmerist moves like an orthodox queen, but cannot capture (except
+ through mind control). His victim is said to be mesmerized.
+
+p The Mesmerist is represented by an upside-down queen for now.
+
+figure.diagram-container
+ .diagram
+ | fen:rnbqkbnr/pppppppp/3m4/8/8/3M4/PPPPPPPP/RNBQKBNR:
+ figcaption Deterministic initial position.
+
+p.
+ The mesmerized piece is temporarily frozen and thus cannot be moved by its
+ owner on the next turn.
+
+p The game is won by capturing the enemy King or Mesmerist.
+
+h3 Source
+
+p
+ | Mesmer Chess on
+ a(href="https://www.chessvariants.com/mvopponent.dir/mesmer-chess.html")
+ | chessvariants.com
+ | .
+
+p Inventor: W. D. Troyka (2003)
-p.boxed TODO
+p.boxed
+ | Las piezas atacadas por el Hipnotizador pueden controlarse.
+
+p.
+ Una nueva pieza — el Hipnotizador — puede elegir mudarse
+ una pieza enemiga que observa, porque luego controla su mente.
+ El Hipnotizador se mueve como una dama ortodoxa, pero no puede capturar
+ (excepto por telepatía). Se dice que su víctima está hipnotizada.
+
+p El Hipnotizador está representado por una dama al revés por ahora.
+
+figure.diagram-container
+ .diagram
+ | fen:rnbqkbnr/pppppppp/3m4/8/8/3M4/PPPPPPPP/RNBQKBNR:
+ figcaption Posición inicial determinista.
+
+p.
+ La pieza hipnotizada está temporalmente inmovilizada y, por lo tanto,
+ no puede ser movido por su dueño en el siguiente turno.
+
+p El juego se gana capturando al Rey o al Hipnotizador oponente.
+
+h3 Fuente
+
+p
+ | Mesmer Chess en
+ a(href="https://www.chessvariants.com/mvopponent.dir/mesmer-chess.html")
+ | chessvariants.com
+ | .
+
+p Inventor: W. D. Troyka (2003)
-p.boxed TODO
+p.boxed
+ | Les pièces attaquées par l'Hypnotiseur peuvent être contrôlées.
+
+p.
+ Une nouvelle pièce — l'Hypnotiseur — peut choisir de déplacer
+ une pièce ennemie qu'il observe, car il contrôle alors son esprit.
+ L'Hypnotiseur se déplace comme une dame orthodoxe, mais ne peut pas capturer
+ (sauf par télépathie). Sa victime est dite hypnotisée.
+
+p L'Hypnotiseur est représenté par une dame inversé pour l'instant.
+
+figure.diagram-container
+ .diagram
+ | fen:rnbqkbnr/pppppppp/3m4/8/8/3M4/PPPPPPPP/RNBQKBNR:
+ figcaption Position initiale déterministe.
+
+p.
+ La pièce hypnotisée est temporairement immobilisée, et ne peut donc pas
+ être déplacée par son propriétaire au tour suivant.
+
+p La partie est gagnée en capturant le Roi ou l'Hypnotiseur adverse.
+
+h3 Source
+
+p
+ | Mesmer Chess sur
+ a(href="https://www.chessvariants.com/mvopponent.dir/mesmer-chess.html")
+ | chessvariants.com
+ | .
+
+p Inventeur : W. D. Troyka (2003)
"Freecapture",
"Gridolina",
"Hamilton",
+ "Hypnotic",
"Isardam",
"Kingsmaker",
"Magnetic",
"Maharajah",
+ "Mesmer",
"Otage",
"Pacosako",
"Parachute",
"Freecapture",
"Gridolina",
"Hamilton",
+ "Hypnotic",
"Isardam",
"Kingsmaker",
"Magnetic",
"Maharajah",
+ "Mesmer",
"Otage",
"Pacosako",
"Parachute",
"Freecapture",
"Gridolina",
"Hamilton",
+ "Hypnotic",
"Isardam",
"Kingsmaker",
"Magnetic",
"Maharajah",
+ "Mesmer",
"Otage",
"Pacosako",
"Parachute",
--- /dev/null
+import { ChessRules } from "@/base_rules";
+
+export class HypnoticRules extends ChessRules {
+
+ static IsGoodFen(fen) {
+ if (!ChessRules.IsGoodFen(fen)) return false;
+ const fenParsed = V.ParseFen(fen);
+ // 5) Check arrival of last hypnotizing move (if any)
+ if (
+ !fenParsed.hSquare ||
+ (fenParsed.hSquare != "-" && !fenParsed.hSquare.match(/^[a-h][1-8]$/))
+ ) {
+ return false;
+ }
+ return true;
+ }
+
+ static ParseFen(fen) {
+ const fenParts = fen.split(" ");
+ return Object.assign(
+ { hSquare: fenParts[5] },
+ ChessRules.ParseFen(fen)
+ );
+ }
+
+ static GenRandInitFen(randomness) {
+ return ChessRules.GenRandInitFen(randomness) + " -";
+ }
+
+ setOtherVariables(fen) {
+ super.setOtherVariables(fen);
+ const parsedFen = V.ParseFen(fen);
+ this.hSquares = [
+ parsedFen.hSquare != "-"
+ ? V.SquareToCoords(parsedFen.hSquare)
+ : null
+ ];
+ }
+
+ getFen() {
+ const L = this.hSquares.length;
+ return (
+ super.getFen() + " " +
+ (!this.hSquares[L-1] ? "-" : V.CoordsToSquare(this.hSquares[L-1]))
+ );
+ }
+
+ canIplay(side) {
+ // Wrong, but sufficient approximation let's say
+ return this.turn == side;
+ }
+
+ canTake([x1, y1], [x2, y2]) {
+ const c = this.turn;
+ const c1 = this.getColor(x1, y1);
+ const c2 = this.getColor(x2, y2);
+ return (c == c1 && c1 != c2) || (c != c1 && c1 == c2);
+ }
+
+ getPotentialMovesFrom([x, y]) {
+ const L = this.hSquares.length;
+ const lh = this.hSquares[L-1];
+ if (!!lh && lh.x == x && lh.y == y) return [];
+ const c = this.getColor(x, y);
+ if (c == this.turn) return super.getPotentialMovesFrom([x, y]);
+ // Playing opponent's pieces: hypnotizing moves. Allowed?
+ if (!this.isAttacked([x, y], this.turn)) return [];
+ const moves =
+ this.getPiece(x, y) == V.KING
+ // No castling with enemy king (...yes, should eat it but...)
+ ? super.getSlideNJumpMoves(
+ [x, y], V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep")
+ : super.getPotentialMovesFrom([x, y]);
+ return moves;
+ }
+
+ getEnpassantCaptures([x, y], shiftX) {
+ const Lep = this.epSquares.length;
+ const epSquare = this.epSquares[Lep - 1]; //always at least one element
+ let enpassantMove = null;
+ const c = this.getColor(x, y);
+ if (
+ !!epSquare &&
+ epSquare.x == x + shiftX &&
+ Math.abs(epSquare.y - y) == 1 &&
+ // Next conditions to avoid capturing self hypnotized pawns:
+ this.board[x][epSquare.y] != V.EMPTY &&
+ this.getColor(x, epSquare.y) != c //TODO: probably redundant
+ ) {
+ enpassantMove = this.getBasicMove([x, y], [epSquare.x, epSquare.y]);
+ enpassantMove.vanish.push({
+ x: x,
+ y: epSquare.y,
+ p: this.board[x][epSquare.y].charAt(1),
+ c: this.getColor(x, epSquare.y)
+ });
+ }
+ return !!enpassantMove ? [enpassantMove] : [];
+ }
+
+ // TODO: avoid following code duplication, by using getColor()
+ // instead of this.turn at the beginning of 2 next methods
+ addPawnMoves([x1, y1], [x2, y2], moves, promotions) {
+ let finalPieces = [V.PAWN];
+ const color = this.getColor(x1, y1);
+ const lastRank = (color == "w" ? 0 : V.size.x - 1);
+ if (x2 == lastRank) finalPieces = V.PawnSpecs.promotions;
+ let tr = null;
+ for (let piece of finalPieces) {
+ tr = (piece != V.PAWN ? { c: color, p: piece } : null);
+ moves.push(this.getBasicMove([x1, y1], [x2, y2], tr));
+ }
+ }
+
+ getPotentialPawnMoves([x, y], promotions) {
+ const color = this.getColor(x, y);
+ const [sizeX, sizeY] = [V.size.x, V.size.y];
+ const forward = (color == 'w' ? -1 : 1);
+
+ let moves = [];
+ if (x + forward >= 0 && x + forward < sizeX) {
+ if (this.board[x + forward][y] == V.EMPTY) {
+ this.addPawnMoves([x, y], [x + forward, y], moves, promotions);
+ if (
+ ((color == 'w' && x == 6) || (color == 'b' && x == 1)) &&
+ this.board[x + 2 * forward][y] == V.EMPTY
+ ) {
+ moves.push(this.getBasicMove([x, y], [x + 2 * forward, y]));
+ }
+ }
+ for (let shiftY of [-1, 1]) {
+ if (
+ y + shiftY >= 0 && y + shiftY < sizeY &&
+ this.board[x + forward][y + shiftY] != V.EMPTY &&
+ this.canTake([x, y], [x + forward, y + shiftY])
+ ) {
+ this.addPawnMoves(
+ [x, y], [x + forward, y + shiftY],
+ moves, promotions
+ );
+ }
+ }
+ }
+ Array.prototype.push.apply(moves,
+ this.getEnpassantCaptures([x, y], forward));
+ return moves;
+ }
+
+ postPlay(move) {
+ super.postPlay(move);
+ if (move.vanish[0].c == this.turn)
+ this.hSquares.push({ x: move.appear[0].x, y: move.appear[0].y });
+ else this.hSquares.push(null);
+ if (move.vanish.length == 2 && move.vanish[1].p == V.KING)
+ this.kingPos[move.vanish[1].c] = [-1, -1];
+ }
+ postUndo(move) {
+ super.postUndo(move);
+ this.hSquares.pop();
+ if (move.vanish.length == 2 && move.vanish[1].p == V.KING)
+ this.kingPos[move.vanish[1].c] = [move.vanish[1].x, move.vanish[1].y];
+ }
+
+ getCheckSquares() {
+ return [];
+ }
+ filterValid(moves) {
+ return moves;
+ }
+
+ getCurrentScore() {
+ const c = this.turn;
+ if (this.kingPos[c][0] < 0) return (c == 'w' ? "0-1" : "1-0");
+ return "*";
+ }
+
+ static get SEARCH_DEPTH() {
+ return 2;
+ }
+
+};
--- /dev/null
+import { ChessRules } from "@/base_rules";
+import { Antiking2Rules } from "@/variants/Antiking2";
+
+export class MesmerRules extends ChessRules {
+
+ static IsGoodFen(fen) {
+ if (!ChessRules.IsGoodFen(fen)) return false;
+ const fenParsed = V.ParseFen(fen);
+ // 5) Check arrival of last hypnotizing move (if any)
+ if (
+ !fenParsed.hSquare ||
+ (fenParsed.hSquare != "-" && !fenParsed.hSquare.match(/^[a-h][1-8]$/))
+ ) {
+ return false;
+ }
+ return true;
+ }
+
+ static get MESMERIST() {
+ return 'm';
+ }
+
+ static get PIECES() {
+ return ChessRules.PIECES.concat([V.MESMERIST]);
+ }
+
+ getPpath(b) {
+ return (b.charAt(1) == 'm' ? "Mesmer/" : "") + b;
+ }
+
+ static ParseFen(fen) {
+ const fenParts = fen.split(" ");
+ return Object.assign(
+ { hSquare: fenParts[5] },
+ ChessRules.ParseFen(fen)
+ );
+ }
+
+ static GenRandInitFen(randomness) {
+ const antikingFen = Antiking2Rules.GenRandInitFen(randomness);
+ return antikingFen.replace('a', 'M').replace('A', 'm') + " -";
+ }
+
+ setOtherVariables(fen) {
+ super.setOtherVariables(fen);
+ const parsedFen = V.ParseFen(fen);
+ this.hSquares = [
+ parsedFen.hSquare != "-"
+ ? V.SquareToCoords(parsedFen.hSquare)
+ : null
+ ];
+ }
+
+ scanKings(fen) {
+ super.scanKings(fen);
+ // Squares of white and black mesmerist:
+ this.mesmerPos = { w: [-1, -1], b: [-1, -1] };
+ const fenRows = V.ParseFen(fen).position.split("/");
+ for (let i = 0; i < fenRows.length; i++) {
+ let k = 0;
+ for (let j = 0; j < fenRows[i].length; j++) {
+ switch (fenRows[i].charAt(j)) {
+ case "m":
+ this.mesmerPos["b"] = [i, k];
+ break;
+ case "M":
+ this.mesmerPos["w"] = [i, k];
+ break;
+ default: {
+ const num = parseInt(fenRows[i].charAt(j), 10);
+ if (!isNaN(num)) k += num - 1;
+ }
+ }
+ k++;
+ }
+ }
+ }
+
+ getFen() {
+ const L = this.hSquares.length;
+ return (
+ super.getFen() + " " +
+ (!this.hSquares[L-1] ? "-" : V.CoordsToSquare(this.hSquares[L-1]))
+ );
+ }
+
+ canIplay(side) {
+ // Wrong, but sufficient approximation let's say
+ return this.turn == side;
+ }
+
+ canTake([x1, y1], [x2, y2]) {
+ const c = this.turn;
+ const c1 = this.getColor(x1, y1);
+ const c2 = this.getColor(x2, y2);
+ return (c == c1 && c1 != c2) || (c != c1 && c1 == c2);
+ }
+
+ getPotentialMovesFrom([x, y]) {
+ const L = this.hSquares.length;
+ const lh = this.hSquares[L-1];
+ if (!!lh && lh.x == x && lh.y == y) return [];
+ const c = this.getColor(x, y);
+ const piece = this.getPiece(x, y);
+ if (c == this.turn) {
+ if (piece == V.MESMERIST) return this.getPotentialMesmeristMoves([x, y]);
+ return super.getPotentialMovesFrom([x, y]);
+ }
+ // Playing opponent's pieces: hypnotizing moves. Allowed?
+ if (piece == V.MESMERIST || !this.isAttackedByMesmerist([x, y], this.turn))
+ return [];
+ const moves =
+ piece == V.KING
+ // No castling with enemy king (...yes, should eat it but...)
+ ? super.getSlideNJumpMoves(
+ [x, y], V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep")
+ : super.getPotentialMovesFrom([x, y]);
+ return moves;
+ }
+
+ // Moves like a queen without capturing
+ getPotentialMesmeristMoves([x, y]) {
+ const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
+ let moves = [];
+ for (let step of steps) {
+ let i = x + step[0];
+ let j = y + step[1];
+ while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
+ moves.push(this.getBasicMove([x, y], [i, j]));
+ i += step[0];
+ j += step[1];
+ }
+ }
+ return moves;
+ }
+
+ isAttackedByMesmerist(sq, color) {
+ return (
+ super.isAttackedBySlideNJump(
+ sq, color, V.MESMERIST, V.steps[V.ROOK].concat(V.steps[V.BISHOP]))
+ );
+ }
+
+ getEnpassantCaptures([x, y], shiftX) {
+ const Lep = this.epSquares.length;
+ const epSquare = this.epSquares[Lep - 1]; //always at least one element
+ let enpassantMove = null;
+ const c = this.getColor(x, y);
+ if (
+ !!epSquare &&
+ epSquare.x == x + shiftX &&
+ Math.abs(epSquare.y - y) == 1 &&
+ // Next conditions to avoid capturing self hypnotized pawns:
+ this.board[x][epSquare.y] != V.EMPTY &&
+ this.getColor(x, epSquare.y) != c //TODO: probably redundant
+ ) {
+ enpassantMove = this.getBasicMove([x, y], [epSquare.x, epSquare.y]);
+ enpassantMove.vanish.push({
+ x: x,
+ y: epSquare.y,
+ p: this.board[x][epSquare.y].charAt(1),
+ c: this.getColor(x, epSquare.y)
+ });
+ }
+ return !!enpassantMove ? [enpassantMove] : [];
+ }
+
+ // TODO: avoid following code duplication, by using getColor()
+ // instead of this.turn at the beginning of 2 next methods
+ addPawnMoves([x1, y1], [x2, y2], moves, promotions) {
+ let finalPieces = [V.PAWN];
+ const color = this.getColor(x1, y1);
+ const lastRank = (color == "w" ? 0 : V.size.x - 1);
+ if (x2 == lastRank) finalPieces = V.PawnSpecs.promotions;
+ let tr = null;
+ for (let piece of finalPieces) {
+ tr = (piece != V.PAWN ? { c: color, p: piece } : null);
+ moves.push(this.getBasicMove([x1, y1], [x2, y2], tr));
+ }
+ }
+
+ getPotentialPawnMoves([x, y], promotions) {
+ const color = this.getColor(x, y);
+ const [sizeX, sizeY] = [V.size.x, V.size.y];
+ const forward = (color == 'w' ? -1 : 1);
+
+ let moves = [];
+ if (x + forward >= 0 && x + forward < sizeX) {
+ if (this.board[x + forward][y] == V.EMPTY) {
+ this.addPawnMoves([x, y], [x + forward, y], moves, promotions);
+ if (
+ ((color == 'w' && x == 6) || (color == 'b' && x == 1)) &&
+ this.board[x + 2 * forward][y] == V.EMPTY
+ ) {
+ moves.push(this.getBasicMove([x, y], [x + 2 * forward, y]));
+ }
+ }
+ for (let shiftY of [-1, 1]) {
+ if (
+ y + shiftY >= 0 && y + shiftY < sizeY &&
+ this.board[x + forward][y + shiftY] != V.EMPTY &&
+ this.canTake([x, y], [x + forward, y + shiftY])
+ ) {
+ this.addPawnMoves(
+ [x, y], [x + forward, y + shiftY],
+ moves, promotions
+ );
+ }
+ }
+ }
+ Array.prototype.push.apply(moves,
+ this.getEnpassantCaptures([x, y], forward));
+ return moves;
+ }
+
+ postPlay(move) {
+ super.postPlay(move);
+ if (move.vanish[0].p == V.MESMERIST)
+ this.mesmerPos[move.vanish[0].c] = [move.appear[0].x, move.appear[0].y];
+ if (move.vanish[0].c == this.turn)
+ this.hSquares.push({ x: move.appear[0].x, y: move.appear[0].y });
+ else this.hSquares.push(null);
+ if (move.vanish.length == 2) {
+ if (move.vanish[1].p == V.KING)
+ this.kingPos[move.vanish[1].c] = [-1, -1];
+ else if (move.vanish[1].p == V.MESMERIST)
+ this.mesmerPos[move.vanish[1].c] = [-1, -1]
+ }
+ }
+ postUndo(move) {
+ super.postUndo(move);
+ if (move.vanish[0].p == V.MESMERIST)
+ this.mesmerPos[move.vanish[0].c] = [move.vanish[0].x, move.vanish[0].y];
+ this.hSquares.pop();
+ if (move.vanish.length == 2) {
+ const v = move.vanish[1];
+ if (v.p == V.KING)
+ this.kingPos[v.c] = [v.x, v.y];
+ else if (v.p == V.MESMERIST)
+ this.mesmerPos[v.c] = [v.x, v.y];
+ }
+ }
+
+ getCheckSquares() {
+ return [];
+ }
+ filterValid(moves) {
+ return moves;
+ }
+
+ getCurrentScore() {
+ const c = this.turn;
+ if (this.kingPos[c][0] < 0) return (c == 'w' ? "0-1" : "1-0");
+ if (this.mesmerPos[c][0] < 0) return (c == 'w' ? "0-1" : "1-0");
+ return "*";
+ }
+
+ static get SEARCH_DEPTH() {
+ return 2;
+ }
+
+};
('Hamilton', 'Walk on a graph'),
('Hoppelpoppel', 'Knibis and Bisknis'),
('Horde', 'A pawns cloud'),
+ ('Hypnotic', 'Mind control (v1)'),
('Interweave', 'Interweaved colorbound teams'),
('Isardam', 'No paralyzed pieces'),
('Janggi', 'Korean Chess'),
('Makpong', 'Thai Chess (v2)'),
('Makruk', 'Thai Chess (v1)'),
('Maxima', 'Occupy the enemy palace'),
+ ('Mesmer', 'Mind control (v2)'),
('Minishogi', 'Shogi 5 x 5'),
('Minixiangqi', 'Xiangqi 7 x 7'),
('Monochrome', 'All of the same color'),