block chain moves which are known dead ends
This commit is contained in:
parent
612a39e891
commit
2171bb00ee
|
|
@ -757,6 +757,72 @@ class Game {
|
||||||
return recordCheck(this, false);
|
return recordCheck(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isDeadEnd(from, to) {
|
||||||
|
const side = this._player;
|
||||||
|
const sim = new Game(this);
|
||||||
|
sim.dropHistory();
|
||||||
|
|
||||||
|
try {
|
||||||
|
sim.move(from, to);
|
||||||
|
} catch (err) {
|
||||||
|
/* illegal moves are automatic dead ends */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sim._board.phantom) {
|
||||||
|
/* moves that leave the player in check are also dead ends */
|
||||||
|
/* otherwise this is a legal non-chain move, so not a dead end */
|
||||||
|
return sim.isInCheck(side);
|
||||||
|
}
|
||||||
|
|
||||||
|
const seen = new Set();
|
||||||
|
let queue = [sim];
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
while (queue.length > 0) {
|
||||||
|
const game = queue[0];
|
||||||
|
queue = queue.slice(1);
|
||||||
|
|
||||||
|
seen.add(game._board.toString());
|
||||||
|
|
||||||
|
/* look for another piece that can reach the king or continue the chain */
|
||||||
|
for (const toNext of game.legalMoves(side, PHANTOM, true)) {
|
||||||
|
if (counter >= 300) {
|
||||||
|
/* this is taking too long */
|
||||||
|
const newMoves = game._moves.length - this._moves.length;
|
||||||
|
console.log(`stopped looking for dead end after ${counter} moves (max length was ${newMoves})`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
++counter;
|
||||||
|
|
||||||
|
const game2 = new Game(game);
|
||||||
|
try {
|
||||||
|
game2.move(PHANTOM, toNext);
|
||||||
|
} catch (err) {
|
||||||
|
/* internal error */
|
||||||
|
console.log('isDeadEnd:', err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!game2._board.phantom) {
|
||||||
|
/* skip moves that would leave the player in check */
|
||||||
|
if (!game2.isInCheck(side)) {
|
||||||
|
/* it's a legal non-chain move, so not a dead end */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!seen.has(game2._board.toString())) {
|
||||||
|
/* we haven't seen this exact board state before */
|
||||||
|
queue.push(game2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* an exhaustive search didn't uncover any legal ways to end the chain */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
move(from, to, meta) {
|
move(from, to, meta) {
|
||||||
if (this._status !== PLAYING) {
|
if (this._status !== PLAYING) {
|
||||||
throw { message: "can't move, game is already over" };
|
throw { message: "can't move, game is already over" };
|
||||||
|
|
|
||||||
|
|
@ -147,14 +147,9 @@ $(function (){
|
||||||
const from = piece.data('location');
|
const from = piece.data('location');
|
||||||
const legals = currentGame.legalMoves(side, from);
|
const legals = currentGame.legalMoves(side, from);
|
||||||
for (const there of legals) {
|
for (const there of legals) {
|
||||||
try {
|
if (currentGame.isDeadEnd(from, there)) {
|
||||||
const preview = new PS.Game(currentGame);
|
continue;
|
||||||
preview.dropHistory();
|
}
|
||||||
preview.move(from, there);
|
|
||||||
if (preview.isInCheck(side)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch (err) {}
|
|
||||||
|
|
||||||
const square = cbSquare(there);
|
const square = cbSquare(there);
|
||||||
square.addClass('cb-legal')
|
square.addClass('cb-legal')
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue