return moves;
}
- isAttacked(sq, color, castling) {
- const singleMoveAttack = super.isAttacked(sq, color);
- if (singleMoveAttack) return true;
- if (!!castling) {
- if (this.subTurn == 1)
- // Castling at move 1 could be done into check
- return false;
- return singleMoveAttack;
- }
- // Double-move allowed:
- const curTurn = this.turn;
- this.turn = color;
- const moves1 = super.getAllPotentialMoves();
- this.turn = curTurn;
- for (let move of moves1) {
- this.play(move);
- const res = super.isAttacked(sq, color);
- this.undo(move);
- if (res) return res;
- }
+ isAttacked() {
+ // Goal is king capture => no checks
return false;
}
filterValid(moves) {
- if (this.subTurn == 1) {
- return moves.filter(m1 => {
- this.play(m1);
- // NOTE: no recursion because next call will see subTurn == 2
- const res = super.atLeastOneMove();
- this.undo(m1);
- return res;
- });
- }
- return super.filterValid(moves);
+ return moves;
+ }
+
+ getCheckSquares() {
+ return [];
+ }
+
+ getCurrentScore() {
+ const color = this.turn;
+ if (this.kingPos[color][0] < 0) return (color == 'w' ? "0-1" : "1-0");
+ return "*";
}
play(move) {
else {
this.epSquares.push([epSq]);
this.movesCount++;
- if (this.movesCount == 1) this.turn = "b";
+ if (
+ this.movesCount == 1 ||
+ // King is captured at subTurn 1?
+ (move.vanish.length == 2 && move.vanish[1].p == V.KING)
+ ) {
+ this.turn = "b";
+ }
}
if (this.movesCount > 1) this.subTurn = 3 - this.subTurn;
this.postPlay(move);
const firstRank = c == "w" ? V.size.x - 1 : 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;
+ this.kingPos[c] = [move.appear[0].x, move.appear[0].y];
this.castleFlags[c] = [V.size.y, V.size.y];
return;
}
const oppCol = V.GetOppCol(c);
+ if (move.vanish.length == 2 && move.vanish[1].p == V.KING) {
+ // Opponent's king is captured, game over
+ this.kingPos[oppCol] = [-1, -1];
+ move.captureKing = true; //for undo
+ }
const oppFirstRank = V.size.x - 1 - firstRank;
if (
move.start.x == firstRank && //our rook moves?
) {
const flagIdx = (move.start.y == this.castleFlags[c][0] ? 0 : 1);
this.castleFlags[c][flagIdx] = V.size.y;
- } else if (
+ }
+ else if (
move.end.x == oppFirstRank && //we took opponent rook?
this.castleFlags[oppCol].includes(move.end.y)
) {
undo(move) {
this.disaggregateFlags(JSON.parse(move.flags));
V.UndoOnBoard(this.board, move);
- if (this.subTurn == 2 || this.movesCount == 1) {
+ if (this.subTurn == 2 || this.movesCount == 1 || !!move.captureKing) {
this.epSquares.pop();
this.movesCount--;
if (this.movesCount == 0) this.turn = "w";
this.turn = V.GetOppCol(this.turn);
}
if (this.movesCount > 0) this.subTurn = 3 - this.subTurn;
- super.postUndo(move);
+ this.postUndo(move);
}
- static get VALUES() {
- return {
- p: 1,
- r: 5,
- n: 3,
- b: 3,
- q: 7, //slightly less than in orthodox game
- k: 1000
- };
+ postUndo(move) {
+ if (move.vanish.length == 2 && move.vanish[1].p == V.KING)
+ // Opponent's king was captured
+ this.kingPos[move.vanish[1].c] = [move.vanish[1].x, move.vanish[1].y];
+ super.postUndo(move);
}
// No alpha-beta here, just adapted min-max at depth 2(+1)
// Search best (half) move for opponent turn
const getBestMoveEval = () => {
let score = this.getCurrentScore();
- if (score != "*") {
- if (score == "1/2") return 0;
- return maxeval * (score == "1-0" ? 1 : -1);
- }
+ if (score != "*") return maxeval * (score == "1-0" ? 1 : -1);
let moves = this.getAllValidMoves();
let res = oppCol == "w" ? -maxeval : maxeval;
for (let m of moves) {
this.play(m);
score = this.getCurrentScore();
- // Now turn is oppCol,2
if (score != "*") {
- if (score == "1/2")
- res = oppCol == "w" ? Math.max(res, 0) : Math.min(res, 0);
- else {
- // King captured
- this.undo(m);
- return maxeval * (score == "1-0" ? 1 : -1);
- }
+ // King captured
+ this.undo(m);
+ return maxeval * (score == "1-0" ? 1 : -1);
}
const evalPos = this.evalPosition();
res = oppCol == "w" ? Math.max(res, evalPos) : Math.min(res, evalPos);
return res;
};
- let moves11 = this.getAllValidMoves();
+ const moves11 = this.getAllValidMoves();
+ if (this.movesCount == 0)
+ // First white move at random:
+ return moves11[randInt(moves11.length)];
let doubleMoves = [];
- // Rank moves using a min-max at depth 2(+1)
+ // Rank moves using a min-max at depth 2
for (let i = 0; i < moves11.length; i++) {
this.play(moves11[i]);
- let moves12 = this.getAllValidMoves();
+ const moves12 = this.getAllValidMoves();
for (let j = 0; j < moves12.length; j++) {
this.play(moves12[j]);
doubleMoves.push({
moves: [moves11[i], moves12[j]],
- eval: getBestMoveEval()
+ // Small fluctuations to uniformize play a little
+ eval: getBestMoveEval() + 0.05 - Math.random() / 10
});
this.undo(moves12[j]);
}