{
this.moves = moves;
// Use fen string to initialize variables, flags and board
- this.board = VariantRules.GetBoard(fen);
+ this.board = V.GetBoard(fen);
this.setFlags(fen);
this.initVariables(fen);
}
k++;
}
}
- const epSq = this.moves.length > 0 ? this.getEpSquare(this.lastMove) : undefined;
+ const epSq = (this.moves.length > 0 ? this.getEpSquare(this.lastMove) : undefined);
this.epSquares = [ epSq ];
}
static GetBoard(fen)
{
let rows = fen.split(" ")[0].split("/");
- const [sizeX,sizeY] = VariantRules.size;
- let board = doubleArray(sizeX, sizeY, "");
+ let board = doubleArray(V.size.x, V.size.y, "");
for (let i=0; i<rows.length; i++)
{
let j = 0;
if (!isNaN(num))
j += num; //just shift j
else //something at position i,j
- board[i][j++] = VariantRules.fen2board(character);
+ board[i][j++] = V.fen2board(character);
}
}
return board;
///////////////////
// GETTERS, SETTERS
- static get size() { return [8,8]; }
+ static get size() { return {x:8, y:8}; }
+
// Two next functions return 'undefined' if called on empty square
getColor(i,j) { return this.board[i][j].charAt(0); }
getPiece(i,j) { return this.board[i][j].charAt(1); }
// Color
- getOppCol(color) { return color=="w" ? "b" : "w"; }
+ getOppCol(color) { return (color=="w" ? "b" : "w"); }
get lastMove() {
const L = this.moves.length;
- return L>0 ? this.moves[L-1] : null;
+ return (L>0 ? this.moves[L-1] : null);
}
+
get turn() {
- return this.moves.length%2==0 ? 'w' : 'b';
+ return (this.moves.length%2==0 ? 'w' : 'b');
}
// Pieces codes
getEpSquare(move)
{
const [sx,sy,ex] = [move.start.x,move.start.y,move.end.x];
- if (this.getPiece(sx,sy) == VariantRules.PAWN && Math.abs(sx - ex) == 2)
+ if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) == 2)
{
return {
x: (sx + ex)/2,
// Can thing on square1 take thing on square2
canTake([x1,y1], [x2,y2])
{
- return this.getColor(x1,y1) != this.getColor(x2,y2);
+ return this.getColor(x1,y1) !== this.getColor(x2,y2);
}
///////////////////
{
switch (this.getPiece(x,y))
{
- case VariantRules.PAWN:
+ case V.PAWN:
return this.getPotentialPawnMoves([x,y]);
- case VariantRules.ROOK:
+ case V.ROOK:
return this.getPotentialRookMoves([x,y]);
- case VariantRules.KNIGHT:
+ case V.KNIGHT:
return this.getPotentialKnightMoves([x,y]);
- case VariantRules.BISHOP:
+ case V.BISHOP:
return this.getPotentialBishopMoves([x,y]);
- case VariantRules.QUEEN:
+ case V.QUEEN:
return this.getPotentialQueenMoves([x,y]);
- case VariantRules.KING:
+ case V.KING:
return this.getPotentialKingMoves([x,y]);
}
}
});
// The opponent piece disappears if we take it
- if (this.board[ex][ey] != VariantRules.EMPTY)
+ if (this.board[ex][ey] != V.EMPTY)
{
mv.vanish.push(
new PiPo({
return mv;
}
+ // Is (x,y) on the chessboard?
+ static OnBoard(x,y)
+ {
+ return (x>=0 && x<V.size.x && y>=0 && y<V.size.y);
+ }
+
// Generic method to find possible moves of non-pawn pieces ("sliding or jumping")
getSlideNJumpMoves([x,y], steps, oneStep)
{
const color = this.getColor(x,y);
let moves = [];
- const [sizeX,sizeY] = VariantRules.size;
outerLoop:
for (let step of steps)
{
let i = x + step[0];
let j = y + step[1];
- while (i>=0 && i<sizeX && j>=0 && j<sizeY
- && this.board[i][j] == VariantRules.EMPTY)
+ while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY)
{
moves.push(this.getBasicMove([x,y], [i,j]));
if (oneStep !== undefined)
i += step[0];
j += step[1];
}
- if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.canTake([x,y], [i,j]))
+ if (V.OnBoard(i,j) && this.canTake([x,y], [i,j]))
moves.push(this.getBasicMove([x,y], [i,j]));
}
return moves;
{
const color = this.turn;
let moves = [];
- const V = VariantRules;
- const [sizeX,sizeY] = V.size;
+ const [sizeX,sizeY] = [V.size.x,V.size.y];
const shift = (color == "w" ? -1 : 1);
const firstRank = (color == 'w' ? sizeX-1 : 0);
const startRank = (color == "w" ? sizeX-2 : 1);
}
}
// Captures
- if (y>0 && this.canTake([x,y], [x+shift,y-1])
- && this.board[x+shift][y-1] != V.EMPTY)
+ if (y>0 && this.board[x+shift][y-1] != V.EMPTY
+ && this.canTake([x,y], [x+shift,y-1]))
{
moves.push(this.getBasicMove([x,y], [x+shift,y-1]));
}
- if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
- && this.board[x+shift][y+1] != V.EMPTY)
+ if (y<sizeY-1 && this.board[x+shift][y+1] != V.EMPTY
+ && this.canTake([x,y], [x+shift,y+1]))
{
moves.push(this.getBasicMove([x,y], [x+shift,y+1]));
}
if (this.board[x+shift][y] == V.EMPTY)
moves.push(this.getBasicMove([x,y], [x+shift,y], {c:pawnColor,p:p}));
// Captures
- if (y>0 && this.canTake([x,y], [x+shift,y-1])
- && this.board[x+shift][y-1] != V.EMPTY)
+ if (y>0 && this.board[x+shift][y-1] != V.EMPTY
+ && this.canTake([x,y], [x+shift,y-1]))
{
moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:pawnColor,p:p}));
}
- if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
- && this.board[x+shift][y+1] != V.EMPTY)
+ if (y<sizeY-1 && this.board[x+shift][y+1] != V.EMPTY
+ && this.canTake([x,y], [x+shift,y+1]))
{
moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:pawnColor,p:p}));
}
// En passant
const Lep = this.epSquares.length;
- const epSquare = Lep>0 ? this.epSquares[Lep-1] : undefined;
+ const epSquare = (Lep>0 ? this.epSquares[Lep-1] : undefined);
if (!!epSquare && epSquare.x == x+shift && Math.abs(epSquare.y - y) == 1)
{
- let epStep = epSquare.y - y;
- var enpassantMove = this.getBasicMove([x,y], [x+shift,y+epStep]);
+ const epStep = epSquare.y - y;
+ let enpassantMove = this.getBasicMove([x,y], [x+shift,y+epStep]);
enpassantMove.vanish.push({
x: x,
y: y+epStep,
// What are the rook moves from square x,y ?
getPotentialRookMoves(sq)
{
- return this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.ROOK]);
+ return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]);
}
// What are the knight moves from square x,y ?
getPotentialKnightMoves(sq)
{
- return this.getSlideNJumpMoves(
- sq, VariantRules.steps[VariantRules.KNIGHT], "oneStep");
+ return this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep");
}
// What are the bishop moves from square x,y ?
getPotentialBishopMoves(sq)
{
- return this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.BISHOP]);
+ return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]);
}
// What are the queen moves from square x,y ?
getPotentialQueenMoves(sq)
{
- const V = VariantRules;
return this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]));
}
// What are the king moves from square x,y ?
getPotentialKingMoves(sq)
{
- const V = VariantRules;
// Initialize with normal moves
let moves = this.getSlideNJumpMoves(sq,
V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
getCastleMoves([x,y])
{
const c = this.getColor(x,y);
- const [sizeX,sizeY] = VariantRules.size;
- if (x != (c=="w" ? sizeX-1 : 0) || y != this.INIT_COL_KING[c])
+ if (x != (c=="w" ? V.size.x-1 : 0) || y != this.INIT_COL_KING[c])
return []; //x isn't first rank, or king has moved (shortcut)
- const V = VariantRules;
-
// Castling ?
const oppCol = this.getOppCol(c);
let moves = [];
let i = 0;
- const finalSquares = [ [2,3], [sizeY-2,sizeY-3] ]; //king, then rook
+ const finalSquares = [ [2,3], [V.size.y-2,V.size.y-3] ]; //king, then rook
castlingCheck:
for (let castleSide=0; castleSide < 2; castleSide++) //large, then small
{
const color = this.turn;
const oppCol = this.getOppCol(color);
let potentialMoves = [];
- const [sizeX,sizeY] = VariantRules.size;
- for (let i=0; i<sizeX; i++)
+ for (let i=0; i<V.size.x; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
// Next condition "!= oppCol" = harmless hack to work with checkered variant
- if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) != oppCol)
+ if (this.board[i][j] != V.EMPTY && this.getColor(i,j) != oppCol)
Array.prototype.push.apply(potentialMoves, this.getPotentialMovesFrom([i,j]));
}
}
{
const color = this.turn;
const oppCol = this.getOppCol(color);
- const [sizeX,sizeY] = VariantRules.size;
- for (let i=0; i<sizeX; i++)
+ for (let i=0; i<V.size.x; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
- if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) != oppCol)
+ if (this.board[i][j] != V.EMPTY && this.getColor(i,j) != oppCol)
{
const moves = this.getPotentialMovesFrom([i,j]);
if (moves.length > 0)
// Is square x,y attacked by 'colors' pawns ?
isAttackedByPawn([x,y], colors)
{
- const [sizeX,sizeY] = VariantRules.size;
for (let c of colors)
{
let pawnShift = (c=="w" ? 1 : -1);
- if (x+pawnShift>=0 && x+pawnShift<sizeX)
+ if (x+pawnShift>=0 && x+pawnShift<V.size.x)
{
for (let i of [-1,1])
{
- if (y+i>=0 && y+i<sizeY && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN
+ if (y+i>=0 && y+i<V.size.y && this.getPiece(x+pawnShift,y+i)==V.PAWN
&& this.getColor(x+pawnShift,y+i)==c)
{
return true;
// Is square x,y attacked by 'colors' rooks ?
isAttackedByRook(sq, colors)
{
- return this.isAttackedBySlideNJump(sq, colors,
- VariantRules.ROOK, VariantRules.steps[VariantRules.ROOK]);
+ return this.isAttackedBySlideNJump(sq, colors, V.ROOK, V.steps[V.ROOK]);
}
// Is square x,y attacked by 'colors' knights ?
isAttackedByKnight(sq, colors)
{
return this.isAttackedBySlideNJump(sq, colors,
- VariantRules.KNIGHT, VariantRules.steps[VariantRules.KNIGHT], "oneStep");
+ V.KNIGHT, V.steps[V.KNIGHT], "oneStep");
}
// Is square x,y attacked by 'colors' bishops ?
isAttackedByBishop(sq, colors)
{
- return this.isAttackedBySlideNJump(sq, colors,
- VariantRules.BISHOP, VariantRules.steps[VariantRules.BISHOP]);
+ return this.isAttackedBySlideNJump(sq, colors, V.BISHOP, V.steps[V.BISHOP]);
}
// Is square x,y attacked by 'colors' queens ?
isAttackedByQueen(sq, colors)
{
- const V = VariantRules;
return this.isAttackedBySlideNJump(sq, colors, V.QUEEN,
V.steps[V.ROOK].concat(V.steps[V.BISHOP]));
}
// Is square x,y attacked by 'colors' king(s) ?
isAttackedByKing(sq, colors)
{
- const V = VariantRules;
return this.isAttackedBySlideNJump(sq, colors, V.KING,
V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
}
// is x,y attacked by a piece of color in array 'colors' ?
isAttackedBySlideNJump([x,y], colors, piece, steps, oneStep)
{
- const [sizeX,sizeY] = VariantRules.size;
for (let step of steps)
{
let rx = x+step[0], ry = y+step[1];
- while (rx>=0 && rx<sizeX && ry>=0 && ry<sizeY
- && this.board[rx][ry] == VariantRules.EMPTY && !oneStep)
+ while (V.OnBoard(rx,ry) && this.board[rx][ry] == V.EMPTY && !oneStep)
{
rx += step[0];
ry += step[1];
}
- if (rx>=0 && rx<sizeX && ry>=0 && ry<sizeY
- && this.board[rx][ry] != VariantRules.EMPTY
- && this.getPiece(rx,ry) == piece && colors.includes(this.getColor(rx,ry)))
+ if (V.OnBoard(rx,ry) && this.getPiece(rx,ry) === piece
+ && colors.includes(this.getColor(rx,ry)))
{
return true;
}
static PlayOnBoard(board, move)
{
for (let psq of move.vanish)
- board[psq.x][psq.y] = VariantRules.EMPTY;
+ board[psq.x][psq.y] = V.EMPTY;
for (let psq of move.appear)
board[psq.x][psq.y] = psq.c + psq.p;
}
static UndoOnBoard(board, move)
{
for (let psq of move.appear)
- board[psq.x][psq.y] = VariantRules.EMPTY;
+ board[psq.x][psq.y] = V.EMPTY;
for (let psq of move.vanish)
board[psq.x][psq.y] = psq.c + psq.p;
}
updateVariables(move)
{
const piece = this.getPiece(move.start.x,move.start.y);
- const c = this.getColor(move.start.x,move.start.y);
- const [sizeX,sizeY] = VariantRules.size;
- const firstRank = (c == "w" ? sizeX-1 : 0);
+ const c = this.turn;
+ const firstRank = (c == "w" ? V.size.x-1 : 0);
// Update king position + flags
- if (piece == VariantRules.KING && move.appear.length > 0)
+ if (piece == V.KING && move.appear.length > 0)
{
this.kingPos[c][0] = move.appear[0].x;
this.kingPos[c][1] = move.appear[0].y;
return;
}
const oppCol = this.getOppCol(c);
- const oppFirstRank = (sizeX-1) - firstRank;
+ const oppFirstRank = (V.size.x-1) - firstRank;
if (move.start.x == firstRank //our rook moves?
&& this.INIT_COL_ROOK[c].includes(move.start.y))
{
{
// (Potentially) Reset king position
const c = this.getColor(move.start.x,move.start.y);
- if (this.getPiece(move.start.x,move.start.y) == VariantRules.KING)
+ if (this.getPiece(move.start.x,move.start.y) == V.KING)
this.kingPos[c] = [move.start.x, move.start.y];
}
this.updateVariables(move);
this.moves.push(move);
this.epSquares.push( this.getEpSquare(move) );
- VariantRules.PlayOnBoard(this.board, move);
+ V.PlayOnBoard(this.board, move);
if (!!ingame)
move.hash = this.getHashState();
undo(move)
{
- VariantRules.UndoOnBoard(this.board, move);
+ V.UndoOnBoard(this.board, move);
this.epSquares.pop();
this.moves.pop();
this.unupdateVariables(move);
static get THRESHOLD_MATE() {
// At this value or above, the game is over
- return VariantRules.INFINITY;
+ return V.INFINITY;
}
static get SEARCH_DEPTH() {
// NOTE: works also for extinction chess because depth is 3...
getComputerMove()
{
- const maxeval = VariantRules.INFINITY;
+ const maxeval = V.INFINITY;
const color = this.turn;
// Some variants may show a bigger moves list to the human (Switching),
// thus the argument "computer" below (which is generally ignored)
for (let i of _.shuffle(_.range(moves1.length)))
{
this.play(moves1[i]);
- const finish = (Math.abs(this.evalPosition()) >= VariantRules.THRESHOLD_MATE);
+ let finish = (Math.abs(this.evalPosition()) >= V.THRESHOLD_MATE);
+ if (!finish && !this.atLeastOneMove())
+ {
+ // Try mate (for other variants)
+ const score = this.checkGameEnd();
+ if (score != "1/2")
+ finish = true;
+ }
this.undo(moves1[i]);
if (finish)
return moves1[i];
const timeStart = Date.now();
// Skip depth 3+ if we found a checkmate (or if we are checkmated in 1...)
- if (VariantRules.SEARCH_DEPTH >= 3
- && Math.abs(moves1[0].eval) < VariantRules.THRESHOLD_MATE)
+ if (V.SEARCH_DEPTH >= 3 && Math.abs(moves1[0].eval) < V.THRESHOLD_MATE)
{
for (let i=0; i<moves1.length; i++)
{
this.play(moves1[i]);
// 0.1 * oldEval : heuristic to avoid some bad moves (not all...)
moves1[i].eval = 0.1*moves1[i].eval +
- this.alphabeta(VariantRules.SEARCH_DEPTH-1, -maxeval, maxeval);
+ this.alphabeta(V.SEARCH_DEPTH-1, -maxeval, maxeval);
this.undo(moves1[i]);
}
moves1.sort( (a,b) => { return (color=="w" ? 1 : -1) * (b.eval - a.eval); });
alphabeta(depth, alpha, beta)
{
- const maxeval = VariantRules.INFINITY;
+ const maxeval = V.INFINITY;
const color = this.turn;
if (!this.atLeastOneMove())
{
evalPosition()
{
- const [sizeX,sizeY] = VariantRules.size;
let evaluation = 0;
// Just count material for now
- for (let i=0; i<sizeX; i++)
+ for (let i=0; i<V.size.x; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
- if (this.board[i][j] != VariantRules.EMPTY)
+ if (this.board[i][j] != V.EMPTY)
{
const sign = this.getColor(i,j) == "w" ? 1 : -1;
- evaluation += sign * VariantRules.VALUES[this.getPiece(i,j)];
+ evaluation += sign * V.VALUES[this.getPiece(i,j)];
}
}
}
getBaseFen()
{
let fen = "";
- let [sizeX,sizeY] = VariantRules.size;
- for (let i=0; i<sizeX; i++)
+ for (let i=0; i<V.size.x; i++)
{
let emptyCount = 0;
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
- if (this.board[i][j] == VariantRules.EMPTY)
+ if (this.board[i][j] == V.EMPTY)
emptyCount++;
else
{
fen += emptyCount;
emptyCount = 0;
}
- fen += VariantRules.board2fen(this.board[i][j]);
+ fen += V.board2fen(this.board[i][j]);
}
}
if (emptyCount > 0)
// "Flush remainder"
fen += emptyCount;
}
- if (i < sizeX - 1)
+ if (i < V.size.x - 1)
fen += "/"; //separate rows
}
return fen;
// Context: just before move is played, turn hasn't changed
getNotation(move)
{
- if (move.appear.length == 2 && move.appear[0].p == VariantRules.KING) //castle
+ if (move.appear.length == 2 && move.appear[0].p == V.KING) //castle
return (move.end.y < move.start.y ? "0-0-0" : "0-0");
// Translate final square
- const finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ const finalSquare = String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
const piece = this.getPiece(move.start.x, move.start.y);
- if (piece == VariantRules.PAWN)
+ if (piece == V.PAWN)
{
// Pawn move
let notation = "";
getLongNotation(move)
{
const startSquare =
- String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x);
- const finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x);
+ const finalSquare = String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
return startSquare + finalSquare; //not encoding move. But short+long is enough
}
};
},
render(h) {
- const [sizeX,sizeY] = VariantRules.size;
+ const [sizeX,sizeY] = [V.size.x,V.size.y];
const smallScreen = (window.innerWidth <= 420);
// Precompute hints squares to facilitate rendering
let hintSquares = doubleArray(sizeX, sizeY, false);
},
methods: {
drawDiag: function(fen) {
- let [sizeX,sizeY] = VariantRules.size;
+ let [sizeX,sizeY] = [V.size.x,V.size.y];
let fenParts = fen.split(" ");
// Obtain array of pieces images names
let board = VariantRules.GetBoard(fenParts[0]);
getSquareOccupation(i, j, mirrorSide)
{
const piece = this.getPiece(i,j);
- const V = VariantRules;
if (mirrorSide==1 && Object.keys(V.ALICE_CODES).includes(piece))
return this.board[i][j];
else if (mirrorSide==2 && Object.keys(V.ALICE_PIECES).includes(piece))
getSideBoard(mirrorSide)
{
// Build corresponding board from complete board
- const [sizeX,sizeY] = VariantRules.size;
- let sideBoard = doubleArray(sizeX, sizeY, "");
- for (let i=0; i<sizeX; i++)
+ let sideBoard = doubleArray(V.size.x, V.size.y, "");
+ for (let i=0; i<V.size.x; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
sideBoard[i][j] = this.getSquareOccupation(i, j, mirrorSide);
}
return sideBoard;
// NOTE: castle & enPassant https://www.chessvariants.com/other.dir/alice.html
getPotentialMovesFrom([x,y], sideBoard)
{
- const pieces = Object.keys(VariantRules.ALICE_CODES);
- const codes = Object.keys(VariantRules.ALICE_PIECES);
+ const pieces = Object.keys(V.ALICE_CODES);
+ const codes = Object.keys(V.ALICE_PIECES);
const mirrorSide = (pieces.includes(this.getPiece(x,y)) ? 1 : 2);
// Search valid moves on sideBoard
// appear[i] must be an empty square on the other board
for (let psq of m.appear)
{
- if (this.getSquareOccupation(psq.x,psq.y,3-mirrorSide) != VariantRules.EMPTY)
+ if (this.getSquareOccupation(psq.x,psq.y,3-mirrorSide) != V.EMPTY)
return false;
}
}
- else if (this.board[m.end.x][m.end.y] != VariantRules.EMPTY)
+ else if (this.board[m.end.x][m.end.y] != V.EMPTY)
{
// Attempt to capture
const piece = this.getPiece(m.end.x,m.end.y);
if (mirrorSide==1)
{
m.appear.forEach(psq => { //forEach: castling taken into account
- psq.p = VariantRules.ALICE_CODES[psq.p]; //goto board2
+ psq.p = V.ALICE_CODES[psq.p]; //goto board2
});
}
else //move on board2: mark vanishing pieces as Alice
{
m.vanish.forEach(psq => {
- psq.p = VariantRules.ALICE_CODES[psq.p];
+ psq.p = V.ALICE_CODES[psq.p];
});
}
// Fix en-passant captures
- if (m.vanish[0].p == VariantRules.PAWN
- && m.vanish.length == 2 && this.board[m.end.x][m.end.y] == VariantRules.EMPTY)
+ if (m.vanish[0].p == V.PAWN && m.vanish.length == 2
+ && this.board[m.end.x][m.end.y] == V.EMPTY)
{
m.vanish[1].c = this.getOppCol(this.getColor(x,y));
// In the special case of en-passant, if
// - board2 takes board1 : vanish[1] --> normal
let van = m.vanish[1];
if (mirrorSide==1 && codes.includes(this.getPiece(van.x,van.y)))
- van.p = VariantRules.ALICE_CODES[van.p];
+ van.p = V.ALICE_CODES[van.p];
else if (mirrorSide==2 && pieces.includes(this.getPiece(van.x,van.y)))
- van.p = VariantRules.ALICE_PIECES[van.p];
+ van.p = V.ALICE_PIECES[van.p];
}
return true;
});
const color = this.turn;
const oppCol = this.getOppCol(color);
var potentialMoves = [];
- let [sizeX,sizeY] = VariantRules.size;
let sideBoard = [this.getSideBoard(1), this.getSideBoard(2)];
- for (var i=0; i<sizeX; i++)
+ for (var i=0; i<V.size.x; i++)
{
- for (var j=0; j<sizeY; j++)
+ for (var j=0; j<V.size.y; j++)
{
- if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) == color)
+ if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == color)
{
const mirrorSide =
- Object.keys(VariantRules.ALICE_CODES).includes(this.getPiece(i,j))
+ Object.keys(V.ALICE_CODES).includes(this.getPiece(i,j))
? 1
: 2;
Array.prototype.push.apply(potentialMoves,
// Play on sideboards [TODO: only one sideBoard required]
playSide(move, sideBoard)
{
- const pieces = Object.keys(VariantRules.ALICE_CODES);
+ const pieces = Object.keys(V.ALICE_CODES);
move.vanish.forEach(psq => {
const mirrorSide = (pieces.includes(psq.p) ? 1 : 2);
- sideBoard[mirrorSide-1][psq.x][psq.y] = VariantRules.EMPTY;
+ sideBoard[mirrorSide-1][psq.x][psq.y] = V.EMPTY;
});
move.appear.forEach(psq => {
const mirrorSide = (pieces.includes(psq.p) ? 1 : 2);
- const piece = (mirrorSide == 1 ? psq.p : VariantRules.ALICE_PIECES[psq.p]);
+ const piece = (mirrorSide == 1 ? psq.p : V.ALICE_PIECES[psq.p]);
sideBoard[mirrorSide-1][psq.x][psq.y] = psq.c + piece;
- if (piece == VariantRules.KING)
+ if (piece == V.KING)
this.kingPos[psq.c] = [psq.x,psq.y];
});
}
// Undo on sideboards
undoSide(move, sideBoard)
{
- const pieces = Object.keys(VariantRules.ALICE_CODES);
+ const pieces = Object.keys(V.ALICE_CODES);
move.appear.forEach(psq => {
const mirrorSide = (pieces.includes(psq.p) ? 1 : 2);
- sideBoard[mirrorSide-1][psq.x][psq.y] = VariantRules.EMPTY;
+ sideBoard[mirrorSide-1][psq.x][psq.y] = V.EMPTY;
});
move.vanish.forEach(psq => {
const mirrorSide = (pieces.includes(psq.p) ? 1 : 2);
- const piece = (mirrorSide == 1 ? psq.p : VariantRules.ALICE_PIECES[psq.p]);
+ const piece = (mirrorSide == 1 ? psq.p : V.ALICE_PIECES[psq.p]);
sideBoard[mirrorSide-1][psq.x][psq.y] = psq.c + piece;
- if (piece == VariantRules.KING)
+ if (piece == V.KING)
this.kingPos[psq.c] = [psq.x,psq.y];
});
}
const color = this.turn;
this.playSide(move, sideBoard); //no need to track flags
const kp = this.kingPos[color];
- const mirrorSide = sideBoard[0][kp[0]][kp[1]] != VariantRules.EMPTY ? 1 : 2;
+ const mirrorSide = (sideBoard[0][kp[0]][kp[1]] != V.EMPTY ? 1 : 2);
let saveBoard = this.board;
this.board = sideBoard[mirrorSide-1];
let res = this.isAttacked(kp, [this.getOppCol(color)]);
{
this.play(move);
const color = this.turn; //opponent
- const pieces = Object.keys(VariantRules.ALICE_CODES);
+ const pieces = Object.keys(V.ALICE_CODES);
const kp = this.kingPos[color];
const mirrorSide = (pieces.includes(this.getPiece(kp[0],kp[1])) ? 1 : 2);
let sideBoard = this.getSideBoard(mirrorSide);
checkGameEnd()
{
- const pieces = Object.keys(VariantRules.ALICE_CODES);
+ const pieces = Object.keys(V.ALICE_CODES);
const color = this.turn;
const kp = this.kingPos[color];
const mirrorSide = (pieces.includes(this.getPiece(kp[0],kp[1])) ? 1 : 2);
getNotation(move)
{
- if (move.appear.length == 2 && move.appear[0].p == VariantRules.KING)
+ if (move.appear.length == 2 && move.appear[0].p == V.KING)
{
if (move.end.y < move.start.y)
return "0-0-0";
return "0-0";
}
- const finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ const finalSquare = String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
const piece = this.getPiece(move.start.x, move.start.y);
const captureMark = (move.vanish.length > move.appear.length ? "x" : "");
{
switch (this.getPiece(x,y))
{
- case VariantRules.ANTIKING:
+ case V.ANTIKING:
return this.getPotentialAntikingMoves([x,y]);
default:
return super.getPotentialMovesFrom([x,y]);
getPotentialAntikingMoves(sq)
{
- const V = VariantRules;
return this.getSlideNJumpMoves(sq,
V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
}
isAttackedByKing([x,y], colors)
{
- const V = VariantRules;
if (this.getPiece(x,y) == V.ANTIKING)
return false; //antiking is not attacked by king
return this.isAttackedBySlideNJump([x,y], colors, V.KING,
isAttackedByAntiking([x,y], colors)
{
- const V = VariantRules;
if ([V.KING,V.ANTIKING].includes(this.getPiece(x,y)))
return false; //(anti)king is not attacked by antiking
return this.isAttackedBySlideNJump([x,y], colors, V.ANTIKING,
const piece = this.getPiece(move.start.x,move.start.y);
const c = this.getColor(move.start.x,move.start.y);
// Update antiking position
- if (piece == VariantRules.ANTIKING)
+ if (piece == V.ANTIKING)
{
this.antikingPos[c][0] = move.appear[0].x;
this.antikingPos[c][1] = move.appear[0].y;
{
super.unupdateVariables(move);
const c = this.getColor(move.start.x,move.start.y);
- if (this.getPiece(move.start.x,move.start.y) == VariantRules.ANTIKING)
+ if (this.getPiece(move.start.x,move.start.y) == V.ANTIKING)
this.antikingPos[c] = [move.start.x, move.start.y];
}
{
let x = m.end.x + step[0];
let y = m.end.y + step[1];
- if (x>=0 && x<8 && y>=0 && y<8 && this.board[x][y] != VariantRules.EMPTY
- && this.getPiece(x,y) != VariantRules.PAWN)
+ if (V.OnBoard(x,y) && this.board[x][y] != V.EMPTY
+ && this.getPiece(x,y) != V.PAWN)
{
m.vanish.push(
new PiPo({p:this.getPiece(x,y),c:this.getColor(x,y),x:x,y:y}));
getPotentialKingMoves([x,y])
{
- const V = VariantRules;
// King cannot capture:
let moves = [];
- let [sizeX,sizeY] = V.size;
const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
for (let step of steps)
{
- var i = x + step[0];
- var j = y + step[1];
- if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] == VariantRules.EMPTY)
+ const i = x + step[0];
+ const j = y + step[1];
+ if (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY)
moves.push(this.getBasicMove([x,y], [i,j]));
}
return moves.concat(this.getCastleMoves([x,y]));
isAttacked(sq, colors)
{
- if (this.getPiece(sq[0],sq[1]) == VariantRules.KING
- && this.isAttackedByKing(sq, colors))
- {
+ if (this.getPiece(sq[0],sq[1]) == V.KING && this.isAttackedByKing(sq, colors))
return false; //king cannot take...
- }
return (this.isAttackedByPawn(sq, colors)
|| this.isAttackedByRook(sq, colors)
|| this.isAttackedByKnight(sq, colors)
{
let standardMoves = super.getPotentialMovesFrom([x,y]);
const lastRank = this.turn == "w" ? 0 : 7;
- if (this.getPiece(x,y) == VariantRules.KING)
+ if (this.getPiece(x,y) == V.KING)
return standardMoves; //king has to be treated differently (for castles)
let moves = [];
standardMoves.forEach(m => {
- if (m.vanish[0].p == VariantRules.PAWN)
+ if (m.vanish[0].p == V.PAWN)
{
if (Math.abs(m.end.x-m.start.x)==2 && !this.pawnFlags[this.turn][m.start.y])
return; //skip forbidden 2-squares jumps
- if (this.board[m.end.x][m.end.y] == VariantRules.EMPTY
- && m.vanish.length==2 && this.getColor(m.start.x,m.start.y) == 'c')
+ if (this.board[m.end.x][m.end.y] == V.EMPTY && m.vanish.length==2
+ && this.getColor(m.start.x,m.start.y) == 'c')
{
return; //checkered pawns cannot take en-passant
}
m.appear[0].c = "c";
moves.push(m);
if (m.appear[0].p != m.vanish[1].p //avoid promotions (already treated):
- && (m.vanish[0].p != VariantRules.PAWN || m.end.x != lastRank))
+ && (m.vanish[0].p != V.PAWN || m.end.x != lastRank))
{
// Add transformation into captured piece
let m2 = JSON.parse(JSON.stringify(m));
{
for (let i of [-1,1])
{
- if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==VariantRules.PAWN
+ if (y+i>=0 && y+i<8 && this.getPiece(x+pawnShift,y+i)==V.PAWN
&& this.getColor(x+pawnShift,y+i)==c)
{
return true;
updateVariables(move)
{
- const c = this.getColor(move.start.x,move.start.y);
- if (c != 'c') //checkered not concerned by castle flags
- super.updateVariables(move);
-
- // Does it turn off a 2-squares pawn flag?
+ super.updateVariables(move);
+ // Does this move turn off a 2-squares pawn flag?
const secondRank = [1,6];
- if (secondRank.includes(move.start.x) && move.vanish[0].p == VariantRules.PAWN)
+ if (secondRank.includes(move.start.x) && move.vanish[0].p == V.PAWN)
this.pawnFlags[move.start.x==6 ? "w" : "b"][move.start.y] = false;
}
evalPosition()
{
- const [sizeX,sizeY] = VariantRules.size;
let evaluation = 0;
//Just count material for now, considering checkered neutral (...)
- for (let i=0; i<sizeX; i++)
+ for (let i=0; i<V.size.x; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
- if (this.board[i][j] != VariantRules.EMPTY)
+ if (this.board[i][j] != V.EMPTY)
{
const sqColor = this.getColor(i,j);
const sign = sqColor == "w" ? 1 : (sqColor=="b" ? -1 : 0);
- evaluation += sign * VariantRules.VALUES[this.getPiece(i,j)];
+ evaluation += sign * V.VALUES[this.getPiece(i,j)];
}
}
}
// Translate final square
let finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
let piece = this.getPiece(move.start.x, move.start.y);
- if (piece == VariantRules.PAWN)
+ if (piece == V.PAWN)
{
// Pawn move
let notation = "";
{
super.initVariables(fen);
// Also init reserves (used by the interface to show landing pieces)
- const V = VariantRules;
this.reserve =
{
"w":
[V.QUEEN]: 0,
}
};
- const [sizeX,sizeY] = VariantRules.size;
- this.promoted = doubleArray(sizeX, sizeY, false);
+ this.promoted = doubleArray(V.size.x, V.size.y, false);
// May be a continuation: adjust numbers of pieces in reserve + promoted pieces
this.moves.forEach(m => { this.updateVariables(m); });
}
getColor(i,j)
{
- const sizeX = VariantRules.size[0];
- if (i >= sizeX)
- return (i==sizeX ? "w" : "b");
+ if (i >= V.size.x)
+ return (i==V.size.x ? "w" : "b");
return this.board[i][j].charAt(0);
}
getPiece(i,j)
{
- const sizeX = VariantRules.size[0];
- if (i >= sizeX)
- return VariantRules.RESERVE_PIECES[j];
+ if (i >= V.size.x)
+ return V.RESERVE_PIECES[j];
return this.board[i][j].charAt(1);
}
// Used by the interface:
getReservePpath(color, index)
{
- return color + VariantRules.RESERVE_PIECES[index];
+ return color + V.RESERVE_PIECES[index];
}
// Ordering on reserve pieces
static get RESERVE_PIECES() {
- const V = VariantRules;
return [V.PAWN,V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
}
getReserveMoves([x,y])
{
const color = this.turn;
- const p = VariantRules.RESERVE_PIECES[y];
+ const p = V.RESERVE_PIECES[y];
if (this.reserve[color][p] == 0)
return [];
let moves = [];
- const [sizeX,sizeY] = VariantRules.size;
- const pawnShift = (p==VariantRules.PAWN ? 1 : 0);
- for (let i=pawnShift; i<sizeX-pawnShift; i++)
+ const pawnShift = (p==V.PAWN ? 1 : 0);
+ for (let i=pawnShift; i<V.size.x-pawnShift; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
- if (this.board[i][j] == VariantRules.EMPTY)
+ if (this.board[i][j] == V.EMPTY)
{
let mv = new Move({
appear: [
getPotentialMovesFrom([x,y])
{
- const sizeX = VariantRules.size[0];
- if (x >= sizeX)
+ if (x >= V.size.x)
{
// Reserves, outside of board: x == sizeX(+1)
return this.getReserveMoves([x,y]);
{
let moves = super.getAllValidMoves();
const color = this.turn;
- const sizeX = VariantRules.size[0];
- for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
- moves = moves.concat(this.getReserveMoves([sizeX+(color=="w"?0:1),i]));
+ for (let i=0; i<V.RESERVE_PIECES.length; i++)
+ moves = moves.concat(this.getReserveMoves([V.size.x+(color=="w"?0:1),i]));
return this.filterValid(moves);
}
{
if (!super.atLeastOneMove())
{
- const sizeX = VariantRules.size[0];
- // Scan for reserve moves
- for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
+ const color = this.turn;
+ // Search one reserve move
+ for (let i=0; i<V.RESERVE_PIECES.length; i++)
{
- let moves = this.filterValid(this.getReserveMoves([sizeX,i]));
+ let moves = this.filterValid(
+ this.getReserveMoves([V.size.x+(this.turn=="w"?0:1), i]) );
if (moves.length > 0)
return true;
}
if (move.vanish.length == 2 && move.appear.length == 2)
return; //skip castle
const color = this.turn;
- const V = VariantRules;
if (move.vanish.length == 0)
{
this.reserve[color][move.appear[0].p]--;
this.promoted[move.end.x][move.end.y] = move.movePromoted
|| (move.vanish[0].p == V.PAWN && move.appear[0].p != V.PAWN);
if (move.capturePromoted)
- this.reserve[color][VariantRules.PAWN]++;
+ this.reserve[color][V.PAWN]++;
else if (move.vanish.length == 2)
this.reserve[color][move.vanish[1].p]++;
}
if (move.vanish.length == 2 && move.appear.length == 2)
return;
const color = this.turn;
- const V = VariantRules;
if (move.vanish.length == 0)
{
this.reserve[color][move.appear[0].p]++;
this.promoted[move.start.x][move.start.y] = true;
this.promoted[move.end.x][move.end.y] = move.capturePromoted;
if (move.capturePromoted)
- this.reserve[color][VariantRules.PAWN]--;
+ this.reserve[color][V.PAWN]--;
else if (move.vanish.length == 2)
this.reserve[color][move.vanish[1].p]--;
}
{
let evaluation = super.evalPosition();
// Add reserves:
- for (let i=0; i<VariantRules.RESERVE_PIECES.length; i++)
+ for (let i=0; i<V.RESERVE_PIECES.length; i++)
{
- const p = VariantRules.RESERVE_PIECES[i];
- evaluation += this.reserve["w"][p] * VariantRules.VALUES[p];
- evaluation -= this.reserve["b"][p] * VariantRules.VALUES[p];
+ const p = V.RESERVE_PIECES[i];
+ evaluation += this.reserve["w"][p] * V.VALUES[p];
+ evaluation -= this.reserve["b"][p] * V.VALUES[p];
}
return evaluation;
}
return super.getNotation(move);
// Rebirth:
const piece =
- (move.appear[0].p != VariantRules.PAWN ? move.appear[0].p.toUpperCase() : "");
+ (move.appear[0].p != V.PAWN ? move.appear[0].p.toUpperCase() : "");
const finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
return piece + "@" + finalSquare;
}
if (move.vanish.length > 0)
return super.getLongNotation(move);
const finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
return "@" + finalSquare;
}
}
initVariables(fen)
{
super.initVariables(fen);
- const V = VariantRules;
this.material =
{
"w":
let moves = super.getPotentialPawnMoves([x,y]);
// Add potential promotions into king
const color = this.turn;
- const V = VariantRules;
- const [sizeX,sizeY] = V.size;
const shift = (color == "w" ? -1 : 1);
- const lastRank = (color == "w" ? 0 : sizeX-1);
+ const lastRank = (color == "w" ? 0 : V.size.x-1);
if (x+shift == lastRank)
{
if (this.board[x+shift][y] == V.EMPTY)
moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:V.KING}));
// Captures
- if (y>0 && this.canTake([x,y], [x+shift,y-1])
- && this.board[x+shift][y-1] != V.EMPTY)
+ if (y>0 && this.board[x+shift][y-1] != V.EMPTY
+ && this.canTake([x,y], [x+shift,y-1]))
{
moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:V.KING}));
}
- if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
- && this.board[x+shift][y+1] != V.EMPTY)
+ if (y<V.size.y-1 && this.board[x+shift][y+1] != V.EMPTY
+ && this.canTake([x,y], [x+shift,y+1]))
{
moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:color,p:V.KING}));
}
if (move.appear[0].p != move.vanish[0].p)
{
this.material[move.appear[0].c][move.appear[0].p]++;
- this.material[move.appear[0].c][VariantRules.PAWN]--;
+ this.material[move.appear[0].c][V.PAWN]--;
}
if (move.vanish.length==2 && move.appear.length==1) //capture
this.material[move.vanish[1].c][move.vanish[1].p]--;
if (move.appear[0].p != move.vanish[0].p)
{
this.material[move.appear[0].c][move.appear[0].p]--;
- this.material[move.appear[0].c][VariantRules.PAWN]++;
+ this.material[move.appear[0].c][V.PAWN]++;
}
if (move.vanish.length==2 && move.appear.length==1)
this.material[move.vanish[1].c][move.vanish[1].p]++;
p => { return this.material[color][p] == 0; }))
{
// Very negative (resp. positive) if white (reps. black) pieces set is incomplete
- return (color=="w"?-1:1) * VariantRules.INFINITY;
+ return (color=="w"?-1:1) * V.INFINITY;
}
return super.evalPosition();
}
{
static getPpath(b)
{
- const V = VariantRules;
return ([V.MARSHALL,V.CARDINAL].includes(b[1]) ? "Grand/" : "") + b;
}
this.captures = { "w": {}, "b": {} }; //for promotions
}
- static get size() { return [10,10]; }
+ static get size() { return {x:10,y:10}; }
static get MARSHALL() { return 'm'; } //rook+knight
static get CARDINAL() { return 'c'; } //bishop+knight
getEpSquare(move)
{
const [sx,sy,ex] = [move.start.x,move.start.y,move.end.x];
- if (this.getPiece(sx,sy) == VariantRules.PAWN && Math.abs(sx - ex) >= 2)
+ if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) >= 2)
{
const step = (ex-sx) / Math.abs(ex-sx);
let res = [{
{
switch (this.getPiece(x,y))
{
- case VariantRules.MARSHALL:
+ case V.MARSHALL:
return this.getPotentialMarshallMoves([x,y]);
- case VariantRules.CARDINAL:
+ case V.CARDINAL:
return this.getPotentialCardinalMoves([x,y]);
default:
return super.getPotentialMovesFrom([x,y])
{
const color = this.turn;
let moves = [];
- const V = VariantRules;
- const [sizeX,sizeY] = VariantRules.size;
+ const [sizeX,sizeY] = [V.size.x,V.size.y];
const shift = (color == "w" ? -1 : 1);
const startRanks = (color == "w" ? [sizeX-2,sizeX-3] : [1,2]);
const lastRanks = (color == "w" ? [0,1,2] : [sizeX-1,sizeX-2,sizeX-3]);
getPotentialMarshallMoves(sq)
{
- const V = VariantRules;
return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat(
this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep"));
}
getPotentialCardinalMoves(sq)
{
- const V = VariantRules;
return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep"));
}
isAttackedByMarshall(sq, colors)
{
- const V = VariantRules;
return this.isAttackedBySlideNJump(sq, colors, V.MARSHALL, V.steps[V.ROOK])
|| this.isAttackedBySlideNJump(
sq, colors, V.MARSHALL, V.steps[V.KNIGHT], "oneStep");
isAttackedByCardinal(sq, colors)
{
- const V = VariantRules;
return this.isAttackedBySlideNJump(sq, colors, V.CARDINAL, V.steps[V.BISHOP])
|| this.isAttackedBySlideNJump(
sq, colors, V.CARDINAL, V.steps[V.KNIGHT], "oneStep");
updateVariables(move)
{
super.updateVariables(move);
- if (move.vanish.length==2 && move.appear.length==1
- && move.vanish[1].p != VariantRules.PAWN)
+ if (move.vanish.length==2 && move.appear.length==1 && move.vanish[1].p != V.PAWN)
{
// Capture: update this.captures
if (!this.captures[move.vanish[1].c][move.vanish[1].p])
unupdateVariables(move)
{
super.unupdateVariables(move);
- if (move.vanish.length==2 && move.appear.length==1
- && move.vanish[1].p != VariantRules.PAWN)
+ if (move.vanish.length==2 && move.appear.length==1 && move.vanish[1].p != V.PAWN)
{
this.captures[move.vanish[1].c][move.vanish[1].p] =
Math.max(0, this.captures[move.vanish[1].c][move.vanish[1].p]-1);
// Complete with promotion(s) into king, if possible
const color = this.turn;
- const V = VariantRules;
- const [sizeX,sizeY] = VariantRules.size;
const shift = (color == "w" ? -1 : 1);
- const lastRank = (color == "w" ? 0 : sizeX-1);
+ const lastRank = (color == "w" ? 0 : V.size.x-1);
if (x+shift == lastRank)
{
// Normal move
{
moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:V.KING}));
}
- if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
+ if (y<V.size.y-1 && this.canTake([x,y], [x+shift,y+1])
&& this.board[x+shift][y+1] != V.EMPTY)
{
moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:color,p:V.KING}));
getPotentialKingMoves(sq)
{
- const V = VariantRules;
return this.getSlideNJumpMoves(sq,
V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
}
{
const color = this.turn;
const oppCol = this.getOppCol(color);
- const [sizeX,sizeY] = VariantRules.size;
- for (let i=0; i<sizeX; i++)
+ for (let i=0; i<V.size.x; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
- if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) != oppCol)
+ if (this.board[i][j] != V.EMPTY && this.getColor(i,j) != oppCol)
{
const moves = this.getPotentialMovesFrom([i,j]);
if (moves.length > 0)
let moves = this.filterValid( this.getPotentialMovesFrom(sq) );
// This is called from interface: we need to know if a capture is possible
if (this.atLeastOneCapture())
- moves = VariantRules.KeepCaptures(moves);
+ moves = V.KeepCaptures(moves);
return moves;
}
{
let moves = super.getAllValidMoves();
if (moves.some(m => { return m.vanish.length == 2; }))
- moves = VariantRules.KeepCaptures(moves);
+ moves = V.KeepCaptures(moves);
return moves;
}
// TODO: job is done multiple times for (normal) promotions.
applyMagneticLaws(move)
{
- const V = VariantRules;
if (move.appear[0].p == V.KING && move.appear.length==1)
return [move]; //kings are not charged
const aIdx = (move.appear[0].p != V.KING ? 0 : 1); //if castling, rook is charged
const lastRank = (color=="w" ? 0 : 7);
const standardMove = JSON.parse(JSON.stringify(move));
this.play(standardMove);
- const [sizeX,sizeY] = V.size;
for (let step of [[-1,0],[1,0],[0,-1],[0,1]])
{
let [i,j] = [x+step[0],y+step[1]];
- while (i>=0 && i<sizeX && j>=0 && j<sizeY)
+ while (V.OnBoard(i,j))
{
if (this.board[i][j] != V.EMPTY)
{
{
// Push it until we meet an obstacle or edge of the board
let [ii,jj] = [i+step[0],j+step[1]];
- while (ii>=0 && ii<sizeX && jj>=0 && jj<sizeY)
+ while (V.OnBoard(ii,jj))
{
if (this.board[ii][jj] != V.EMPTY)
break;
{
super.updateVariables(move);
const c = this.getColor(move.start.x,move.start.y);
- if (this.board[move.end.x][move.end.y] != VariantRules.EMPTY
+ if (this.board[move.end.x][move.end.y] != V.EMPTY
&& c != this.getColor(move.end.x,move.end.y)
- && this.getPiece(move.end.x,move.end.y) == VariantRules.KING)
+ && this.getPiece(move.end.x,move.end.y) == V.KING)
{
// We took opponent king !
const oppCol = this.getOppCol(c);
const c = this.getColor(x1,y1); //same as color at square 2
const p1 = this.getPiece(x1,y1);
const p2 = this.getPiece(x2,y2);
- const V = VariantRules;
if (p1 == V.KING && p2 == V.ROOK)
return []; //avoid duplicate moves (potential conflict with castle)
let move = new Move({
end: {x:x2,y:y2}
});
// Move completion: promote switched pawns (as in Magnetic)
- const sizeX = VariantRules.size[0];
- const lastRank = (c == "w" ? 0 : sizeX-1);
+ const lastRank = (c == "w" ? 0 : V.size.x-1);
let moves = [];
if ((p1==V.PAWN && x2==lastRank) || (p2==V.PAWN && x1==lastRank))
{
{
let moves = super.getPotentialMovesFrom([x,y]);
// Add switches: respecting chessboard ordering if "computer" is on
- const V = VariantRules;
const color = this.turn;
const piece = this.getPiece(x,y);
- const [sizeX,sizeY] = V.size;
const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
const kp = this.kingPos[color];
const oppCol = this.getOppCol(color);
let [i,j] = [x+step[0],y+step[1]];
if (!!computer && (i<x || (i==x && j<y)))
continue; //only switch with superior indices
- if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j]!=V.EMPTY
+ if (V.OnBoard(i,j) && this.board[i][j]!=V.EMPTY
&& this.getColor(i,j)==color && this.getPiece(i,j)!=piece
// No switching under check (theoretically non-king pieces could, but not)
&& !this.isAttacked(kp, [oppCol]))
const color = this.turn;
const oppCol = this.getOppCol(color);
let potentialMoves = [];
- const [sizeX,sizeY] = VariantRules.size;
- for (let i=0; i<sizeX; i++)
+ for (let i=0; i<V.size.x; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
- if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) == color)
+ if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == color)
{
Array.prototype.push.apply(potentialMoves,
this.getPotentialMovesFrom([i,j], computer));
{
super.updateVariables(move);
if (move.appear.length == 2 && move.vanish.length == 2
- && move.appear[1].p == VariantRules.KING)
+ && move.appear[1].p == V.KING)
{
// Switch with the king; not castle, and not handled by main class
const color = this.getColor(move.start.x, move.start.y);
{
super.unupdateVariables(move);
if (move.appear.length == 2 && move.vanish.length == 2
- && move.appear[1].p == VariantRules.KING)
+ && move.appear[1].p == V.KING)
{
const color = this.getColor(move.start.x, move.start.y);
this.kingPos[color] = [move.appear[0].x, move.appear[0].y];
if (move.appear.length == 1)
return super.getNotation(move); //no switch
// Switch or castle
- if (move.appear[0].p == VariantRules.KING && move.appear[1].p == VariantRules.ROOK)
+ if (move.appear[0].p == V.KING && move.appear[1].p == V.ROOK)
return (move.end.y < move.start.y ? "0-0-0" : "0-0");
// Switch:
const startSquare =
- String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x);
+ String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x);
const finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
return "S" + startSquare + finalSquare;
}
}
const piece = this.getPiece(x,y);
const color = this.getColor(x,y);
const oppCol = this.getOppCol(color);
- const V = VariantRules;
const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
- const [sizeX,sizeY] = V.size;
outerLoop:
for (let step of adjacentSteps)
{
const [i,j] = [x+step[0],y+step[1]];
- if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] != V.EMPTY
+ if (V.OnBoard(i,j) && this.board[i][j] != V.EMPTY
&& this.getColor(i,j) == oppCol)
{
const oppPiece = this.getPiece(i,j);
const [i2,j2] = [i+step2[0],j+step2[1]];
if (i2 == x && j2 == y)
continue; //skip initial piece!
- if (i2>=0 && i2<sizeX && j2>=0 && j2<sizeY
- && this.board[i2][j2] != V.EMPTY && this.getColor(i2,j2) == color)
+ if (V.OnBoard(i2,j2) && this.board[i2][j2] != V.EMPTY
+ && this.getColor(i2,j2) == color)
{
if ([V.BISHOP,V.IMMOBILIZER].includes(this.getPiece(i2,j2)))
return false;
return [];
switch (this.getPiece(x,y))
{
- case VariantRules.IMMOBILIZER:
+ case V.IMMOBILIZER:
return this.getPotentialImmobilizerMoves([x,y]);
default:
return super.getPotentialMovesFrom([x,y]);
const color = this.getColor(x,y);
const piece = this.getPiece(x,y);
let moves = [];
- const [sizeX,sizeY] = VariantRules.size;
outerLoop:
for (let step of steps)
{
let i = x + step[0];
let j = y + step[1];
- while (i>=0 && i<sizeX && j>=0 && j<sizeY
- && this.board[i][j] == VariantRules.EMPTY)
+ while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY)
{
moves.push(this.getBasicMove([x,y], [i,j]));
if (oneStep !== undefined)
j += step[1];
}
// Only king can take on occupied square:
- if (piece==VariantRules.KING && i>=0 && i<sizeX && j>=0
- && j<sizeY && this.canTake([x,y], [i,j]))
- {
+ if (piece==V.KING && V.OnBoard(i,j) && this.canTake([x,y], [i,j]))
moves.push(this.getBasicMove([x,y], [i,j]));
- }
}
return moves;
}
// Modify capturing moves among listed pawn moves
addPawnCaptures(moves, byChameleon)
{
- const steps = VariantRules.steps[VariantRules.ROOK];
- const [sizeX,sizeY] = VariantRules.size;
+ const steps = V.steps[V.ROOK];
const color = this.turn;
const oppCol = this.getOppCol(color);
moves.forEach(m => {
for (let step of steps)
{
const sq2 = [m.end.x+2*step[0],m.end.y+2*step[1]];
- if (sq2[0]>=0 && sq2[0]<sizeX && sq2[1]>=0 && sq2[1]<sizeY
- && this.board[sq2[0]][sq2[1]] != VariantRules.EMPTY
+ if (V.OnBoard(sq2[0],sq2[1]) && this.board[sq2[0]][sq2[1]] != V.EMPTY
&& this.getColor(sq2[0],sq2[1]) == color)
{
// Potential capture
const sq1 = [m.end.x+step[0],m.end.y+step[1]];
- if (this.board[sq1[0]][sq1[1]] != VariantRules.EMPTY
+ if (this.board[sq1[0]][sq1[1]] != V.EMPTY
&& this.getColor(sq1[0],sq1[1]) == oppCol)
{
const piece1 = this.getPiece(sq1[0],sq1[1]);
- if (!byChameleon || piece1 == VariantRules.PAWN)
+ if (!byChameleon || piece1 == V.PAWN)
{
m.vanish.push(new PiPo({
x:sq1[0],
const corner2 = [kp[0], m.end.y];
for (let [i,j] of [corner1,corner2])
{
- if (this.board[i][j] != VariantRules.EMPTY && this.getColor(i,j) == oppCol)
+ if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol)
{
const piece = this.getPiece(i,j);
- if (!byChameleon || piece == VariantRules.ROOK)
+ if (!byChameleon || piece == V.ROOK)
{
m.vanish.push( new PiPo({
x:i,
getKnightCaptures(startSquare, byChameleon)
{
// Look in every direction for captures
- const V = VariantRules;
const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
- const [sizeX,sizeY] = V.size;
const color = this.turn;
const oppCol = this.getOppCol(color);
let moves = [];
for (let step of steps)
{
let [i,j] = [x+step[0], y+step[1]];
- while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j]==V.EMPTY)
+ while (V.OnBoard(i,j) && this.board[i][j]==V.EMPTY)
{
i += step[0];
j += step[1];
}
- if (i<0 || i>=sizeX || j<0 || j>=sizeY || this.getColor(i,j)==color
+ if (!V.OnBoard(i,j) || this.getColor(i,j)==color
|| (!!byChameleon && this.getPiece(i,j)!=V.KNIGHT))
{
continue;
let last = [i,j];
let cur = [i+step[0],j+step[1]];
let vanished = [ new PiPo({x:x,y:y,c:color,p:piece}) ];
- while (cur[0]>=0 && cur[0]<sizeX && cur[1]>=0 && cur[1]<sizeY)
+ while (V.OnBoard(cur[0],cur[1]))
{
if (this.board[last[0]][last[1]] != V.EMPTY)
{
this.addQueenCaptures(moves, "asChameleon");
// Post-processing: merge similar moves, concatenating vanish arrays
let mergedMoves = {};
- const [sizeX,sizeY] = VariantRules.size;
moves.forEach(m => {
- const key = m.end.x + sizeX * m.end.y;
+ const key = m.end.x + V.size.x * m.end.y;
if (!mergedMoves[key])
mergedMoves[key] = m;
else
if (moves.length == 0)
return;
const [x,y] = [moves[0].start.x,moves[0].start.y];
- const V = VariantRules;
const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
let capturingDirections = [];
const color = this.turn;
const oppCol = this.getOppCol(color);
- const [sizeX,sizeY] = V.size;
adjacentSteps.forEach(step => {
const [i,j] = [x+step[0],y+step[1]];
- if (i>=0 && i<sizeX && j>=0 && j<sizeY
- && this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol
+ if (V.OnBoard(i,j) && this.board[i][j] != V.EMPTY && this.getColor(i,j) == oppCol
&& (!byChameleon || this.getPiece(i,j) == V.QUEEN))
{
capturingDirections.push(step);
getPotentialKingMoves(sq)
{
- const V = VariantRules;
return this.getSlideNJumpMoves(sq,
V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
}
// Square (x,y) must be surroundable by two enemy pieces,
// and one of them at least should be a pawn (moving).
const dirs = [ [1,0],[0,1] ];
- const steps = VariantRules.steps[VariantRules.ROOK];
- const [sizeX,sizeY] = VariantRules.size;
+ const steps = V.steps[V.ROOK];
for (let dir of dirs)
{
const [i1,j1] = [x-dir[0],y-dir[1]]; //"before"
const [i2,j2] = [x+dir[0],y+dir[1]]; //"after"
- if (i1>=0 && i1<sizeX && i2>=0 && i2<sizeX
- && j1>=0 && j1<sizeY && j2>=0 && j2<sizeY)
+ if (V.OnBoard(i1,j1) && V.OnBoard(i2,j2))
{
- if ((this.board[i1][j1]!=VariantRules.EMPTY
- && colors.includes(this.getColor(i1,j1))
- && this.board[i2][j2]==VariantRules.EMPTY)
+ if ((this.board[i1][j1]!=V.EMPTY && colors.includes(this.getColor(i1,j1))
+ && this.board[i2][j2]==V.EMPTY)
||
- (this.board[i2][j2]!=VariantRules.EMPTY
- && colors.includes(this.getColor(i2,j2))
- && this.board[i1][j1]==VariantRules.EMPTY))
+ (this.board[i2][j2]!=V.EMPTY && colors.includes(this.getColor(i2,j2))
+ && this.board[i1][j1]==V.EMPTY))
{
// Search a movable enemy pawn landing on the empty square
for (let step of steps)
{
- let [ii,jj] = (this.board[i1][j1]==VariantRules.EMPTY ? [i1,j1] : [i2,j2]);
+ let [ii,jj] = (this.board[i1][j1]==V.EMPTY ? [i1,j1] : [i2,j2]);
let [i3,j3] = [ii+step[0],jj+step[1]];
- while (i3>=0 && i3<sizeX && j3>=0 && j3<sizeY
- && this.board[i3][j3]==VariantRules.EMPTY)
+ while (V.OnBoard(i3,j3) && this.board[i3][j3]==V.EMPTY)
{
i3 += step[0];
j3 += step[1];
}
- if (i3>=0 && i3<sizeX && j3>=0 && j3<sizeY
- && colors.includes(this.getColor(i3,j3))
- && this.getPiece(i3,j3) == VariantRules.PAWN
- && !this.isImmobilized([i3,j3]))
+ if (V.OnBoard(i3,j3) && colors.includes(this.getColor(i3,j3))
+ && this.getPiece(i3,j3) == V.PAWN && !this.isImmobilized([i3,j3]))
{
return true;
}
{
// King must be on same column or row,
// and a rook should be able to reach a capturing square
- const [sizeX,sizeY] = VariantRules.size;
// colors contains only one element, giving the oppCol and thus king position
const sameRow = (x == this.kingPos[colors[0]][0]);
const sameColumn = (y == this.kingPos[colors[0]][1]);
if (sameRow || sameColumn)
{
// Look for the enemy rook (maximum 1)
- for (let i=0; i<sizeX; i++)
+ for (let i=0; i<V.size.x; i++)
{
- for (let j=0; j<sizeY; j++)
+ for (let j=0; j<V.size.y; j++)
{
- if (this.board[i][j] != VariantRules.EMPTY
- && colors.includes(this.getColor(i,j))
- && this.getPiece(i,j) == VariantRules.ROOK)
+ if (this.board[i][j] != V.EMPTY && colors.includes(this.getColor(i,j))
+ && this.getPiece(i,j) == V.ROOK)
{
if (this.isImmobilized([i,j]))
return false; //because only one rook
{
// Square (x,y) must be on same line as a knight,
// and there must be empty square(s) behind.
- const V = VariantRules;
const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
- const [sizeX,sizeY] = V.size;
outerLoop:
for (let step of steps)
{
const [i0,j0] = [x+step[0],y+step[1]];
- if (i0>=0 && i0<sizeX && j0>=0 && j0<sizeY && this.board[i0][j0] == V.EMPTY)
+ if (V.OnBoard(i0,j0) && this.board[i0][j0] == V.EMPTY)
{
// Try in opposite direction:
let [i,j] = [x-step[0],y-step[1]];
- while (i>=0 && i<sizeX && j>=0 && j<sizeY)
+ while (V.OnBoard(i,j))
{
- while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] == V.EMPTY)
+ while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY)
{
i -= step[0];
j -= step[1];
}
- if (i>=0 && i<sizeX && j>=0 && j<sizeY)
+ if (V.OnBoard(i,j))
{
if (colors.includes(this.getColor(i,j)))
{
{
// We cheat a little here: since this function is used exclusively for king,
// it's enough to check the immediate surrounding of the square.
- const V = VariantRules;
const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
- const [sizeX,sizeY] = V.size;
for (let step of adjacentSteps)
{
const [i,j] = [x+step[0],y+step[1]];
- if (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j]!=V.EMPTY
+ if (V.OnBoard(i,j) && this.board[i][j]!=V.EMPTY
&& colors.includes(this.getColor(i,j)) && this.getPiece(i,j) == V.BISHOP)
{
return true; //bishops are never immobilized
{
// Square (x,y) must be adjacent to a queen, and the queen must have
// some free space in the opposite direction from (x,y)
- const V = VariantRules;
const adjacentSteps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
- const [sizeX,sizeY] = V.size;
for (let step of adjacentSteps)
{
const sq2 = [x+2*step[0],y+2*step[1]];
- if (sq2[0]>=0 && sq2[0]<sizeX && sq2[1]>=0 && sq2[1]<sizeY
- && this.board[sq2[0]][sq2[1]] == V.EMPTY)
+ if (V.OnBoard(sq2[0],sq2[1]) && this.board[sq2[0]][sq2[1]] == V.EMPTY)
{
const sq1 = [x+step[0],y+step[1]];
if (this.board[sq1[0]][sq1[1]] != V.EMPTY
// Just update king(s) position(s)
const piece = this.getPiece(move.start.x,move.start.y);
const c = this.getColor(move.start.x,move.start.y);
- if (piece == VariantRules.KING && move.appear.length > 0)
+ if (piece == V.KING && move.appear.length > 0)
{
this.kingPos[c][0] = move.appear[0].x;
this.kingPos[c][1] = move.appear[0].y;
getNotation(move)
{
const initialSquare =
- String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x);
- const finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x);
+ const finalSquare = String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
let notation = undefined;
- if (move.appear[0].p == VariantRules.PAWN)
+ if (move.appear[0].p == V.PAWN)
{
// Pawn: generally ambiguous short notation, so we use full description
notation = "P" + initialSquare + finalSquare;
}
- else if (move.appear[0].p == VariantRules.KING)
+ else if (move.appear[0].p == V.KING)
notation = "K" + (move.vanish.length>1 ? "x" : "") + finalSquare;
else
notation = move.appear[0].p.toUpperCase() + finalSquare;
- if (move.vanish.length > 1 && move.appear[0].p != VariantRules.KING)
+ if (move.vanish.length > 1 && move.appear[0].p != V.KING)
notation += "X"; //capture mark (not describing what is captured...)
return notation;
}
{
static getPpath(b)
{
- const V = VariantRules;
return ([V.CAMEL,V.WILDEBEEST].includes(b[1]) ? "Wildebeest/" : "") + b;
}
- static get size() { return [10,11]; }
+ static get size() { return {x:10,y:11}; }
static get CAMEL() { return 'c'; }
static get WILDEBEEST() { return 'w'; }
getEpSquare(move)
{
const [sx,sy,ex] = [move.start.x,move.start.y,move.end.x];
- if (this.getPiece(sx,sy) == VariantRules.PAWN && Math.abs(sx - ex) >= 2)
+ if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) >= 2)
{
const step = (ex-sx) / Math.abs(ex-sx);
let res = [{
{
switch (this.getPiece(x,y))
{
- case VariantRules.CAMEL:
+ case V.CAMEL:
return this.getPotentialCamelMoves([x,y]);
- case VariantRules.WILDEBEEST:
+ case V.WILDEBEEST:
return this.getPotentialWildebeestMoves([x,y]);
default:
return super.getPotentialMovesFrom([x,y])
{
const color = this.turn;
let moves = [];
- const V = VariantRules;
- const [sizeX,sizeY] = VariantRules.size;
+ const [sizeX,sizeY] = [V.size.x,V.size.y];
const shift = (color == "w" ? -1 : 1);
const startRanks = (color == "w" ? [sizeX-2,sizeX-3] : [1,2]);
const lastRank = (color == "w" ? 0 : sizeX-1);
getPotentialCamelMoves(sq)
{
- return this.getSlideNJumpMoves(
- sq, VariantRules.steps[VariantRules.CAMEL], "oneStep");
+ return this.getSlideNJumpMoves(sq, V.steps[V.CAMEL], "oneStep");
}
getPotentialWildebeestMoves(sq)
{
- const V = VariantRules;
return this.getSlideNJumpMoves(
sq, V.steps[V.KNIGHT].concat(V.steps[V.CAMEL]), "oneStep");
}
isAttackedByCamel(sq, colors)
{
return this.isAttackedBySlideNJump(sq, colors,
- VariantRules.CAMEL, VariantRules.steps[VariantRules.CAMEL], "oneStep");
+ V.CAMEL, V.steps[V.CAMEL], "oneStep");
}
isAttackedByWildebeest(sq, colors)
{
- const V = VariantRules;
return this.isAttackedBySlideNJump(sq, colors, V.WILDEBEEST,
V.steps[V.KNIGHT].concat(V.steps[V.CAMEL]), "oneStep");
}
{
const color = this.getColor(x,y);
let moves = [];
- const [sizeX,sizeY] = VariantRules.size;
outerLoop:
for (let loop=0; loop<steps.length; loop++)
{
const step = steps[loop];
let i = x + step[0];
let j = y + step[1];
- while (i>=0 && i<sizeX && j>=0 && j<sizeY
- && this.board[i][j] == VariantRules.EMPTY)
+ while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY)
{
moves.push(this.getBasicMove([x,y], [i,j]));
if (!!oneStep)
{
const color = this.getColor(x,y);
var moves = [];
- const V = VariantRules;
const steps = asA != V.PAWN
? (asA==V.QUEEN ? V.steps[V.ROOK].concat(V.steps[V.BISHOP]) : V.steps[asA])
: color=='w' ? [[-1,-1],[-1,1]] : [[1,-1],[1,1]];
const oneStep = (asA==V.KNIGHT || asA==V.PAWN); //we don't capture king
- const [sizeX,sizeY] = V.size;
- const lastRank = (color == 'w' ? 0 : sizeY-1);
+ const lastRank = (color == 'w' ? 0 : V.size.x-1);
const promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
outerLoop:
for (let loop=0; loop<steps.length; loop++)
const step = steps[loop];
let i = x + step[0];
let j = y + step[1];
- while (i>=0 && i<sizeX && j>=0 && j<sizeY && this.board[i][j] == V.EMPTY)
+ while (V.OnBoard(i,j) && this.board[i][j] == V.EMPTY)
{
if (oneStep)
continue outerLoop;
i += step[0];
j += step[1];
}
- if (i>=0 && i<sizeX && j>=0 && j<sizeY &&
- this.getColor(i,j) == this.getOppCol(color) && this.getPiece(i,j) == asA)
+ if (V.OnBoard(i,j) && this.getColor(i,j) == this.getOppCol(color)
+ && this.getPiece(i,j) == asA)
{
// eat!
if (this.getPiece(x,y) == V.PAWN && i == lastRank)
{
let moves = [];
- Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.PAWN));
- Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.ROOK));
- Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.KNIGHT));
- Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.BISHOP));
- Array.prototype.push.apply(moves, this.findCaptures_aux(sq, VariantRules.QUEEN));
+ Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.PAWN));
+ Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.ROOK));
+ Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.KNIGHT));
+ Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.BISHOP));
+ Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.QUEEN));
return moves;
}
getPotentialPawnMoves([x,y])
{
const color = this.getColor(x,y);
- var moves = [];
- var V = VariantRules;
- let [sizeX,sizeY] = VariantRules.size;
- let shift = (color == 'w' ? -1 : 1);
- let startRank = (color == 'w' ? sizeY-2 : 1);
- let firstRank = (color == 'w' ? sizeY-1 : 0);
- let lastRank = (color == "w" ? 0 : sizeY-1);
+ let moves = [];
+ const [sizeX,sizeY] = [V.size.x,V.size.y];
+ const shift = (color == 'w' ? -1 : 1);
+ const startRank = (color == 'w' ? sizeY-2 : 1);
+ const firstRank = (color == 'w' ? sizeY-1 : 0);
+ const lastRank = (color == "w" ? 0 : sizeY-1);
if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank)
{
getPotentialRookMoves(sq)
{
- let noCaptures = this.getSlideNJumpMoves(
- sq, VariantRules.steps[VariantRules.ROOK]);
+ let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.ROOK]);
let captures = this.findCaptures(sq);
return noCaptures.concat(captures);
}
getPotentialKnightMoves(sq)
{
- let noCaptures = this.getSlideNJumpMoves(
- sq, VariantRules.steps[VariantRules.KNIGHT], "oneStep");
+ let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep");
let captures = this.findCaptures(sq);
return noCaptures.concat(captures);
}
getPotentialBishopMoves(sq)
{
- let noCaptures = this.getSlideNJumpMoves(
- sq, VariantRules.steps[VariantRules.BISHOP]);
+ let noCaptures = this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]);
let captures = this.findCaptures(sq);
return noCaptures.concat(captures);
}
getPotentialQueenMoves(sq)
{
- const V = VariantRules;
let noCaptures = this.getSlideNJumpMoves(
sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]));
let captures = this.findCaptures(sq);
getPotentialKingMoves(sq)
{
- const V = VariantRules;
// Initialize with normal moves
let noCaptures = this.getSlideNJumpMoves(sq,
V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
// Translate initial square (because pieces may fly unusually in this variant!)
const initialSquare =
- String.fromCharCode(97 + move.start.y) + (VariantRules.size[0]-move.start.x);
+ String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x);
// Translate final square
const finalSquare =
- String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x);
+ String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
let notation = "";
const piece = this.getPiece(move.start.x, move.start.y);
- if (piece == VariantRules.PAWN)
+ if (piece == V.PAWN)
{
// pawn move (TODO: enPassant indication)
if (move.vanish.length > 1)
script(src="/javascripts/variants/" + variant + ".js")
script.
const VariantRules = #{variant}Rules;
+ const V = VariantRules; //because this variable is often used
const variant = "#{variant}";
script(src="/javascripts/components/rules.js")
script(src="/javascripts/components/game.js")