//////////////
// MISC UTILS
+ static get HasFlags() { return true; } //some variants don't have flags
+
+ static get HasEnpassant() { return true; } //some variants don't have ep.
+
// Path to pieces
static getPpath(b)
{
{
const fenParsed = V.ParseFen(fen);
// 1) Check position
- const position = fenParsed.position;
+ if (!V.IsGoodPosition(fenParsed.position))
+ return false;
+ // 2) Check turn
+ if (!fenParsed.turn || !["w","b"].includes(fenParsed.turn))
+ return false;
+ // 3) Check flags
+ if (V.HasFlags && (!fenParsed.flags || !V.IsGoodFlags(fenParsed.flags)))
+ return false;
+ // 4) Check enpassant
+ if (V.HasEnpassant)
+ {
+ if (!fenParsed.enpassant)
+ return false;
+ if (fenParsed.enpassant != "-")
+ {
+ const ep = V.SquareToCoords(fenParsed.enpassant);
+ if (ep.y < 0 || ep.y > V.size.y || isNaN(ep.x) || ep.x < 0 || ep.x > V.size.x)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Is position part of the FEN a priori correct?
+ static IsGoodPosition(position)
+ {
+ if (position.length == 0)
+ return false;
const rows = position.split("/");
if (rows.length != V.size.x)
return false;
if (sumElts != V.size.y)
return false;
}
- // 2) Check flags (if present)
- if (!!fenParsed.flags && !V.IsGoodFlags(fenParsed.flags))
- return false;
- // 3) Check turn (if present)
- if (!!fenParsed.turn && !["w","b"].includes(fenParsed.turn))
- return false;
- // 4) Check enpassant (if present)
- if (!!fenParsed.enpassant)
- {
- const ep = V.SquareToCoords(fenParsed.enpassant);
- if (ep.y < 0 || ep.y > V.size.y || isNaN(ep.x) || ep.x < 0 || ep.x > V.size.x)
- return false;
- }
return true;
}
return !!flags.match(/^[01]{4,4}$/);
}
+ // 3 --> d (column letter from number)
+ static GetColumn(colnum)
+ {
+ return String.fromCharCode(97 + colnum);
+ }
+
// a4 --> {x:3,y:0}
static SquareToCoords(sq)
{
// {x:0,y:4} --> e8
static CoordsToSquare(coords)
{
- return String.fromCharCode(97 + coords.y) + (V.size.x - coords.x);
+ return V.GetColumn(coords.y) + (V.size.x - coords.x);
}
// Aggregates flags into one object
const square = moveOrSquare;
if (square == "-")
return undefined;
- return {
- x: square[0].charCodeAt()-97,
- y: V.size.x-parseInt(square[1])
- };
+ return V.SquareToCoords(square);
}
// Argument is a move:
const move = moveOrSquare;
static ParseFen(fen)
{
const fenParts = fen.split(" ");
- return {
+ let res =
+ {
position: fenParts[0],
turn: fenParts[1],
- flags: fenParts[2],
- enpassant: fenParts[3],
};
+ let nextIdx = 2;
+ if (V.HasFlags)
+ Object.assign(res, {flags: fenParts[nextIdx++]});
+ if (V.HasEnpassant)
+ Object.assign(res, {enpassant: fenParts[nextIdx]});
+ return res;
}
// Return current fen (game state)
getFen()
{
- return this.getBaseFen() + " " + this.turn + " " +
- this.getFlagsFen() + " " + this.getEnpassantFen();
+ return this.getBaseFen() + " " + this.turn +
+ (V.HasFlags ? (" " + this.getFlagsFen()) : "") +
+ (V.HasEnpassant ? (" " + this.getEnpassantFen()) : "");
}
// Position part of the FEN string
position += emptyCount;
emptyCount = 0;
}
- fen += V.board2fen(this.board[i][j]);
+ position += V.board2fen(this.board[i][j]);
}
}
if (emptyCount > 0)
getEnpassantFen()
{
const L = this.epSquares.length;
- if (L == 0)
+ if (!this.epSquares[L-1])
return "-"; //no en-passant
return V.CoordsToSquare(this.epSquares[L-1]);
}
this.setOtherVariables(fen);
}
- // Some additional variables from FEN (variant dependant)
- setOtherVariables(fen)
+ // Scan board for kings and rooks positions
+ scanKingsRooks(fen)
{
- // Set flags and enpassant:
- const parsedFen = V.ParseFen(fen);
- this.setFlags(fenParsed.flags);
- this.epSquares = [ V.SquareToCoords(parsedFen.enpassant) ];
- // Search for king and rooks positions:
this.INIT_COL_KING = {'w':-1, 'b':-1};
this.INIT_COL_ROOK = {'w':[-1,-1], 'b':[-1,-1]};
this.kingPos = {'w':[-1,-1], 'b':[-1,-1]}; //squares of white and black king
- const fenRows = parsedFen.position.split("/");
+ const fenRows = V.ParseFen(fen).position.split("/");
for (let i=0; i<fenRows.length; i++)
{
let k = 0; //column index on board
}
}
+ // Some additional variables from FEN (variant dependant)
+ setOtherVariables(fen)
+ {
+ // Set flags and enpassant:
+ const parsedFen = V.ParseFen(fen);
+ if (V.HasFlags)
+ this.setFlags(parsedFen.flags);
+ if (V.HasEnpassant)
+ {
+ const epSq = parsedFen.enpassant != "-"
+ ? V.SquareToCoords(parsedFen.enpassant)
+ : undefined;
+ this.epSquares = [ epSq ];
+ }
+ // Search for king and rooks positions:
+ this.scanKingsRooks(fen);
+ }
+
/////////////////////
// GETTERS & SETTERS
// En passant
const Lep = this.epSquares.length;
- const epSquare = (Lep>0 ? this.epSquares[Lep-1] : undefined);
+ const epSquare = this.epSquares[Lep-1]; //always at least one element
if (!!epSquare && epSquare.x == x+shift && Math.abs(epSquare.y - y) == 1)
{
const epStep = epSquare.y - y;
if (!!ingame)
move.notation = [this.getNotation(move), this.getLongNotation(move)];
- move.flags = JSON.stringify(this.aggregateFlags()); //save flags (for undo)
+ if (V.HasFlags)
+ move.flags = JSON.stringify(this.aggregateFlags()); //save flags (for undo)
this.updateVariables(move);
this.moves.push(move);
- this.epSquares.push( this.getEpSquare(move) );
+ if (V.HasEnpassant)
+ this.epSquares.push( this.getEpSquare(move) );
this.turn = this.getOppCol(this.turn);
V.PlayOnBoard(this.board, move);
if (!!ingame)
{
// Hash of current game state *after move*, to detect repetitions
- move.hash = hex_md5(this.getFen();
+ move.hash = hex_md5(this.getFen());
}
}
{
V.UndoOnBoard(this.board, move);
this.turn = this.getOppCol(this.turn);
- this.epSquares.pop();
+ if (V.HasEnpassant)
+ this.epSquares.pop();
this.moves.pop();
this.unupdateVariables(move);
- this.disaggregateFlags(JSON.parse(move.flags));
+ if (V.HasFlags)
+ this.disaggregateFlags(JSON.parse(move.flags));
// DEBUG:
// if (this.getFen() != this.states[this.states.length-1])