Skip to content

Commit

Permalink
crazyhouse nvui wip
Browse files Browse the repository at this point in the history
  • Loading branch information
allanjoseph98 committed Feb 1, 2025
1 parent 9220d83 commit b7c62a4
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 18 deletions.
20 changes: 15 additions & 5 deletions ui/analyse/src/plugins/analyse.nvui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
castlingFlavours,
inputToLegalUci,
lastCapturedCommandHandler,
type DropMove,
} from 'nvui/chess';
import { renderSetting } from 'nvui/setting';
import { Notify } from 'nvui/notify';
Expand Down Expand Up @@ -317,10 +318,8 @@ function onSubmit(
if (isShortCommand(input)) input = '/' + input;
if (input[0] === '/') onCommand(ctrl, notify, input.slice(1), style());
else {
const uci = inputToLegalUci(input, ctrl.node.fen, ctrl.chessground);
if (uci)
ctrl.sendMove(uci.slice(0, 2) as Key, uci.slice(2, 4) as Key, undefined, charToRole(uci.slice(4)));
else notify('Invalid command');
const uciOrDrop = inputToLegalUci(input, ctrl.node.fen, ctrl.chessground);
uciOrDrop ? sendMove(uciOrDrop, ctrl) : notify('Invalid command');
}
$input.val('');
};
Expand All @@ -329,6 +328,17 @@ function onSubmit(
const isShortCommand = (input: string) =>
['p', 's', 'next', 'prev', 'eval', 'best'].includes(input.split(' ')[0].toLowerCase());

function sendMove(uciOrDrop: string | DropMove, ctrl: AnalyseController) {
if (typeof uciOrDrop === 'string')
ctrl.sendMove(
uciOrDrop.slice(0, 2) as Key,
uciOrDrop.slice(2, 4) as Key,
undefined,
charToRole(uciOrDrop.slice(4)),
);
else if (ctrl.crazyValid(uciOrDrop.role, uciOrDrop.key)) ctrl.sendNewPiece(uciOrDrop.role, uciOrDrop.key);
}

function onCommand(ctrl: AnalyseController, notify: (txt: string) => void, c: string, style: MoveStyle) {
const lowered = c.toLowerCase();
if (lowered === 'next') doAndRedraw(ctrl, next);
Expand All @@ -354,7 +364,7 @@ function renderAcpl(ctrl: AnalyseController, style: MoveStyle): MaybeVNodes | un
const analysisNodes = ctrl.mainline.filter(n => n.glyphs?.find(g => analysisGlyphs.includes(g.symbol)));
const res: Array<VNode> = [];
['white', 'black'].forEach((color: Color) => {
res.push(h('h3', `${color} player: ${anal[color].acpl} ACPL`));
res.push(h('h3', `${color} player: ${anal[color].acpl} ${i18n.site.averageCentipawnLoss}`));
res.push(
h(
'select',
Expand Down
20 changes: 15 additions & 5 deletions ui/nvui/src/chess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ const anna: { [file in Files]: string } = {
h: 'hector',
};

export const supportedVariant = (key: VariantKey): boolean => key !== 'crazyhouse';

export function boardSetting(): Setting<BoardStyle> {
return makeSetting<BoardStyle>({
choices: [
Expand Down Expand Up @@ -169,6 +167,15 @@ export const renderPieces = (pieces: Pieces, style: MoveStyle): VNode =>
),
);

type CrazyPocket = { [role in Role]?: number };
export const renderPockets = (pockets: [CrazyPocket, CrazyPocket]): VNode[] =>
COLORS.map((color, i) => h('h2', `${color} pocket: ${pocketsStr(pockets[i])}`));

export const pocketsStr = (pocket: CrazyPocket): string =>
Object.entries(pocket)
.map(([role, count]) => `${role}: ${count}`)
.join(', ');

const keysWithPiece = (pieces: Pieces, role?: Role, color?: Color): Key[] =>
Array.from(pieces).reduce<Key[]>(
(keys, [key, p]) => (p.color === color && p.role === role ? keys.concat(key) : keys),
Expand Down Expand Up @@ -476,15 +483,19 @@ export function possibleMovesHandler(

const promotionRegex = /^([a-h]x?)?[a-h](1|8)=[kqnbr]$/;
const uciPromotionRegex = /^([a-h][1-8])([a-h](1|8))[kqnbr]$/;
const dropRegex = /^([qrnb])@([a-h][1-8])|p?@([a-h][2-7])$/;
export type DropMove = { role: Role; key: Key };

export function inputToLegalUci(input: string, fen: string, chessground: CgApi): string | undefined {
export function inputToLegalUci(input: string, fen: string, chessground: CgApi): Uci | DropMove | undefined {
const dests = chessground.state.movable.dests;
if (!dests) return;
const legalUcis = destsToUcis(dests),
legalSans = sanWriter(fen, legalUcis);
let uci = sanToUci(input, legalSans) || input,
promotion = '';

const drop = input.match(dropRegex);
if (drop) return { role: charToRole(input[0]) || 'pawn', key: input.split('@')[1] as Key };
if (input.match(promotionRegex)) {
uci = sanToUci(input.slice(0, -2), legalSans) || input;
promotion = input.slice(-1).toLowerCase();
Expand All @@ -494,8 +505,7 @@ export function inputToLegalUci(input: string, fen: string, chessground: CgApi):
} else if ('18'.includes(uci[3]) && chessground.state.pieces.get(uci.slice(0, 2) as Key)?.role === 'pawn')
promotion = 'q';

if (legalUcis.includes(uci.toLowerCase())) return uci + promotion;
else return;
return legalUcis.includes(uci.toLowerCase()) ? `${uci}${promotion}` : undefined;
}

export function renderMainline(nodes: Tree.Node[], currentPath: Tree.Path, style: MoveStyle): VNodeChildren {
Expand Down
2 changes: 1 addition & 1 deletion ui/puzzle/src/plugins/puzzle.nvui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ function onSubmit(
if (input[0] === '/') onCommand(ctrl, notify, input.slice(1), style());
else {
const uci = inputToLegalUci(input, ctrl.node.fen, ground);
if (uci) {
if (uci && typeof uci === 'string') {
ctrl.playUci(uci);
const fback = ctrl.lastFeedback;
if (fback === 'fail') notify(i18n.puzzle.notTheMove);
Expand Down
22 changes: 15 additions & 7 deletions ui/round/src/plugins/round.nvui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import {
positionJumpHandler,
pieceJumpingHandler,
castlingFlavours,
supportedVariant,
inputToLegalUci,
renderPockets,
type DropMove,
} from 'nvui/chess';
import { renderSetting } from 'nvui/setting';
import { Notify } from 'nvui/notify';
Expand Down Expand Up @@ -69,6 +70,7 @@ export function initModule(): NvuiPlugin {
nvui = ctrl.nvui!,
step = plyStep(d, ctrl.ply),
style = moveStyle.get(),
pockets = ctrl.data.crazyhouse?.pockets,
clocks = [anyClock(ctrl, 'bottom'), anyClock(ctrl, 'top')];
if (!ctrl.chessground) {
ctrl.setChessground(
Expand All @@ -79,7 +81,6 @@ export function initModule(): NvuiPlugin {
coordinates: false,
}),
);
if (variantNope) setTimeout(() => notify.set(variantNope), 3000);
}
return h('div.nvui', { hook: onInsert(_ => setTimeout(() => notify.set(gameText(ctrl)), 2000)) }, [
h('h1', gameText(ctrl)),
Expand All @@ -93,6 +94,7 @@ export function initModule(): NvuiPlugin {
h('p.moves', { attrs: { role: 'log', 'aria-live': 'off' } }, renderMoves(d.steps.slice(1), style)),
h('h2', 'Pieces'),
h('div.pieces', renderPieces(ctrl.chessground.state.pieces, style)),
pockets && h('div.pockets', renderPockets(pockets)),
h('h2', 'Game status'),
h('div.status', { attrs: { role: 'status', 'aria-live': 'assertive', 'aria-atomic': 'true' } }, [
ctrl.data.game.status.name === 'started' ? i18n.site.playingRightNow : renderResult(ctrl),
Expand Down Expand Up @@ -129,8 +131,6 @@ export function initModule(): NvuiPlugin {
type: 'text',
autocomplete: 'off',
autofocus: true,
disabled: !!variantNope,
title: variantNope,
},
}),
]),
Expand Down Expand Up @@ -250,15 +250,17 @@ function createSubmitHandler(
} else notify('Invalid move');
}

let input = submitStoredPremove ? nvui.premoveInput : castlingFlavours(($input.val() as string).trim());
let input = submitStoredPremove
? nvui.premoveInput
: castlingFlavours(($input.val() as string).trim().toLowerCase());
if (!input) return;

// commands may be submitted with or without a leading /
const command = isShortCommand(input) || isShortCommand(input.slice(1));
if (command) onCommand(ctrl, notify, command, style(), input);
else {
const uci = inputToLegalUci(input, plyStep(ctrl.data, ctrl.ply).fen, ctrl.chessground);
if (uci) ctrl.socket.send('move', { u: uci }, { ackable: true });
const uciOrDrop = inputToLegalUci(input, plyStep(ctrl.data, ctrl.ply).fen, ctrl.chessground);
if (uciOrDrop) sendMove(uciOrDrop, ctrl, !!nvui.premoveInput);
else if (ctrl.data.player.color !== ctrl.data.game.player) {
// if it is not the user's turn, store this input as a premove
nvui.premoveInput = input;
Expand Down Expand Up @@ -288,6 +290,12 @@ type ShortCommand = (typeof shortCommands)[number];
const isShortCommand = (input: string): ShortCommand | undefined =>
shortCommands.find(c => c === input.split(' ')[0].toLowerCase());

function sendMove(uciOrDrop: string | DropMove, ctrl: RoundController, premove: boolean): void {
if (typeof uciOrDrop === 'string') ctrl.socket.send('move', { u: uciOrDrop }, { ackable: true });
else if (ctrl.crazyValid(uciOrDrop.role, uciOrDrop.key))
ctrl.sendNewPiece(uciOrDrop.role, uciOrDrop.key, premove);
}

function onCommand(
ctrl: RoundController,
notify: (txt: string) => void,
Expand Down

0 comments on commit b7c62a4

Please sign in to comment.