return "Eightpieces/tmp_png/" + b;
}
- getPPpath(b, orientation) {
- return this.getPpath(b, null, null, orientation);
+ getPPpath(m, orientation) {
+ return (
+ this.getPpath(
+ m.appear[0].c + m.appear[0].p,
+ null,
+ null,
+ orientation
+ )
+ );
}
static ParseFen(fen) {
// 5) Check sentry push (if any)
if (
fenParsed.sentrypush != "-" &&
- !fenParsed.sentrypush.match(/^([a-h][1-8],?)+$/)
+ !fenParsed.sentrypush.match(/^([a-h][1-8]){2,2}$/)
) {
return false;
}
const L = this.sentryPush.length;
if (!this.sentryPush[L-1]) return "-";
let res = "";
- this.sentryPush[L-1].forEach(coords =>
- res += V.CoordsToSquare(coords) + ",");
- return res.slice(0, -1);
+ const spL = this.sentryPush[L-1].length;
+ // Condensate path: just need initial and final squares:
+ return [0, spL - 1]
+ .map(i => V.CoordsToSquare(this.sentryPush[L-1][i]))
+ .join("");
}
setOtherVariables(fen) {
const parsedFen = V.ParseFen(fen);
if (parsedFen.sentrypush == "-") this.sentryPush = [null];
else {
- this.sentryPush = [
- parsedFen.sentrypush.split(",").map(sq => {
- return V.SquareToCoords(sq);
- })
- ];
+ // Expand init + dest squares into a full path:
+ const init = V.SquareToCoords(parsedFen.sentrypush.substr(0, 2)),
+ dest = V.SquareToCoords(parsedFen.sentrypush.substr(2));
+ let newPath = [init];
+ const delta = ['x', 'y'].map(i => Math.abs(dest[i] - init[i]));
+ // Check that it's not a knight movement:
+ if (delta[0] == 0 || delta[1] == 0 || delta[0] == delta[1]) {
+ const step = ['x', 'y'].map((i, idx) => {
+ return (dest[i] - init[i]) / delta[idx] || 0
+ });
+ let x = init.x + step[0],
+ y = init.y + step[1];
+ while (x != dest.x || y != dest.y) {
+ newPath.push({ x: x, y: y });
+ x += step[0];
+ y += step[1];
+ }
+ }
+ newPath.push(dest);
+ this.sentryPush = [newPath];
}
}
static GenRandInitFen(randomness) {
if (randomness == 0)
// Deterministic:
- return "jsfqkbnr/pppppppp/8/8/8/8/PPPPPPPP/JSDQKBNR w 0 ahah - -";
+ return "jfsqkbnr/pppppppp/8/8/8/8/PPPPPPPP/JDSQKBNR w 0 ahah - -";
let pieces = { w: new Array(8), b: new Array(8) };
let flags = "";
if (c == 'b') {
// Check if white sentry is on the same color as ours.
// If yes: swap bishop and sentry positions.
- if ((pieces['w'].indexOf('s') - sentryPos) % 2 == 0)
+ // NOTE: test % 2 == 1 because there are 7 slashes.
+ if ((pieces['w'].indexOf('s') - sentryPos) % 2 == 1)
[bishopPos, sentryPos] = [sentryPos, bishopPos];
}
positions.splice(Math.max(randIndex, randIndex_tmp), 1);
canIplay(side, [x, y]) {
return (
- (this.subTurn == 1 && this.turn == side && this.getColor(x, y) == side) ||
+ (this.subTurn == 1 && this.turn == side && this.getColor(x, y) == side)
+ ||
(this.subTurn == 2 && x == this.sentryPos.x && y == this.sentryPos.y)
);
}
return this.filterValid(this.getPotentialMovesFrom(sentrySq));
}
- prePlay(move) {
- if (move.appear.length == 0 && move.vanish.length == 1)
- // The sentry is about to push a piece: subTurn goes from 1 to 2
- this.sentryPos = { x: move.end.x, y: move.end.y };
- if (this.subTurn == 2 && move.vanish[0].p != V.PAWN) {
- // A piece is pushed: forbid array of squares between start and end
- // of move, included (except if it's a pawn)
- let squares = [];
- if ([V.KNIGHT,V.KING].includes(move.vanish[0].p))
- // short-range pieces: just forbid initial square
- squares.push({ x: move.start.x, y: move.start.y });
- else {
- const deltaX = move.end.x - move.start.x;
- const deltaY = move.end.y - move.start.y;
- const step = [
- deltaX / Math.abs(deltaX) || 0,
- deltaY / Math.abs(deltaY) || 0
- ];
- for (
- let sq = {x: move.start.x, y: move.start.y};
- sq.x != move.end.x || sq.y != move.end.y;
- sq.x += step[0], sq.y += step[1]
- ) {
- squares.push({ x: sq.x, y: sq.y });
- }
- }
- // Add end square as well, to know if I was pushed (useful for lancers)
- squares.push({ x: move.end.x, y: move.end.y });
- this.sentryPush.push(squares);
- } else this.sentryPush.push(null);
- }
-
- play(move) {
- this.prePlay(move);
- move.flags = JSON.stringify(this.aggregateFlags());
- this.epSquares.push(this.getEpSquare(move));
- V.PlayOnBoard(this.board, move);
- // Is it a sentry push? (useful for undo)
- move.sentryPush = (this.subTurn == 2);
- if (this.subTurn == 1) this.movesCount++;
- if (move.appear.length == 0 && move.vanish.length == 1) this.subTurn = 2;
- else {
- // Turn changes only if not a sentry "pre-push"
- this.turn = V.GetOppCol(this.turn);
- this.subTurn = 1;
- }
- this.postPlay(move);
- }
-
- postPlay(move) {
- if (move.vanish.length == 0 || this.subTurn == 2)
- // Special pass move of the king, or sentry pre-push: nothing to update
- return;
- const c = move.vanish[0].c;
- const piece = move.vanish[0].p;
- const firstRank = c == "w" ? V.size.x - 1 : 0;
-
- if (piece == V.KING) {
- this.kingPos[c][0] = move.appear[0].x;
- this.kingPos[c][1] = move.appear[0].y;
- this.castleFlags[c] = [V.size.y, V.size.y];
- return;
- }
- // Update castling flags if rooks are moved
- const oppCol = V.GetOppCol(c);
- const oppFirstRank = V.size.x - 1 - firstRank;
- if (
- move.start.x == firstRank && //our rook moves?
- this.castleFlags[c].includes(move.start.y)
- ) {
- const flagIdx = (move.start.y == this.castleFlags[c][0] ? 0 : 1);
- this.castleFlags[c][flagIdx] = V.size.y;
- } else if (
- move.end.x == oppFirstRank && //we took opponent rook?
- this.castleFlags[oppCol].includes(move.end.y)
- ) {
- const flagIdx = (move.end.y == this.castleFlags[oppCol][0] ? 0 : 1);
- this.castleFlags[oppCol][flagIdx] = V.size.y;
- }
- }
-
- undo(move) {
- this.epSquares.pop();
- this.disaggregateFlags(JSON.parse(move.flags));
- V.UndoOnBoard(this.board, move);
- // Decrement movesCount except if the move is a sentry push
- if (!move.sentryPush) this.movesCount--;
- if (this.subTurn == 2) this.subTurn = 1;
- else {
- this.turn = V.GetOppCol(this.turn);
- if (move.sentryPush) this.subTurn = 2;
- }
- this.postUndo(move);
- }
-
- postUndo(move) {
- super.postUndo(move);
- this.sentryPush.pop();
- }
-
isAttacked(sq, color) {
return (
super.isAttacked(sq, color) ||
case V.QUEEN:
return sliderAttack(V.steps[V.ROOK].concat(V.steps[V.BISHOP]));
case V.LANCER: {
- // Special case: as long as no enemy units stands in-between, it attacks
- // (if it points toward the king).
+ // Special case: as long as no enemy units stands in-between,
+ // it attacks (if it points toward the king).
const allowedStep = V.LANCER_DIRS[this.board[x1][y1].charAt(1)];
return sliderAttack([allowedStep], "lancer");
}
// Jailer doesn't capture or give check
+ prePlay(move) {
+ if (move.appear.length == 0 && move.vanish.length == 1)
+ // The sentry is about to push a piece: subTurn goes from 1 to 2
+ this.sentryPos = { x: move.end.x, y: move.end.y };
+ if (this.subTurn == 2 && move.vanish[0].p != V.PAWN) {
+ // A piece is pushed: forbid array of squares between start and end
+ // of move, included (except if it's a pawn)
+ let squares = [];
+ if ([V.KNIGHT,V.KING].includes(move.vanish[0].p))
+ // short-range pieces: just forbid initial square
+ squares.push({ x: move.start.x, y: move.start.y });
+ else {
+ const deltaX = move.end.x - move.start.x;
+ const deltaY = move.end.y - move.start.y;
+ const step = [
+ deltaX / Math.abs(deltaX) || 0,
+ deltaY / Math.abs(deltaY) || 0
+ ];
+ for (
+ let sq = {x: move.start.x, y: move.start.y};
+ sq.x != move.end.x || sq.y != move.end.y;
+ sq.x += step[0], sq.y += step[1]
+ ) {
+ squares.push({ x: sq.x, y: sq.y });
+ }
+ }
+ // Add end square as well, to know if I was pushed (useful for lancers)
+ squares.push({ x: move.end.x, y: move.end.y });
+ this.sentryPush.push(squares);
+ } else this.sentryPush.push(null);
+ }
+
+ play(move) {
+ this.prePlay(move);
+ move.flags = JSON.stringify(this.aggregateFlags());
+ this.epSquares.push(this.getEpSquare(move));
+ V.PlayOnBoard(this.board, move);
+ // Is it a sentry push? (useful for undo)
+ move.sentryPush = (this.subTurn == 2);
+ if (this.subTurn == 1) this.movesCount++;
+ if (move.appear.length == 0 && move.vanish.length == 1) this.subTurn = 2;
+ else {
+ // Turn changes only if not a sentry "pre-push"
+ this.turn = V.GetOppCol(this.turn);
+ this.subTurn = 1;
+ }
+ this.postPlay(move);
+ }
+
+ postPlay(move) {
+ if (move.vanish.length == 0 || this.subTurn == 2)
+ // Special pass move of the king, or sentry pre-push: nothing to update
+ return;
+ const c = move.vanish[0].c;
+ const piece = move.vanish[0].p;
+ const firstRank = c == "w" ? V.size.x - 1 : 0;
+
+ if (piece == V.KING) {
+ this.kingPos[c][0] = move.appear[0].x;
+ this.kingPos[c][1] = move.appear[0].y;
+ this.castleFlags[c] = [V.size.y, V.size.y];
+ return;
+ }
+ // Update castling flags if rooks are moved
+ const oppCol = V.GetOppCol(c);
+ const oppFirstRank = V.size.x - 1 - firstRank;
+ if (
+ move.start.x == firstRank && //our rook moves?
+ this.castleFlags[c].includes(move.start.y)
+ ) {
+ const flagIdx = (move.start.y == this.castleFlags[c][0] ? 0 : 1);
+ this.castleFlags[c][flagIdx] = V.size.y;
+ } else if (
+ move.end.x == oppFirstRank && //we took opponent rook?
+ this.castleFlags[oppCol].includes(move.end.y)
+ ) {
+ const flagIdx = (move.end.y == this.castleFlags[oppCol][0] ? 0 : 1);
+ this.castleFlags[oppCol][flagIdx] = V.size.y;
+ }
+ }
+
+ undo(move) {
+ this.epSquares.pop();
+ this.disaggregateFlags(JSON.parse(move.flags));
+ V.UndoOnBoard(this.board, move);
+ // Decrement movesCount except if the move is a sentry push
+ if (!move.sentryPush) this.movesCount--;
+ if (this.subTurn == 2) this.subTurn = 1;
+ else {
+ this.turn = V.GetOppCol(this.turn);
+ if (move.sentryPush) this.subTurn = 2;
+ }
+ this.postUndo(move);
+ }
+
+ postUndo(move) {
+ super.postUndo(move);
+ this.sentryPush.pop();
+ }
+
static get VALUES() {
return Object.assign(
{ l: 4.8, s: 2.8, j: 3.8 }, //Jeff K. estimations
if (Object.keys(V.LANCER_DIRNAMES).includes(move.vanish[0].p))
// Lancer: add direction info
notation += "=" + V.LANCER_DIRNAMES[move.appear[0].p];
+ else if (
+ move.vanish[0].p == V.PAWN &&
+ Object.keys(V.LANCER_DIRNAMES).includes(move.appear[0].p)
+ ) {
+ // Fix promotions in lancer:
+ notation = notation.slice(0, -1) +
+ "L:" + V.LANCER_DIRNAMES[move.appear[0].p];
+ }
return notation;
}
};