for (let part of amoveParts) {
if (part != "-") {
for (let psq of part.split("."))
- if (!psq.match(/^[a-r]{3}[1-8]$/)) return false;
+ if (!psq.match(/^[a-z]{3}[1-8]$/)) return false;
}
}
}
// (not undoing a potential move + action of the opponent)
this.play(m);
let res = this.underCheck(color);
- let isOpposite = La > 0 && this.oppositeMoves(this.amoves[La-1], m);
- if (res || isOpposite) {
- const moves2 = this.getAllPotentialMoves();
- for (let m2 of moves2) {
- this.play(m2);
- const res2 = this.underCheck(color);
- const amove = this.getAmove(m, m2);
- isOpposite =
- La > 0 && this.oppositeMoves(this.amoves[La-1], amove);
- this.undo(m2);
- if (!res2 && !isOpposite) {
- res = false;
- break;
+ if (this.subTurn == 2) {
+ let isOpposite = La > 0 && this.oppositeMoves(this.amoves[La-1], m);
+ if (res || isOpposite) {
+ const moves2 = this.getAllPotentialMoves();
+ for (let m2 of moves2) {
+ this.play(m2);
+ const res2 = this.underCheck(color);
+ const amove = this.getAmove(m, m2);
+ isOpposite =
+ La > 0 && this.oppositeMoves(this.amoves[La-1], amove);
+ this.undo(m2);
+ if (!res2 && !isOpposite) {
+ res = false;
+ break;
+ }
}
}
}
return potentialMoves;
}
+ getEmptyMove() {
+ return new Move({
+ start: { x: -1, y: -1 },
+ end: { x: -1, y: -1 },
+ appear: [],
+ vanish: []
+ });
+ }
+
doClick(square) {
// A click to promote a piece on subTurn 2 would trigger this.
// For now it would then return [NaN, NaN] because surrounding squares
!this.underCheck(this.turn) &&
(La == 0 || !this.oppositeMoves(this.amoves[La-1], this.firstMove[Lf-1]))
) {
- return {
- start: { x: -1, y: -1 },
- end: { x: -1, y: -1 },
- appear: [],
- vanish: []
- };
+ return this.getEmptyMove();
}
return null;
}
play(move) {
- move.flags = JSON.stringify(this.aggregateFlags());
- V.PlayOnBoard(this.board, move);
- // NOTE; if subTurn == 1, there may be no available moves at subTurn == 2.
- // However, it's quite easier to wait for a user click.
- if (this.subTurn == 2) {
+ if (this.subTurn == 1 && move.vanish.length == 0) {
+ // Patch to work with old format: (TODO: remove later)
+ move.ignore = true;
+ return;
+ }
+ const color = this.turn;
+ move.subTurn = this.subTurn; //for undo
+ const gotoNext = (mv) => {
const L = this.firstMove.length;
- this.amoves.push(this.getAmove(this.firstMove[L-1], move));
- this.turn = V.GetOppCol(this.turn);
+ this.amoves.push(this.getAmove(this.firstMove[L-1], mv));
+ this.turn = V.GetOppCol(color);
+ this.subTurn = 1;
this.movesCount++;
+ };
+ move.flags = JSON.stringify(this.aggregateFlags());
+ V.PlayOnBoard(this.board, move);
+ if (this.subTurn == 2) gotoNext(move);
+ else {
+ this.subTurn = 2;
+ this.firstMove.push(move);
+ this.toNewKingPos(move);
+ if (
+ // Condition is true on empty arrays:
+ this.getAllPotentialMoves().every(m => {
+ V.PlayOnBoard(this.board, m);
+ this.toNewKingPos(m);
+ const res = this.underCheck(color);
+ V.UndoOnBoard(this.board, m);
+ this.toOldKingPos(m);
+ return res;
+ })
+ ) {
+ // No valid move at subTurn 2
+ gotoNext(this.getEmptyMove());
+ }
+ this.toOldKingPos(move);
}
- else this.firstMove.push(move);
- this.subTurn = 3 - this.subTurn;
this.postPlay(move);
}
- postPlay(move) {
- if (move.start.x < 0) return;
+ toNewKingPos(move) {
for (let a of move.appear)
if (a.p == V.KING) this.kingPos[a.c] = [a.x, a.y];
+ }
+
+ postPlay(move) {
+ if (move.start.x < 0) return;
+ this.toNewKingPos(move);
this.updateCastleFlags(move);
}
}
undo(move) {
+ if (!!move.ignore) return; //TODO: remove that later
this.disaggregateFlags(JSON.parse(move.flags));
V.UndoOnBoard(this.board, move);
if (this.subTurn == 1) {
this.turn = V.GetOppCol(this.turn);
this.movesCount--;
}
- else this.firstMove.pop();
- this.subTurn = 3 - this.subTurn;
- this.postUndo(move);
+ if (move.subTurn == 1) this.firstMove.pop();
+ this.subTurn = move.subTurn;
+ this.toOldKingPos(move);
}
- postUndo(move) {
+ toOldKingPos(move) {
// (Potentially) Reset king position
for (let v of move.vanish)
if (v.p == V.KING) this.kingPos[v.c] = [v.x, v.y];
};
moves.forEach(m => {
this.play(m);
- m.eval = (color == "w" ? -1 : 1) * maxeval;
- const moves2 = this.getAllValidMoves().concat([emptyMove]);
- m.next = moves2[0];
- moves2.forEach(m2 => {
- this.play(m2);
- const score = this.getCurrentScore();
- let mvEval = 0;
- if (score != "1/2") {
- if (score != "*") mvEval = (score == "1-0" ? 1 : -1) * maxeval;
- else mvEval = this.evalPosition();
- }
- if (
- (color == 'w' && mvEval > m.eval) ||
- (color == 'b' && mvEval < m.eval)
- ) {
- m.eval = mvEval;
- m.next = m2;
- }
- this.undo(m2);
- });
+ if (this.turn != color) m.eval = this.evalPosition();
+ else {
+ m.eval = (color == "w" ? -1 : 1) * maxeval;
+ const moves2 = this.getAllValidMoves().concat([emptyMove]);
+ m.next = moves2[0];
+ moves2.forEach(m2 => {
+ this.play(m2);
+ const score = this.getCurrentScore();
+ let mvEval = 0;
+ if (score != "1/2") {
+ if (score != "*") mvEval = (score == "1-0" ? 1 : -1) * maxeval;
+ else mvEval = this.evalPosition();
+ }
+ if (
+ (color == 'w' && mvEval > m.eval) ||
+ (color == 'b' && mvEval < m.eval)
+ ) {
+ m.eval = mvEval;
+ m.next = m2;
+ }
+ this.undo(m2);
+ });
+ }
this.undo(m);
});
moves.sort((a, b) => {
for (let i = 1; i < moves.length && moves[i].eval == moves[0].eval; i++)
candidates.push(i);
const mIdx = candidates[randInt(candidates.length)];
+ if (!moves[mIdx].next) return moves[mIdx];
const move2 = moves[mIdx].next;
delete moves[mIdx]["next"];
return [moves[mIdx], move2];