Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui/nvui cleanup #16560

Merged
merged 46 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
edf0cdb
use destsToUcis from ui/chess
allanjoseph98 Dec 9, 2024
4b11790
move sanToUci to ui/chess
allanjoseph98 Dec 9, 2024
60e0b60
change some types
allanjoseph98 Dec 9, 2024
686690a
some code golf
allanjoseph98 Dec 9, 2024
c26acd4
use lichessrules chessops compat util
allanjoseph98 Dec 9, 2024
3dad0fb
golf + rename stuff to be more accurate
allanjoseph98 Dec 9, 2024
0e2b7cf
remove unused blindmode variants scala set
allanjoseph98 Dec 10, 2024
cafb9ae
type tweak
allanjoseph98 Dec 10, 2024
08dd1db
distinguish between cash and non cash variables
allanjoseph98 Dec 10, 2024
7e6b26b
rename `Style` to `MoveStyle` for clarity
allanjoseph98 Dec 10, 2024
1c067b8
cast type directly
allanjoseph98 Dec 10, 2024
2f36dac
use roles const from chessops
allanjoseph98 Dec 10, 2024
730a5f8
refactor
allanjoseph98 Dec 10, 2024
410d118
programatically render choice examples
allanjoseph98 Dec 10, 2024
e5cd01d
fix order
allanjoseph98 Dec 10, 2024
fbd6d0e
some weight loss
allanjoseph98 Dec 11, 2024
28d1180
`sanToWords` util func.
allanjoseph98 Dec 11, 2024
1a803a5
remove unused constructor parameter
allanjoseph98 Dec 12, 2024
21c1cc7
golf
allanjoseph98 Dec 12, 2024
036ca3c
correct lichess comment Regex
allanjoseph98 Dec 12, 2024
f242042
fix game start
allanjoseph98 Dec 14, 2024
79750ae
allow racingKings and antichess in nvui
allanjoseph98 Dec 14, 2024
f82f82c
refactor
allanjoseph98 Dec 16, 2024
894dac0
golf puzzle nvui
allanjoseph98 Dec 17, 2024
06d76fb
golf
allanjoseph98 Dec 18, 2024
e08c9c7
refactor:use analyse result rendering
allanjoseph98 Dec 18, 2024
23e014a
king underpromotion regex for antichess
allanjoseph98 Dec 18, 2024
eff01df
key attr regex
allanjoseph98 Dec 31, 2024
650b574
don't assume dests are available
allanjoseph98 Dec 31, 2024
4c4e607
Don't destroy chessground when the board is hidden by snabb. Required…
allanjoseph98 Dec 31, 2024
6dd0ca8
nvui study chapter select
allanjoseph98 Dec 31, 2024
bcea574
maybe pacify gh security warning
allanjoseph98 Dec 31, 2024
5a6b066
nvui study add and edit chapters
allanjoseph98 Dec 31, 2024
dfb3f54
golf
allanjoseph98 Jan 1, 2025
9b7d50f
remove debug
allanjoseph98 Jan 1, 2025
e6108d7
translate some existing commands
allanjoseph98 Jan 1, 2025
4ca3df1
refactor board commands
allanjoseph98 Jan 1, 2025
8c97326
fix puzzle i18n
allanjoseph98 Jan 1, 2025
8d24edc
some more i18n
allanjoseph98 Jan 3, 2025
4c076f9
uci is already treated as optional
allanjoseph98 Jan 3, 2025
cf05aa8
more i18n
allanjoseph98 Jan 4, 2025
ba0ada7
round i18n
allanjoseph98 Jan 4, 2025
8d02d02
golf
allanjoseph98 Jan 4, 2025
8959e5c
Merge branch 'master' into ui-nvui-cleanup
ornicar Jan 13, 2025
244671b
reconfigure chessground on every redraw
allanjoseph98 Jan 18, 2025
dbe1f76
use <select> change events for chapter changes
allanjoseph98 Jan 18, 2025
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
12 changes: 0 additions & 12 deletions modules/game/src/main/Game.scala
Original file line number Diff line number Diff line change
Expand Up @@ -239,18 +239,6 @@ object Game:

val unanalysableVariants: Set[Variant] = Variant.list.all.toSet -- analysableVariants

val blindModeVariants: Set[Variant] = Set(
chess.variant.Standard,
chess.variant.Chess960,
chess.variant.KingOfTheHill,
chess.variant.ThreeCheck,
chess.variant.FromPosition,
chess.variant.Antichess,
chess.variant.Atomic,
chess.variant.RacingKings,
chess.variant.Horde
)

val hordeWhitePawnsSince = instantOf(2015, 4, 11, 10, 0)

def isOldHorde(game: Game) =
Expand Down
102 changes: 43 additions & 59 deletions ui/analyse/src/plugins/analyse.nvui.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { h, type VNode } from 'snabbdom';
import { h, type VNode, type VNodeChildren } from 'snabbdom';
import { defined, prop, type Prop } from 'common';
import { text as xhrText } from 'common/xhr';
import type AnalyseController from '../ctrl';
Expand All @@ -7,7 +7,7 @@ import type { AnalyseData } from '../interfaces';
import type { Player } from 'game';
import viewStatus from 'game/view/status';
import {
type Style,
type MoveStyle,
renderSan,
renderPieces,
renderBoard,
Expand Down Expand Up @@ -119,7 +119,7 @@ export function initModule(ctrl: AnalyseController) {
insert(vnode) {
const $form = $(vnode.elm as HTMLFormElement),
$input = $form.find('.move').val('');
$input[0]!.focus();
$input[0]?.focus();
$form.on('submit', onSubmit(ctrl, notify.set, moveStyle.get, $input));
},
},
Expand All @@ -134,8 +134,6 @@ export function initModule(ctrl: AnalyseController) {
],
),
notify.render(),
// h('h2', 'Actions'),
// h('div.actions', tableInner(ctrl)),
h('h2', 'Computer analysis'),
...cevalView.renderCeval(ctrl),
cevalView.renderPvs(ctrl),
Expand Down Expand Up @@ -165,7 +163,7 @@ export function initModule(ctrl: AnalyseController) {
},
renderBoard(
ctrl.chessground.state.pieces,
ctrl.data.player.color,
ctrl.data.game.variant.key === 'racingKings' ? 'white' : ctrl.data.player.color,
pieceStyle.get(),
prefixStyle.get(),
positionStyle.get(),
Expand Down Expand Up @@ -279,31 +277,22 @@ function renderEvalAndDepth(ctrl: AnalyseController): string {
evalStr = evalInfo(bestEv);
depthStr = depthInfo(evs.client, !!evs.client?.cloud);
}
if (!evalStr) {
if (!ctrl.ceval.allowed()) return NOT_ALLOWED;
else if (!ctrl.ceval.possible) return NOT_POSSIBLE;
else return NOT_ENABLED;
} else {
return evalStr + ' ' + depthStr;
}
if (!evalStr)
return !ctrl.ceval.allowed() ? NOT_ALLOWED : !ctrl.ceval.possible ? NOT_POSSIBLE : NOT_ENABLED;
else return evalStr + ' ' + depthStr;
}

function evalInfo(bestEv: EvalScore | undefined): string {
if (bestEv) {
if (defined(bestEv.cp)) return renderEval(bestEv.cp).replace('-', '−');
else if (defined(bestEv.mate))
return `mate in ${Math.abs(bestEv.mate)} for ${bestEv.mate > 0 ? 'white' : 'black'}`;
}
return '';
}
const evalInfo = (bestEv: EvalScore | undefined): string =>
defined(bestEv?.cp)
? renderEval(bestEv.cp).replace('-', '−')
: defined(bestEv?.mate)
? `mate in ${Math.abs(bestEv.mate)} for ${bestEv.mate > 0 ? 'white' : 'black'}`
: '';

function depthInfo(clientEv: Tree.ClientEval | undefined, isCloud: boolean): string {
if (!clientEv) return '';
const depth = clientEv.depth || 0;
return i18n.site.depthX(depth) + isCloud ? ' Cloud' : '';
}
const depthInfo = (clientEv: Tree.ClientEval | undefined, isCloud: boolean): string =>
clientEv ? `${i18n.site.depthX(clientEv.depth || 0)} ${isCloud ? 'Cloud' : ''}` : '';

function renderBestMove(ctrl: AnalyseController, style: Style): string {
function renderBestMove(ctrl: AnalyseController, style: MoveStyle): string {
const instance = ctrl.getCeval();
if (!instance.allowed()) return NOT_ALLOWED;
if (!instance.possible) return NOT_POSSIBLE;
Expand Down Expand Up @@ -352,7 +341,7 @@ function renderResult(ctrl: AnalyseController): VNode[] {
return [];
}

function renderCurrentLine(ctrl: AnalyseController, style: Style): (string | VNode)[] {
function renderCurrentLine(ctrl: AnalyseController, style: MoveStyle): VNodeChildren {
if (ctrl.path.length === 0) {
return renderMainline(ctrl.mainline, ctrl.path, style);
} else {
Expand All @@ -361,8 +350,14 @@ function renderCurrentLine(ctrl: AnalyseController, style: Style): (string | VNo
}
}

function onSubmit(ctrl: AnalyseController, notify: (txt: string) => void, style: () => Style, $input: Cash) {
return function () {
function onSubmit(
ctrl: AnalyseController,
notify: (txt: string) => void,
style: () => MoveStyle,
$input: Cash,
) {
return (e: SubmitEvent) => {
e.preventDefault();
let input = castlingFlavours(($input.val() as string).trim());
if (isShortCommand(input)) input = '/' + input;
if (input[0] === '/') onCommand(ctrl, notify, input.slice(1), style());
Expand All @@ -373,31 +368,23 @@ function onSubmit(ctrl: AnalyseController, notify: (txt: string) => void, style:
else notify('Invalid command');
}
$input.val('');
return false;
};
}

const shortCommands = ['p', 's', 'next', 'prev', 'eval', 'best'];
const isShortCommand = (input: string) =>
['p', 's', 'next', 'prev', 'eval', 'best'].includes(input.split(' ')[0].toLowerCase());

function isShortCommand(input: string): boolean {
return shortCommands.includes(input.split(' ')[0].toLowerCase());
}

function onCommand(ctrl: AnalyseController, notify: (txt: string) => void, c: string, style: Style) {
function onCommand(ctrl: AnalyseController, notify: (txt: string) => void, c: string, style: MoveStyle) {
const lowered = c.toLowerCase();
if (lowered === 'next') {
next(ctrl);
ctrl.redraw();
} else if (lowered === 'prev') {
prev(ctrl);
ctrl.redraw();
} else if (lowered === 'next line') {
jumpNextLine(ctrl);
ctrl.redraw();
} else if (lowered === 'prev line') {
jumpPrevLine(ctrl);
const doAndRedraw = (fn: (ctrl: AnalyseController) => void): void => {
fn(ctrl);
ctrl.redraw();
} else if (lowered === 'eval') notify(renderEvalAndDepth(ctrl));
};
if (lowered === 'next') doAndRedraw(next);
else if (lowered === 'prev') doAndRedraw(prev);
else if (lowered === 'next line') doAndRedraw(jumpNextLine);
else if (lowered === 'prev line') doAndRedraw(jumpPrevLine);
else if (lowered === 'eval') notify(renderEvalAndDepth(ctrl));
else if (lowered === 'best') notify(renderBestMove(ctrl, style));
else {
const pieces = ctrl.chessground.state.pieces;
Expand All @@ -411,16 +398,15 @@ function onCommand(ctrl: AnalyseController, notify: (txt: string) => void, c: st

const analysisGlyphs = ['?!', '?', '??'];

function renderAcpl(ctrl: AnalyseController, style: Style): MaybeVNodes | undefined {
function renderAcpl(ctrl: AnalyseController, style: MoveStyle): MaybeVNodes | undefined {
const anal = ctrl.data.analysis;
if (!anal) return undefined;
const analysisNodes = ctrl.mainline.filter(n =>
(n.glyphs || []).find(g => analysisGlyphs.includes(g.symbol)),
);
const res: Array<VNode> = [];
['white', 'black'].forEach((color: Color) => {
const acpl = anal[color].acpl;
res.push(h('h3', `${color} player: ${acpl} ACPL`));
res.push(h('h3', `${color} player: ${anal[color].acpl} ACPL`));
res.push(
h(
'select',
Expand Down Expand Up @@ -486,7 +472,7 @@ function renderLineIndex(ctrl: AnalyseController): string {
return of > 1 ? `, line ${i + 1} of ${of} ,` : '';
}

function renderCurrentNode(ctrl: AnalyseController, style: Style): string {
function renderCurrentNode(ctrl: AnalyseController, style: MoveStyle): string {
const node = ctrl.node;
if (!node.san || !node.uci) return 'Initial position';
return [
Expand All @@ -499,9 +485,8 @@ function renderCurrentNode(ctrl: AnalyseController, style: Style): string {
.trim();
}

function renderPlayer(ctrl: AnalyseController, player: Player) {
return player.ai ? i18n.site.aiNameLevelAiLevel('Stockfish', player.ai) : userHtml(ctrl, player);
}
const renderPlayer = (ctrl: AnalyseController, player: Player): VNodeChildren =>
player.ai ? i18n.site.aiNameLevelAiLevel('Stockfish', player.ai) : userHtml(ctrl, player);

function userHtml(ctrl: AnalyseController, player: Player) {
const d = ctrl.data,
Expand All @@ -523,9 +508,8 @@ function userHtml(ctrl: AnalyseController, player: Player) {
: 'Anonymous';
}

function playerByColor(d: AnalyseData, color: Color) {
return color === d.player.color ? d.player : d.opponent;
}
const playerByColor = (d: AnalyseData, color: Color): Player =>
color === d.player.color ? d.player : d.opponent;

const jumpNextLine = (ctrl: AnalyseController) => jumpLine(ctrl, 1);
const jumpPrevLine = (ctrl: AnalyseController) => jumpLine(ctrl, -1);
Expand Down
65 changes: 33 additions & 32 deletions ui/chess/src/sanWriter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { charToRole, type Square } from 'chessops';

export type Board = { pieces: { [key: number]: string }; turn: boolean };
export type SanToUci = { [key: string]: Uci };
export type SanToUci = { [key: AlmostSan]: Uci };

function fixCrazySan(san: string) {
return san[0] === 'P' ? san.slice(1) : san;
Expand Down Expand Up @@ -151,39 +151,40 @@ export function sanWriter(fen: string, ucis: string[]): SanToUci {
return sans;
}

export function sanToUci(san: string, legalSans: SanToUci): Uci | undefined {
if (san in legalSans) return legalSans[san];
const lowered = san.toLowerCase();
for (const i in legalSans) if (i.toLowerCase() === lowered) return legalSans[i];
return;
}

export const sanToWords = (san: string): string =>
san
.split('')
.map(c => {
if (c === 'x') return 'takes';
if (c === '+') return 'check';
if (c === '#') return 'checkmate';
if (c === '=') return 'promotes to';
if (c === '@') return 'at';
const code = c.charCodeAt(0);
if (code > 48 && code < 58) return c; // 1-8
if (code > 96 && code < 105) return c.toUpperCase(); // a-h
return charToRole(c) ?? c;
})
.join(' ')
.replace('O - O - O', 'long castle')
.replace('O - O', 'short castle');

export function speakable(san?: San): string {
const text = !san
? 'Game start'
: san.includes('O-O-O#')
? 'long castle checkmate'
: san.includes('O-O-O+')
? 'long castle check'
: san.includes('O-O-O')
? 'long castle'
: san.includes('O-O#')
? 'short castle checkmate'
: san.includes('O-O+')
? 'short castle check'
: san.includes('O-O')
? 'short castle'
: san
.split('')
.map(c => {
if (c === 'x') return 'takes';
if (c === '+') return 'check';
if (c === '#') return 'checkmate';
if (c === '=') return 'promotes to';
if (c === '@') return 'at';
const code = c.charCodeAt(0);
if (code > 48 && code < 58) return c; // 1-8
if (code > 96 && code < 105) return c.toUpperCase();
return charToRole(c) ?? c;
})
.join(' ')
.replace(/^A /, '"A"') // "A takes" & "A 3" are mispronounced
.replace(/(\d) E (\d)/, '$1,E $2') // Strings such as 1E5 are treated as scientific notation
.replace(/C /, 'c ') // Capital C is pronounced as "degrees celsius" when it comes after a number (e.g. R8c3)
.replace(/F /, 'f ') // Capital F is pronounced as "degrees fahrenheit" when it comes after a number (e.g. R8f3)
.replace(/(\d) H (\d)/, '$1H$2'); // "H" is pronounced as "hour" when it comes after a number with a space (e.g. Rook 5 H 3)
: sanToWords(san)
.replace(/^A /, '"A"') // "A takes" & "A 3" are mispronounced
.replace(/(\d) E (\d)/, '$1,E $2') // Strings such as 1E5 are treated as scientific notation
.replace(/C /, 'c ') // Capital C is pronounced as "degrees celsius" when it comes after a number (e.g. R8c3)
.replace(/F /, 'f ') // Capital F is pronounced as "degrees fahrenheit" when it comes after a number (e.g. R8f3)
.replace(/(\d) H (\d)/, '$1H$2') // "H" is pronounced as "hour" when it comes after a number with a space (e.g. Rook 5 H 3)
.replace(/(\d) H (\d)/, '$1H$2');
return text;
}
9 changes: 1 addition & 8 deletions ui/keyboardMove/src/keyboardSubmit.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { files } from 'chessground/types';
import type { SanToUci } from 'chess';
import { sanToUci, type SanToUci } from 'chess';
import type { Opts } from './exports';

const keyRegex = /^[a-h][1-8]$/;
Expand Down Expand Up @@ -138,13 +138,6 @@ function iccfToUci(v: string) {
return chars.join('');
}

function sanToUci(san: string, legalSans: SanToUci): Uci | undefined {
if (san in legalSans) return legalSans[san];
const lowered = san.toLowerCase();
for (const i in legalSans) if (i.toLowerCase() === lowered) return legalSans[i];
return;
}

function sanCandidates(san: string, legalSans: SanToUci): San[] {
// replace '=' in promotion moves (#7326)
const lowered = san.replace('=', '').toLowerCase();
Expand Down
Loading
Loading