import { ChessRules, PiPo, Move } from "@/base_rules";
+import { SuicideRules } from "@/variants/Suicide";
+
+export class SuctionRules extends ChessRules {
+
+ static get PawnSpecs() {
+ return Object.assign(
+ {},
+ ChessRules.PawnSpecs,
+ // No promotions:
+ { promotions: [V.PAWN] }
+ );
+ }
+
+ static get HasFlags() {
+ return false;
+ }
-export const VariantRules = class SuctionRules extends ChessRules {
setOtherVariables(fen) {
super.setOtherVariables(fen);
- // Local stack of captures
+ // Local stack of "captures"
this.cmoves = [];
- const cmove = fen.split(" ")[5];
+ const cmove = V.ParseFen(fen).cmove;
if (cmove == "-") this.cmoves.push(null);
else {
this.cmoves.push({
}
}
+ static ParseFen(fen) {
+ return Object.assign(
+ ChessRules.ParseFen(fen),
+ { cmove: fen.split(" ")[4] }
+ );
+ }
+
static IsGoodFen(fen) {
if (!ChessRules.IsGoodFen(fen)) return false;
const fenParts = fen.split(" ");
- if (fenParts.length != 6) return false;
- if (fenParts[5] != "-" && !fenParts[5].match(/^([a-h][1-8]){2}$/))
+ if (fenParts.length != 5) return false;
+ if (fenParts[4] != "-" && !fenParts[4].match(/^([a-h][1-8]){2}$/))
return false;
return true;
}
return mv;
}
- getPotentialPawnMoves([x, y]) {
- const color = this.turn;
+ getEnpassantCaptures([x, y], shiftX) {
let moves = [];
- const [sizeX, sizeY] = [V.size.x, V.size.y];
- const shiftX = color == "w" ? -1 : 1;
- const startRank = color == "w" ? sizeX - 2 : 1;
- const firstRank = color == "w" ? sizeX - 1 : 0;
-
- if (x + shiftX >= 0 && x + shiftX < sizeX) {
- // One square forward
- if (this.board[x + shiftX][y] == V.EMPTY) {
- moves.push(
- this.getBasicMove([x, y], [x + shiftX, y], {
- c: color,
- p: "p"
- })
- );
- if (
- [startRank,firstRank].includes(x) &&
- this.board[x + 2 * shiftX][y] == V.EMPTY
- ) {
- // Two squares jump
- moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
- }
- }
- // Swaps
- for (let shiftY of [-1, 1]) {
- if (
- y + shiftY >= 0 &&
- y + shiftY < sizeY &&
- this.board[x + shiftX][y + shiftY] != V.EMPTY &&
- this.canTake([x, y], [x + shiftX, y + shiftY])
- ) {
- moves.push(
- this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
- c: color,
- p: "p"
- })
- );
- }
- }
- }
-
- // En passant
const Lep = this.epSquares.length;
const epSquare = this.epSquares[Lep - 1]; //always at least one element
if (
Math.abs(epSquare.y - y) == 1
) {
let enpassantMove = this.getBasicMove([x, y], [epSquare.x, epSquare.y]);
- const oppCol = V.GetOppCol(color);
+ const oppCol = V.GetOppCol(this.turn);
enpassantMove.vanish.push({
x: x,
y: epSquare.y,
});
moves.push(enpassantMove);
}
-
return moves;
}
// Does m2 un-do m1 ? (to disallow undoing captures)
oppositeMoves(m1, m2) {
return (
- m1 &&
+ !!m1 &&
m2.vanish.length == 2 &&
m1.start.x == m2.start.x &&
m1.end.x == m2.end.x &&
filterValid(moves) {
if (moves.length == 0) return [];
- const color = this.turn;
return moves.filter(m => {
const L = this.cmoves.length; //at least 1: init from FEN
return !this.oppositeMoves(this.cmoves[L - 1], m);
});
}
- updateVariables(move) {
- super.updateVariables(move);
- if (move.vanish.length == 2) {
- // Was opponent king swapped?
- if (move.vanish[1].p == V.KING)
- this.kingPos[this.turn] = [move.appear[1].x, move.appear[1].y];
- }
+ static GenRandInitFen(randomness) {
+ // Add empty cmove:
+ return SuicideRules.GenRandInitFen(randomness) + " -";
}
- unupdateVariables(move) {
- super.unupdateVariables(move);
- if (move.appear.length == 2) {
- // Was opponent king swapped?
- if (move.appear[1].p == V.KING)
- this.kingPos[move.vanish[1].c] = [move.vanish[1].x,move.vanish[1].y];
- }
+ getCmoveFen() {
+ const L = this.cmoves.length;
+ return (
+ !this.cmoves[L - 1]
+ ? "-"
+ : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) +
+ ChessRules.CoordsToSquare(this.cmoves[L - 1].end)
+ );
}
- static GenRandInitFen() {
- // Add empty cmove:
- return ChessRules.GenRandInitFen() + " -";
+ getFen() {
+ return super.getFen() + " " + this.getCmoveFen();
}
- getFen() {
- const L = this.cmoves.length;
- const cmoveFen = !this.cmoves[L - 1]
- ? "-"
- : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) +
- ChessRules.CoordsToSquare(this.cmoves[L - 1].end);
- return super.getFen() + " " + cmoveFen;
+ getFenForRepeat() {
+ return super.getFenForRepeat() + "_" + this.getCmoveFen();
}
- play(move) {
+ postPlay(move) {
+ super.postPlay(move);
+ if (move.vanish.length == 2) {
+ // Was opponent king swapped?
+ if (move.vanish[1].p == V.KING)
+ this.kingPos[this.turn] = [move.appear[1].x, move.appear[1].y];
+ }
this.cmoves.push(this.getCmove(move));
- super.play(move);
}
- undo(move) {
+ postUndo(move) {
+ super.postUndo(move);
+ if (move.appear.length == 2) {
+ if (move.appear[1].p == V.KING)
+ this.kingPos[move.vanish[1].c] = [move.vanish[1].x, move.vanish[1].y];
+ }
this.cmoves.pop();
- super.undo(move);
}
atLeastOneMove() {
getCurrentScore() {
const color = this.turn;
const kp = this.kingPos[color];
- if (color == "w" && kp[0] == 0)
- return "0-1";
- if (color == "b" && kp[0] == V.size.x - 1)
- return "1-0";
+ if (color == "w" && kp[0] == 0) return "0-1";
+ if (color == "b" && kp[0] == V.size.x - 1) return "1-0";
// King is not on the opposite edge: game not over
return "*";
}
// Very simple criterion for now: kings position
return this.kingPos["w"][0] + this.kingPos["b"][0];
}
+
+ getNotation(move) {
+ // Translate final square
+ const finalSquare = V.CoordsToSquare(move.end);
+
+ const piece = this.getPiece(move.start.x, move.start.y);
+ if (piece == V.PAWN) {
+ // Pawn move
+ let notation = "";
+ if (move.vanish.length == 2) {
+ // Capture
+ const startColumn = V.CoordToColumn(move.start.y);
+ notation = startColumn + "x" + finalSquare;
+ }
+ else notation = finalSquare;
+ return notation;
+ }
+ // Piece movement
+ return (
+ piece.toUpperCase() +
+ (move.vanish.length == 2 ? "x" : "") +
+ finalSquare
+ );
+ }
+
};