Upstream lichess-org/lila state of the touched files before f8fadacc65
This commit is contained in:
1 parent
8e8500f7ac
commit
818e05beaf
2 files changed
+14
-129
No files matched your search
+14
-18
@@ -1,11 +1,10 @@
|
||||
import type { DrawShape } from '@lichess-org/chessground/draw';
|
||||
import type { Outcome, Position } from 'chessops';
|
||||
import type { Outcome } from 'chessops';
|
||||
import { parseFen } from 'chessops/fen';
|
||||
import { makeSquare, opposite } from 'chessops/util';
|
||||
|
||||
import type { PositionResult } from '@/tree/types';
|
||||
|
||||
import { endgameGlyphs } from './glyphs';
|
||||
import { fenColor } from './chess';
|
||||
import { endgameGlyphs, type EndgameGlyph } from './glyphs';
|
||||
import type { StatusName } from './status';
|
||||
|
||||
export interface EndgameResult {
|
||||
@@ -15,33 +14,33 @@ export interface EndgameResult {
|
||||
|
||||
type EndgameNode = {
|
||||
fen: FEN;
|
||||
pos: () => PositionResult;
|
||||
outcome: () => Outcome | undefined;
|
||||
check: () => boolean;
|
||||
dests: () => Dests;
|
||||
};
|
||||
|
||||
const terminalStatus = (pos: Position, outcome: Outcome): StatusName =>
|
||||
outcome.winner ? (pos.isCheckmate() ? 'mate' : 'variantEnd') : pos.isStalemate() ? 'stalemate' : 'draw';
|
||||
|
||||
const endgameResult = (
|
||||
node: EndgameNode,
|
||||
isLast: boolean,
|
||||
gameWinner: Color | undefined,
|
||||
gameStatus: StatusName,
|
||||
): EndgameResult => {
|
||||
const outcome = node.dests().size === 0 ? node.outcome() : undefined;
|
||||
if (outcome) return { winner: outcome.winner, status: terminalStatus(node.pos().unwrap(), outcome) };
|
||||
if (!isLast) return {};
|
||||
return { winner: node.outcome()?.winner ?? gameWinner, status: gameStatus };
|
||||
const outcome = node.outcome();
|
||||
const isTerminal = node.dests().size === 0;
|
||||
const isMate = isTerminal && node.check();
|
||||
const isStalemate = isTerminal && !node.check() && outcome && !outcome.winner;
|
||||
|
||||
return {
|
||||
winner: isMate ? opposite(fenColor(node.fen)) : isStalemate ? undefined : (outcome?.winner ?? gameWinner),
|
||||
status: isMate ? 'mate' : isStalemate ? 'stalemate' : gameStatus,
|
||||
};
|
||||
};
|
||||
|
||||
export function endgameShapesForNode(
|
||||
node: EndgameNode,
|
||||
isLast: boolean,
|
||||
gameWinner: Color | undefined,
|
||||
gameStatus: StatusName,
|
||||
): DrawShape[] {
|
||||
const result = endgameResult(node, isLast, gameWinner, gameStatus);
|
||||
const result = endgameResult(node, gameWinner, gameStatus);
|
||||
return endgameShapes(node.fen, result.winner, result.status);
|
||||
}
|
||||
|
||||
@@ -53,8 +52,6 @@ export function findKingSquare(fen: FEN, color: Color): Key | undefined {
|
||||
return king === undefined ? undefined : makeSquare(king);
|
||||
}
|
||||
|
||||
type EndgameGlyph = keyof typeof endgameGlyphs;
|
||||
|
||||
const loserGlyph = (status: StatusName | undefined): EndgameGlyph =>
|
||||
status === 'mate'
|
||||
? 'mate'
|
||||
@@ -95,7 +92,6 @@ export function endgameShapes(
|
||||
};
|
||||
|
||||
if (winner) {
|
||||
add(winner, 'win');
|
||||
add(opposite(winner), loserGlyph(status));
|
||||
} else {
|
||||
const glyph = drawGlyph(status);
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { describe, test } from 'node:test';
|
||||
|
||||
import { endgameShapesForNode } from '../src/game/endgame';
|
||||
import { endgameGlyphs } from '../src/game/glyphs';
|
||||
import type { StatusName } from '../src/game/status';
|
||||
import { completeNode } from '../src/tree/node';
|
||||
|
||||
const glyphName = (html: string | undefined) =>
|
||||
Object.entries(endgameGlyphs).find(([, glyph]) => glyph(0) === html)?.[0];
|
||||
|
||||
type GameEnd = { isLast?: boolean; winner?: Color; status?: StatusName };
|
||||
|
||||
const kingGlyphs = (
|
||||
variant: VariantKey,
|
||||
fen: FEN,
|
||||
{ isLast = false, winner, status = 'started' }: GameEnd = {},
|
||||
) => {
|
||||
const node = completeNode(variant)({ ply: 1, fen });
|
||||
return Object.fromEntries(
|
||||
endgameShapesForNode(node, isLast, winner, status).map(shape => [
|
||||
shape.orig,
|
||||
glyphName(shape.customSvg?.html),
|
||||
]),
|
||||
);
|
||||
};
|
||||
|
||||
describe('endgame glyphs on terminal positions', () => {
|
||||
test('standard checkmate', () =>
|
||||
assert.deepEqual(kingGlyphs('standard', 'R5k1/5ppp/8/8/8/8/8/6K1 b - - 1 1'), {
|
||||
g1: 'win',
|
||||
g8: 'mate',
|
||||
}));
|
||||
|
||||
test('standard stalemate', () =>
|
||||
assert.deepEqual(kingGlyphs('standard', '7k/5Q2/6K1/8/8/8/8/8 b - - 0 1'), {
|
||||
g6: 'stalemate',
|
||||
h8: 'stalemate',
|
||||
}));
|
||||
|
||||
test('atomic king explosion', () =>
|
||||
assert.deepEqual(kingGlyphs('atomic', 'rn2k2r/ppp3pp/8/3ppp2/3P2P1/5P1B/PP5P/RNB4R w kq - 0 12'), {
|
||||
e8: 'win',
|
||||
}));
|
||||
|
||||
test('atomic checkmate', () =>
|
||||
assert.deepEqual(kingGlyphs('atomic', 'R5k1/5ppp/8/8/8/8/8/6K1 b - - 1 1'), {
|
||||
g1: 'win',
|
||||
g8: 'mate',
|
||||
}));
|
||||
|
||||
test('antichess win by losing all pieces', () =>
|
||||
assert.deepEqual(kingGlyphs('antichess', '8/8/8/8/8/8/8/k7 w - - 0 1'), {
|
||||
a1: 'unknown',
|
||||
}));
|
||||
|
||||
test('antichess win by being stalemated', () =>
|
||||
assert.deepEqual(kingGlyphs('antichess', '8/8/8/p7/P7/8/8/7k w - - 0 1'), {
|
||||
h1: 'unknown',
|
||||
}));
|
||||
|
||||
test('king of the hill', () =>
|
||||
assert.deepEqual(kingGlyphs('kingOfTheHill', '8/8/8/8/4K3/8/8/k7 b - - 0 1'), {
|
||||
e4: 'win',
|
||||
a1: 'unknown',
|
||||
}));
|
||||
|
||||
test('racing kings win', () =>
|
||||
assert.deepEqual(kingGlyphs('racingKings', 'K7/8/8/8/8/8/k7/8 b - - 0 1'), {
|
||||
a8: 'win',
|
||||
a2: 'unknown',
|
||||
}));
|
||||
|
||||
test('racing kings draw', () =>
|
||||
assert.deepEqual(kingGlyphs('racingKings', 'K6k/8/8/8/8/8/8/8 w - - 0 1'), {
|
||||
a8: 'draw',
|
||||
h8: 'draw',
|
||||
}));
|
||||
|
||||
test('three-check', () =>
|
||||
assert.deepEqual(
|
||||
kingGlyphs('threeCheck', 'rnb1kbnr/pppp1ppp/8/4p3/4P2q/5P2/PPPP2PP/RNBQKBNR w KQkq - 3+0 0 1'),
|
||||
{ e8: 'win', e1: 'unknown' },
|
||||
));
|
||||
|
||||
test('horde', () =>
|
||||
assert.deepEqual(kingGlyphs('horde', 'k7/8/8/8/8/8/8/8 w - - 0 1'), {
|
||||
a8: 'win',
|
||||
}));
|
||||
});
|
||||
|
||||
describe('endgame glyphs on non-terminal positions', () => {
|
||||
test('crazyhouse check that can be blocked by a drop', () =>
|
||||
assert.deepEqual(kingGlyphs('crazyhouse', 'R5k1/5ppp/8/8/8/8/8/6K1[n] b - - 1 1'), {}));
|
||||
|
||||
test('last move of a resigned game', () =>
|
||||
assert.deepEqual(
|
||||
kingGlyphs('standard', 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1', {
|
||||
isLast: true,
|
||||
winner: 'black',
|
||||
status: 'resign',
|
||||
}),
|
||||
{ e8: 'win', e1: 'resign' },
|
||||
));
|
||||
|
||||
test('mid-game position', () =>
|
||||
assert.deepEqual(
|
||||
kingGlyphs('standard', 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1'),
|
||||
{},
|
||||
));
|
||||
});
|
||||
Reference in new issue
Block a user