add the ability to detect checkmate without taking the king

This commit is contained in:
Jesse D. McDonald 2020-04-24 23:16:21 -05:00
parent db5f56735b
commit 204d7acddc
2 changed files with 41 additions and 11 deletions

View File

@ -4,7 +4,8 @@ import {Iterator} from './iterator.js';
/* Game states */
const PLAYING = 'playing';
const ENDED = 'ended';
const RESIGNED = 'resigned';
const CHECKMATE = 'checkmate';
/* Sides */
const LIGHT = 'light';
@ -393,7 +394,7 @@ function addHistory(game) {
result += '(' + move.promotion.toUpperCase() + ')';
}
if (move.took === KING) {
if (game.status === CHECKMATE) {
result += '#';
} else if (game.isInCheck()) {
result += '+';
@ -936,7 +937,31 @@ class Game {
this._redo = [];
if (took === KING) {
this._status = ENDED;
this._status = CHECKMATE;
} else if (this._history && this.isInCheck(this._player)) {
/*
* NOTE: Preemptive checkmate detection is not performed on
* simulated games (without history) to prevent recursion.
*/
let canEscape = false;
for (const tryFrom of this._board.findPieces(this._player, true)) {
for (const tryTo of this.legalMoves(this._player, tryFrom)) {
if (!this.isDeadEnd(tryFrom, tryTo)) {
canEscape = true;
break;
}
}
if (canEscape) {
break;
}
}
if (!canEscape) {
this._status = CHECKMATE;
}
}
addHistory(this);
@ -960,7 +985,7 @@ class Game {
this._checkCache = {};
this._moves.push(move);
this._redo = [];
this._status = ENDED;
this._status = RESIGNED;
addHistory(this);
}
@ -974,11 +999,10 @@ class Game {
}
get winner() {
const move = this.lastMove;
if (move && move.resign) {
if (this._status === RESIGNED) {
return otherSide(this.lastMove.side);
} else if (move && move.took === KING) {
return move.side;
} else if (this._status === CHECKMATE) {
return this.lastMove.side;
} else {
return null;
}
@ -1063,7 +1087,7 @@ export default {
Board, Game,
/* Game States */
PLAYING, ENDED,
PLAYING, RESIGNED, CHECKMATE,
/* Sides */
LIGHT, DARK,

View File

@ -369,7 +369,9 @@ $(function (){
}
if (winner) {
if (lastMove && lastMove.resign) {
if (game.status === PS.CHECKMATE) {
msg += 'Checkmate! ';
} else if (lastMove && lastMove.resign) {
msg += (lastMove.side === PS.LIGHT ? 'Light' : 'Dark') + ' player resigned. ';
}
msg += (winner === PS.LIGHT ? 'Light' : 'Dark') + ' player won!';
@ -486,7 +488,11 @@ $(function (){
const winner = currentGame.winner;
const lastMove = currentGame.lastMove || {};
const lastMeta = lastMove.meta || {};
const status = !winner ? null : (lastMove.took === PS.KING) ? 'mate' : 'ended';
const status =
(currentGame.status === PS.PLAYING) ? null :
(currentGame.status === PS.CHECKMATE) ? 'checkmate' :
(currentGame.status === PS.RESIGNED) ? 'resigned' :
'ended';
const meta = {
lightName,