Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions public/images/icons/checkmate.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions public/images/icons/resign.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions public/images/icons/stalemate.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions public/images/icons/timeout.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions public/images/icons/victory.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 47 additions & 0 deletions ui/lib/css/theme/board/_chessground.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
@import 'board-2d';

@keyframes pulse {
0% {
background-size: 0%;
top: -1%;
left: 11%;
opacity: 0.2;
}
100% {
background-size: 45%;
top: -2.8%;
left: 9.8%;
opacity: 0.98;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.6));
}
}

cg-board {
@extend %box-shadow, %abs-100;
@include prevent-select;
Expand Down Expand Up @@ -118,6 +134,37 @@ square {
&.bh1 piece {
opacity: 0.98;
}

&.king-win {
background-image: url(../images/icons/victory.svg);
}

&.king-draw {
background-image: url(../images/icons/stalemate.svg);
}

&.king-lose-checkmate {
background-image: url(../images/icons/checkmate.svg);
}

&.king-lose-resign {
background-image: url(../images/icons/resign.svg);
}

&.king-lose-timeout {
background-image: url(../images/icons/timeout.svg);
}

&.king-win,
&.king-draw,
&.king-lose-checkmate,
&.king-lose-resign,
&.king-lose-timeout {
background-color: transparent;
background-repeat: no-repeat;
z-index: 5;
animation: pulse 0.4s ease-out 1 forwards;
}
}

piece {
Expand Down
1 change: 1 addition & 0 deletions ui/round/src/ctrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ export default class RoundController implements MoveRootCtrl {
) {
notify(viewStatus(this.data));
}
if (!this.replaying()) groundReload(this);
};

challengeRematch = async (): Promise<void> => {
Expand Down
38 changes: 37 additions & 1 deletion ui/round/src/ground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,47 @@ import { uciToMove } from '@lichess-org/chessground/util';
import { ShowResizeHandle, Coords, MoveEvent } from 'lib/prefs';
import { storage } from 'lib/storage';
import { Chessground as makeChessground } from '@lichess-org/chessground';
import { finished, status } from 'lib/game/status';

export function makeConfig(ctrl: RoundController): CgConfig {
const data = ctrl.data,
hooks = ctrl.makeCgHooks(),
step = plyStep(data, ctrl.ply),
playing = ctrl.isPlaying();
playing = ctrl.isPlaying(),
gameFinished = finished(data),
customHighlights = new Map<Key, string>();
if (gameFinished && data.game.variant.key == 'standard') {
const gameStatus = data.game.status.id;
const winner = data.game.winner,
loser = winner === 'white' ? 'black' : winner === 'black' ? 'white' : undefined;
if (winner) {
const winningKingSquare = util.findKingSquare(step.fen, winner);
if (winningKingSquare) {
customHighlights.set(winningKingSquare as Key, 'king-win');
}
}
if (loser) {
const losingKingSquare = util.findKingSquare(step.fen, loser);
if (losingKingSquare) {
if (gameStatus === status.mate) {
customHighlights.set(losingKingSquare as Key, 'king-lose-checkmate');
} else if (gameStatus === status.outoftime || gameStatus === status.timeout) {
customHighlights.set(losingKingSquare as Key, 'king-lose-timeout');
} else if (gameStatus === status.resign) {
customHighlights.set(losingKingSquare as Key, 'king-lose-resign');
}
}
} else if (
gameStatus === status.draw ||
gameStatus === status.stalemate ||
gameStatus === status.timeout
) {
const white_king = util.findKingSquare(step.fen, 'white');
const black_king = util.findKingSquare(step.fen, 'black');
customHighlights.set(white_king as Key, 'king-draw');
customHighlights.set(black_king as Key, 'king-draw');
}
}
return {
fen: step.fen,
orientation: boardOrientation(data, ctrl.flip),
Expand All @@ -28,6 +63,7 @@ export function makeConfig(ctrl: RoundController): CgConfig {
highlight: {
lastMove: data.pref.highlight,
check: data.pref.highlight,
custom: customHighlights,
},
events: {
move: hooks.onMove,
Expand Down
23 changes: 23 additions & 0 deletions ui/round/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,29 @@ export function parsePossibleMoves(dests?: EncodedDests): Dests {
return dec;
}

export function findKingSquare(fen: string, color: Color): string | null {
const rows = fen.split(' ')[0].split('/');
const kingChar = color === 'white' ? 'K' : 'k';

let rank = 8;
for (const row of rows) {
let fileIndex = 0;
for (const ch of row) {
if (/\d/.test(ch)) {
fileIndex += parseInt(ch, 10);
} else {
const file = 'abcdefgh'[fileIndex];
if (ch === kingChar) {
return `${file}${rank}`;
}
fileIndex++;
}
}
rank--;
}
return null;
}

export const firstPly = (d: RoundData): number => d.steps[0].ply;

export const lastPly = (d: RoundData): number => lastStep(d).ply;
Expand Down
Loading