}
};
-// NOTE: x coords = top to bottom; y = left to right (from white player perspective)
+// NOTE: x coords = top to bottom; y = left to right
+// (from white player perspective)
export const ChessRules = class ChessRules {
//////////////
// MISC UTILS
return V.CanFlip;
}
- // Some variants require turn indicator
- // (generally when analysis or flip is diabled)
- static get ShowTurn() {
- return !V.CanAnalyze || V.ShowMoves != "all" || !V.CanFlip;
- }
- get showTurn() {
- return V.ShowTurn;
+ // Some variants use click infos:
+ doClick() {
+ return null;
}
static get IMAGE_EXTENSION() {
}
// Path to promotion pieces (usually the same)
- getPPpath(b) {
- return this.getPpath(b);
+ getPPpath(m) {
+ return this.getPpath(m.appear[0].c + m.appear[0].p);
}
// Aggregates flags into one object
const s = move.start,
e = move.end;
if (
- Math.abs(s.x - e.x) == 2 &&
s.y == e.y &&
- move.appear[0].p == V.PAWN
+ Math.abs(s.x - e.x) == 2 &&
+ // Next conditions for variants like Atomic or Rifle, Recycle...
+ (move.appear.length > 0 && move.appear[0].p == V.PAWN) &&
+ (move.vanish.length > 0 && move.vanish[0].p == V.PAWN)
) {
return {
x: (s.x + e.x) / 2,
getCheckSquares(color) {
return (
this.underCheck(color)
- ? [JSON.parse(JSON.stringify(this.kingPos[color]))] //need to duplicate!
+ // kingPos must be duplicated, because it may change:
+ ? [JSON.parse(JSON.stringify(this.kingPos[color]))]
: []
);
}
// Scan board for kings positions
scanKings(fen) {
this.INIT_COL_KING = { w: -1, b: -1 };
- this.kingPos = { w: [-1, -1], b: [-1, -1] }; //squares of white and black king
+ // Squares of white and black king:
+ this.kingPos = { w: [-1, -1], b: [-1, -1] };
const fenRows = V.ParseFen(fen).position.split("/");
const startRow = { 'w': V.size.x - 1, 'b': 0 };
for (let i = 0; i < fenRows.length; i++) {
if (this.castleFlags[c][castleSide] >= V.size.y) continue;
// If this code is reached, rook and king are on initial position
- // NOTE: in some variants this is not a rook, but let's keep variable name
+ // NOTE: in some variants this is not a rook
const rookPos = this.castleFlags[c][castleSide];
- const castlingPiece = this.getPiece(x, rookPos);
- if (this.getColor(x, rookPos) != c)
- // Rook is here but changed color (see Benedict)
+ if (this.board[x][rookPos] == V.EMPTY || this.getColor(x, rookPos) != c)
+ // Rook is not here, or changed color (see Benedict)
continue;
// Nothing on the path of the king ? (and no checks)
+ const castlingPiece = this.getPiece(x, rookPos);
const finDist = finalSquares[castleSide][0] - y;
let step = finDist / Math.max(1, Math.abs(finDist));
i = y;
moves.push(
new Move({
appear: [
- new PiPo({ x: x, y: finalSquares[castleSide][0], p: V.KING, c: c }),
- new PiPo({ x: x, y: finalSquares[castleSide][1], p: castlingPiece, c: c })
+ new PiPo({
+ x: x,
+ y: finalSquares[castleSide][0],
+ p: V.KING,
+ c: c
+ }),
+ new PiPo({
+ x: x,
+ y: finalSquares[castleSide][1],
+ p: castlingPiece,
+ c: c
+ })
],
vanish: [
new PiPo({ x: x, y: y, p: V.KING, c: c }),
}
// Stop at the first move found
+ // TODO: not really, it explores all moves from a square (one is enough).
atLeastOneMove() {
const color = this.turn;
for (let i = 0; i < V.size.x; i++) {
// this.states.push(stateFen);
this.prePlay(move);
- if (V.HasFlags) move.flags = JSON.stringify(this.aggregateFlags()); //save flags (for undo)
+ // Save flags (for undo)
+ if (V.HasFlags) move.flags = JSON.stringify(this.aggregateFlags());
if (V.HasEnpassant) this.epSquares.push(this.getEpSquare(move));
V.PlayOnBoard(this.board, move);
this.turn = V.GetOppCol(this.turn);
const c = V.GetOppCol(this.turn);
const firstRank = (c == "w" ? V.size.x - 1 : 0);
// Update castling flags if rooks are moved
- const oppCol = V.GetOppCol(c);
+ const oppCol = this.turn;
const oppFirstRank = V.size.x - 1 - firstRank;
if (piece == V.KING && move.appear.length > 0)
this.castleFlags[c] = [V.size.y, V.size.y];
return V.INFINITY;
}
- // Search depth: 1,2 for high branching factor, 4 for small (Loser chess, eg.)
+ // Search depth: 1,2 for e.g. higher branching factor, 4 for smaller
static get SEARCH_DEPTH() {
return 3;
}
finalSquare
);
}
+
+ static GetUnambiguousNotation(move) {
+ // Machine-readable format with all the informations about the move
+ return (
+ (!!move.start && V.OnBoard(move.start.x, move.start.y)
+ ? V.CoordsToSquare(move.start)
+ : "-"
+ ) + "." +
+ (!!move.end && V.OnBoard(move.end.x, move.end.y)
+ ? V.CoordsToSquare(move.end)
+ : "-"
+ ) + " " +
+ (!!move.appear && move.appear.length > 0
+ ? move.appear.map(a =>
+ a.c + a.p + V.CoordsToSquare({ x: a.x, y: a.y })).join(".")
+ : "-"
+ ) + "/" +
+ (!!move.vanish && move.vanish.length > 0
+ ? move.vanish.map(a =>
+ a.c + a.p + V.CoordsToSquare({ x: a.x, y: a.y })).join(".")
+ : "-"
+ )
+ );
+ }
};