From a5f1b842cb28773ec9b5bce7c33f37887c77fb1f Mon Sep 17 00:00:00 2001 From: Raul Rivera <72164424+raulriverarojas@users.noreply.github.com> Date: Mon, 21 Aug 2023 11:46:47 -0400 Subject: [PATCH 1/5] onyl allow standard castling in analysis filters user inputed fen in ctrl.ts to take away castling rights if rooks or kings not on standard starting squares --- ui/analyse/src/ctrl.ts | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 19b4d75e70c4..2fe3db8b7b58 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -35,7 +35,7 @@ import { make as makeSocket, Socket } from './socket'; import { nextGlyphSymbol } from './nodeFinder'; import { opposite, parseUci, makeSquare, roleToChar } from 'chessops/util'; import { Outcome, isNormal } from 'chessops/types'; -import { parseFen } from 'chessops/fen'; +import { parseFen, makeFen, parseCastlingFen } from 'chessops/fen'; import { Position, PositionError } from 'chessops/chess'; import { Result } from '@badrap/result'; import { setupPosition } from 'chessops/variant'; @@ -462,12 +462,44 @@ export default class AnalyseCtrl { changeFen(fen: Fen): void { this.redirecting = true; + if(this.data.game.variant.key=='standard'||this.data.game.variant.key=='fromPosition'){ + fen=this.returnStandardCastlingFen(fen) + } window.location.href = '/analysis/' + this.data.game.variant.key + '/' + encodeURIComponent(fen).replace(/%20/g, '_').replace(/%2F/g, '/'); } + returnStandardCastlingFen(fen: Fen): Fen { + let new_fen=fen + const setup = parseFen(fen).unwrap(); + let castlingPart="-" + const iterable=setup.unmovedRooks[Symbol.iterator](); + const w_castling_squares=[] + const b_castling_squares=[] + const kings_in_starting={ + //check if white king on its starting square + 'w':setup.board.king.has(4)&&setup.board.white.has(4), + //check same thing for black king + 'b':setup.board.king.has(60)&&setup.board.black.has(60) + } + let result = iterable.next(); + //populate arrays to contain possible black and white castling squares + while (!result.done) { + if(setup.board.black.has(result.value)) b_castling_squares.push(result.value) + else if (setup.board.white.has(result.value)) w_castling_squares.push(result.value) + result = iterable.next(); + } + //generate new fen if necessary + if ((kings_in_starting['w']&&w_castling_squares)||(kings_in_starting['b']&&b_castling_squares)){ + castlingPart="K".repeat(w_castling_squares.includes(7)?1:0)+"Q".repeat(w_castling_squares.includes(0)?1:0)+"k".repeat(b_castling_squares.includes(63)?1:0)+"q".repeat(b_castling_squares.includes(56)?1:0) + + } + setup.unmovedRooks=parseCastlingFen(setup.board,castlingPart).unwrap() + new_fen=makeFen(setup) + return new_fen + } userNewPiece = (piece: cg.Piece, pos: Key): void => { if (crazyValid(this.chessground, this.node.drops, piece, pos)) { From a98e7c7b779de483010800c5a3874e0d64c4786a Mon Sep 17 00:00:00 2001 From: raulriverarojas <72164424+raulriverarojas@users.noreply.github.com> Date: Mon, 21 Aug 2023 19:10:28 -0400 Subject: [PATCH 2/5] analysis page filters all stndrd and FP positions --- ui/analyse/src/ctrl.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 2fe3db8b7b58..3bf6dd8fd113 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -128,6 +128,10 @@ export default class AnalyseCtrl { makeStudy?: typeof makeStudyCtrl, ) { this.data = opts.data; + if(opts.data.game.variant.key==='standard'||opts.data.game.variant.key==='fromPosition'){ + const new_fen=this.returnStandardCastlingFen(opts.data.game.fen); + opts.data.game.fen=new_fen + opts.data.treeParts[0].fen=new_fen} this.element = opts.element; this.trans = opts.trans; this.treeView = treeViewCtrl('column'); @@ -462,9 +466,6 @@ export default class AnalyseCtrl { changeFen(fen: Fen): void { this.redirecting = true; - if(this.data.game.variant.key=='standard'||this.data.game.variant.key=='fromPosition'){ - fen=this.returnStandardCastlingFen(fen) - } window.location.href = '/analysis/' + this.data.game.variant.key + From bc5f9bd216587c957280ed83ef16c4798f325bf2 Mon Sep 17 00:00:00 2001 From: raulriverarojas <72164424+raulriverarojas@users.noreply.github.com> Date: Tue, 22 Aug 2023 14:57:18 -0400 Subject: [PATCH 3/5] add 960 to board editor --- ui/editor/src/ctrl.ts | 27 ++++++++++++++++++++++++--- ui/editor/src/view.ts | 7 +++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/ui/editor/src/ctrl.ts b/ui/editor/src/ctrl.ts index 67fa7d56bd0c..ffd0962c296a 100644 --- a/ui/editor/src/ctrl.ts +++ b/ui/editor/src/ctrl.ts @@ -33,6 +33,7 @@ export default class EditorCtrl { epSquare: Square | undefined; remainingChecks: RemainingChecks | undefined; rules: Rules; + variant: string; halfmoves: number; fullmoves: number; @@ -60,6 +61,7 @@ export default class EditorCtrl { this.castlingToggles = { K: false, Q: false, k: false, q: false }; const params = new URLSearchParams(location.search); this.rules = this.cfg.embed ? 'chess' : lichessRules((params.get('variant') || 'standard') as VariantKey); + this.variant=this.cfg.embed ? 'Standard': this.getVariantFromParams((params.get('variant') || 'Standard')); this.initialFen = (cfg.fen || params.get('fen') || INITIAL_FEN).replace(/_/g, ' '); this.redraw = () => {}; @@ -78,7 +80,23 @@ export default class EditorCtrl { this.options.onChange?.(fen); this.redraw(); } + private getVariantFromParams(paramVariant:string){ + switch (paramVariant){ + case 'standard': + return 'Standard'; + case 'chess960': + return 'Chess 960'; + case 'threeCheck': + return 'Three-check'; + case 'kingOfTheHill': + return 'King of the Hill'; + case 'racingKings': + return 'Racing Kings'; + default: + return paramVariant.charAt(0).toUpperCase() + paramVariant.slice(1); + } + } private castlingToggleFen(): string { let fen = ''; for (const toggle of CASTLING_TOGGLES) { @@ -132,13 +150,13 @@ export default class EditorCtrl { } makeAnalysisUrl(legalFen: string, orientation: Color = 'white'): string { - const variant = this.rules === 'chess' ? '' : lichessVariant(this.rules) + '/'; + const variant = this.rules === 'chess' ? this.variant=='Chess 960'? 'chess960/': '' : lichessVariant(this.rules) + '/'; return `/analysis/${variant}${urlFen(legalFen)}?color=${orientation}`; } makeEditorUrl(fen: string, orientation: Color = 'white'): string { - if (fen === INITIAL_FEN && this.rules === 'chess' && orientation === 'white') return this.cfg.baseUrl; - const variant = this.rules === 'chess' ? '' : '?variant=' + lichessVariant(this.rules); + if (fen === INITIAL_FEN && this.rules === 'chess' && orientation === 'white' && this.variant=== 'Standard') return this.cfg.baseUrl; + const variant = this.rules === 'chess' ? this.variant=='Chess 960'? '?variant=chess960': '' : '?variant=' + lichessVariant(this.rules); const orientationParam = variant ? `&color=${orientation}` : `?color=${orientation}`; return `${this.cfg.baseUrl}/${urlFen(fen)}${variant}${orientationParam}`; } @@ -203,6 +221,9 @@ export default class EditorCtrl { else if (!this.remainingChecks) this.remainingChecks = RemainingChecks.default(); this.onChange(); } + setVariant(variant: string): void{ + this.variant=variant; + } setOrientation(o: Color): void { this.options.orientation = o; diff --git a/ui/editor/src/view.ts b/ui/editor/src/view.ts index 730b478d2252..bb7a7503050b 100644 --- a/ui/editor/src/view.ts +++ b/ui/editor/src/view.ts @@ -72,7 +72,7 @@ function variant2option(key: Rules, name: string, ctrl: EditorCtrl): VNode { { attrs: { value: key, - selected: key == ctrl.rules, + selected: key == ctrl.rules && name==ctrl.variant, }, }, `${ctrl.trans.noarg('variant')} | ${name}`, @@ -81,6 +81,7 @@ function variant2option(key: Rules, name: string, ctrl: EditorCtrl): VNode { const allVariants: Array<[Rules, string]> = [ ['chess', 'Standard'], + ['chess', 'Chess 960'], ['antichess', 'Antichess'], ['atomic', 'Atomic'], ['crazyhouse', 'Crazyhouse'], @@ -222,7 +223,9 @@ function controls(ctrl: EditorCtrl, state: EditorState): VNode { attrs: { id: 'variants' }, on: { change(e) { - ctrl.setRules((e.target as HTMLSelectElement).value as Rules); + const option=(e.target as HTMLSelectElement).item((e.target as HTMLSelectElement).selectedIndex); + if(option)ctrl.setVariant(option.text.slice(10)); + ctrl.setRules((e.target as HTMLSelectElement).value as Rules); }, }, }, From a34377d8a4a5041e3c0b910ff3ab1b03b71c0b11 Mon Sep 17 00:00:00 2001 From: raulriverarojas <72164424+raulriverarojas@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:17:55 -0400 Subject: [PATCH 4/5] formatting --- ui/analyse/src/ctrl.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 3bf6dd8fd113..73369cec37ab 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -130,8 +130,8 @@ export default class AnalyseCtrl { this.data = opts.data; if(opts.data.game.variant.key==='standard'||opts.data.game.variant.key==='fromPosition'){ const new_fen=this.returnStandardCastlingFen(opts.data.game.fen); - opts.data.game.fen=new_fen - opts.data.treeParts[0].fen=new_fen} + opts.data.game.fen=new_fen; + opts.data.treeParts[0].fen=new_fen;} this.element = opts.element; this.trans = opts.trans; this.treeView = treeViewCtrl('column'); @@ -473,33 +473,33 @@ export default class AnalyseCtrl { encodeURIComponent(fen).replace(/%20/g, '_').replace(/%2F/g, '/'); } returnStandardCastlingFen(fen: Fen): Fen { - let new_fen=fen + let new_fen=fen; const setup = parseFen(fen).unwrap(); - let castlingPart="-" + let castlingPart="-"; const iterable=setup.unmovedRooks[Symbol.iterator](); - const w_castling_squares=[] - const b_castling_squares=[] + const w_castling_squares=[]; + const b_castling_squares=[]; const kings_in_starting={ //check if white king on its starting square 'w':setup.board.king.has(4)&&setup.board.white.has(4), //check same thing for black king 'b':setup.board.king.has(60)&&setup.board.black.has(60) - } + }; let result = iterable.next(); //populate arrays to contain possible black and white castling squares while (!result.done) { - if(setup.board.black.has(result.value)) b_castling_squares.push(result.value) - else if (setup.board.white.has(result.value)) w_castling_squares.push(result.value) + if(setup.board.black.has(result.value)) b_castling_squares.push(result.value); + else if (setup.board.white.has(result.value)) w_castling_squares.push(result.value); result = iterable.next(); } //generate new fen if necessary if ((kings_in_starting['w']&&w_castling_squares)||(kings_in_starting['b']&&b_castling_squares)){ - castlingPart="K".repeat(w_castling_squares.includes(7)?1:0)+"Q".repeat(w_castling_squares.includes(0)?1:0)+"k".repeat(b_castling_squares.includes(63)?1:0)+"q".repeat(b_castling_squares.includes(56)?1:0) + castlingPart="K".repeat(w_castling_squares.includes(7)?1:0)+"Q".repeat(w_castling_squares.includes(0)?1:0)+"k".repeat(b_castling_squares.includes(63)?1:0)+"q".repeat(b_castling_squares.includes(56)?1:0); } - setup.unmovedRooks=parseCastlingFen(setup.board,castlingPart).unwrap() - new_fen=makeFen(setup) - return new_fen + setup.unmovedRooks=parseCastlingFen(setup.board,castlingPart).unwrap(); + new_fen=makeFen(setup); + return new_fen; } userNewPiece = (piece: cg.Piece, pos: Key): void => { From 1b5af30ec868cade7fcee296cc0453f137bc2e98 Mon Sep 17 00:00:00 2001 From: raulriverarojas <72164424+raulriverarojas@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:20:30 -0400 Subject: [PATCH 5/5] formatting 2 --- ui/analyse/src/ctrl.ts | 44 +++++++++++++++++++++++------------------- ui/editor/src/ctrl.ts | 35 ++++++++++++++++++++++++--------- ui/editor/src/view.ts | 10 ++++++---- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/ui/analyse/src/ctrl.ts b/ui/analyse/src/ctrl.ts index 73369cec37ab..938eb7d5c0dd 100644 --- a/ui/analyse/src/ctrl.ts +++ b/ui/analyse/src/ctrl.ts @@ -128,10 +128,11 @@ export default class AnalyseCtrl { makeStudy?: typeof makeStudyCtrl, ) { this.data = opts.data; - if(opts.data.game.variant.key==='standard'||opts.data.game.variant.key==='fromPosition'){ - const new_fen=this.returnStandardCastlingFen(opts.data.game.fen); - opts.data.game.fen=new_fen; - opts.data.treeParts[0].fen=new_fen;} + if (opts.data.game.variant.key === 'standard' || opts.data.game.variant.key === 'fromPosition') { + const new_fen = this.returnStandardCastlingFen(opts.data.game.fen); + opts.data.game.fen = new_fen; + opts.data.treeParts[0].fen = new_fen; + } this.element = opts.element; this.trans = opts.trans; this.treeView = treeViewCtrl('column'); @@ -473,32 +474,35 @@ export default class AnalyseCtrl { encodeURIComponent(fen).replace(/%20/g, '_').replace(/%2F/g, '/'); } returnStandardCastlingFen(fen: Fen): Fen { - let new_fen=fen; + let new_fen = fen; const setup = parseFen(fen).unwrap(); - let castlingPart="-"; - const iterable=setup.unmovedRooks[Symbol.iterator](); - const w_castling_squares=[]; - const b_castling_squares=[]; - const kings_in_starting={ - //check if white king on its starting square - 'w':setup.board.king.has(4)&&setup.board.white.has(4), - //check same thing for black king - 'b':setup.board.king.has(60)&&setup.board.black.has(60) + let castlingPart = '-'; + const iterable = setup.unmovedRooks[Symbol.iterator](); + const w_castling_squares = []; + const b_castling_squares = []; + const kings_in_starting = { + //check if white king on its starting square + w: setup.board.king.has(4) && setup.board.white.has(4), + //check same thing for black king + b: setup.board.king.has(60) && setup.board.black.has(60), }; let result = iterable.next(); //populate arrays to contain possible black and white castling squares while (!result.done) { - if(setup.board.black.has(result.value)) b_castling_squares.push(result.value); + if (setup.board.black.has(result.value)) b_castling_squares.push(result.value); else if (setup.board.white.has(result.value)) w_castling_squares.push(result.value); result = iterable.next(); } //generate new fen if necessary - if ((kings_in_starting['w']&&w_castling_squares)||(kings_in_starting['b']&&b_castling_squares)){ - castlingPart="K".repeat(w_castling_squares.includes(7)?1:0)+"Q".repeat(w_castling_squares.includes(0)?1:0)+"k".repeat(b_castling_squares.includes(63)?1:0)+"q".repeat(b_castling_squares.includes(56)?1:0); - + if ((kings_in_starting['w'] && w_castling_squares) || (kings_in_starting['b'] && b_castling_squares)) { + castlingPart = + 'K'.repeat(w_castling_squares.includes(7) ? 1 : 0) + + 'Q'.repeat(w_castling_squares.includes(0) ? 1 : 0) + + 'k'.repeat(b_castling_squares.includes(63) ? 1 : 0) + + 'q'.repeat(b_castling_squares.includes(56) ? 1 : 0); } - setup.unmovedRooks=parseCastlingFen(setup.board,castlingPart).unwrap(); - new_fen=makeFen(setup); + setup.unmovedRooks = parseCastlingFen(setup.board, castlingPart).unwrap(); + new_fen = makeFen(setup); return new_fen; } diff --git a/ui/editor/src/ctrl.ts b/ui/editor/src/ctrl.ts index ffd0962c296a..a1a9a12d9709 100644 --- a/ui/editor/src/ctrl.ts +++ b/ui/editor/src/ctrl.ts @@ -61,7 +61,9 @@ export default class EditorCtrl { this.castlingToggles = { K: false, Q: false, k: false, q: false }; const params = new URLSearchParams(location.search); this.rules = this.cfg.embed ? 'chess' : lichessRules((params.get('variant') || 'standard') as VariantKey); - this.variant=this.cfg.embed ? 'Standard': this.getVariantFromParams((params.get('variant') || 'Standard')); + this.variant = this.cfg.embed + ? 'Standard' + : this.getVariantFromParams(params.get('variant') || 'Standard'); this.initialFen = (cfg.fen || params.get('fen') || INITIAL_FEN).replace(/_/g, ' '); this.redraw = () => {}; @@ -80,8 +82,8 @@ export default class EditorCtrl { this.options.onChange?.(fen); this.redraw(); } - private getVariantFromParams(paramVariant:string){ - switch (paramVariant){ + private getVariantFromParams(paramVariant: string) { + switch (paramVariant) { case 'standard': return 'Standard'; case 'chess960': @@ -95,7 +97,6 @@ export default class EditorCtrl { default: return paramVariant.charAt(0).toUpperCase() + paramVariant.slice(1); } - } private castlingToggleFen(): string { let fen = ''; @@ -150,13 +151,29 @@ export default class EditorCtrl { } makeAnalysisUrl(legalFen: string, orientation: Color = 'white'): string { - const variant = this.rules === 'chess' ? this.variant=='Chess 960'? 'chess960/': '' : lichessVariant(this.rules) + '/'; + const variant = + this.rules === 'chess' + ? this.variant == 'Chess 960' + ? 'chess960/' + : '' + : lichessVariant(this.rules) + '/'; return `/analysis/${variant}${urlFen(legalFen)}?color=${orientation}`; } makeEditorUrl(fen: string, orientation: Color = 'white'): string { - if (fen === INITIAL_FEN && this.rules === 'chess' && orientation === 'white' && this.variant=== 'Standard') return this.cfg.baseUrl; - const variant = this.rules === 'chess' ? this.variant=='Chess 960'? '?variant=chess960': '' : '?variant=' + lichessVariant(this.rules); + if ( + fen === INITIAL_FEN && + this.rules === 'chess' && + orientation === 'white' && + this.variant === 'Standard' + ) + return this.cfg.baseUrl; + const variant = + this.rules === 'chess' + ? this.variant == 'Chess 960' + ? '?variant=chess960' + : '' + : '?variant=' + lichessVariant(this.rules); const orientationParam = variant ? `&color=${orientation}` : `?color=${orientation}`; return `${this.cfg.baseUrl}/${urlFen(fen)}${variant}${orientationParam}`; } @@ -221,8 +238,8 @@ export default class EditorCtrl { else if (!this.remainingChecks) this.remainingChecks = RemainingChecks.default(); this.onChange(); } - setVariant(variant: string): void{ - this.variant=variant; + setVariant(variant: string): void { + this.variant = variant; } setOrientation(o: Color): void { diff --git a/ui/editor/src/view.ts b/ui/editor/src/view.ts index bb7a7503050b..ef544618afae 100644 --- a/ui/editor/src/view.ts +++ b/ui/editor/src/view.ts @@ -72,7 +72,7 @@ function variant2option(key: Rules, name: string, ctrl: EditorCtrl): VNode { { attrs: { value: key, - selected: key == ctrl.rules && name==ctrl.variant, + selected: key == ctrl.rules && name == ctrl.variant, }, }, `${ctrl.trans.noarg('variant')} | ${name}`, @@ -223,9 +223,11 @@ function controls(ctrl: EditorCtrl, state: EditorState): VNode { attrs: { id: 'variants' }, on: { change(e) { - const option=(e.target as HTMLSelectElement).item((e.target as HTMLSelectElement).selectedIndex); - if(option)ctrl.setVariant(option.text.slice(10)); - ctrl.setRules((e.target as HTMLSelectElement).value as Rules); + const option = (e.target as HTMLSelectElement).item( + (e.target as HTMLSelectElement).selectedIndex, + ); + if (option) ctrl.setVariant(option.text.slice(10)); + ctrl.setRules((e.target as HTMLSelectElement).value as Rules); }, }, },