From 0eee5ed657ee0c08dd4be227ca0443cd6f3d7626 Mon Sep 17 00:00:00 2001 From: chrislicodes Date: Tue, 23 May 2023 10:47:03 +0200 Subject: [PATCH] chore: refactor display move WIP --- README.md | 24 +- src/components/react/ChessStudy.tsx | 249 ++------ .../react/ChessgroundWrapper/index.tsx | 49 +- src/components/react/PgnViewer/index.tsx | 23 +- src/lib/ui-state/index.ts | 95 +++ storage/2m6QC6OcyGeusalNfUC7s.json | 233 +++++++ storage/Pgx29Fy-EHIrzWKkp8fai.json | 589 ++++++++++++++++++ storage/R26qhQYNfcEEe2gVA6PaC.json | 95 ++- 8 files changed, 1107 insertions(+), 250 deletions(-) create mode 100644 src/lib/ui-state/index.ts create mode 100644 storage/2m6QC6OcyGeusalNfUC7s.json create mode 100644 storage/Pgx29Fy-EHIrzWKkp8fai.json diff --git a/README.md b/README.md index f39cfe9..e8b5342 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,17 @@ With this plugin, you can either import PGNs or simply start a fresh new game. I ## Table of contents -- [Obsidian Chess Study](#obsidian-chess-study) - - [Table of contents](#table-of-contents) - - [Motivation](#motivation) - - [Installation](#installation) - - [Usage](#usage) - - [Features](#features) - - [1.0.0](#100) - - [1.0.1](#101) - - [Settings](#settings) - - [Roadmap](#roadmap) - - [Tools Used](#tools-used) - - [Alternatives](#alternatives) - - [License](#license) +- [Motivation](#motivation) +- [Installation](#installation) +- [Usage](#usage) +- [Features](#features) + - [1.0.0](#100) + - [1.0.1](#101) +- [Settings](#settings) +- [Roadmap](#roadmap) +- [Tools Used](#tools-used) +- [Alternatives](#alternatives) +- [License](#license) ## Motivation diff --git a/src/components/react/ChessStudy.tsx b/src/components/react/ChessStudy.tsx index 9a0093c..78cfb30 100644 --- a/src/components/react/ChessStudy.tsx +++ b/src/components/react/ChessStudy.tsx @@ -7,7 +7,6 @@ import { App, Notice } from 'obsidian'; import * as React from 'react'; import { useCallback, useMemo, useState } from 'react'; import { ChessStudyPluginSettings } from 'src/components/obsidian/SettingsTab'; -import { playOtherSide, toColor, toDests } from 'src/lib/chess-logic'; import { parseUserConfig } from 'src/lib/obsidian'; import { ChessStudyDataAdapter, @@ -15,6 +14,7 @@ import { ChessStudyMove, VariantMove, } from 'src/lib/storage'; +import { displayMoveInHistory, findMoveIndex } from 'src/lib/ui-state'; import { useImmerReducer } from 'use-immer'; import { ChessgroundProps, ChessgroundWrapper } from './ChessgroundWrapper'; import { CommentSection } from './CommentSection'; @@ -30,48 +30,19 @@ interface AppProps { dataAdapter: ChessStudyDataAdapter; } -interface GameState { +export interface GameState { currentMove: ChessStudyMove | VariantMove; isViewOnly: boolean; study: ChessStudyFileData; } -interface MovePosition { - variant: { parentMoveIndex: number; variantIndex: number } | null; - moveIndex: number; -} - -type GameActions = +export type GameActions = + | { type: 'ADD_MOVE_TO_HISTORY'; move: Move } | { type: 'DISPLAY_NEXT_MOVE_IN_HISTORY' } | { type: 'DISPLAY_PREVIOUS_MOVE_IN_HISTORY' } | { type: 'DISPLAY_SELECTED_MOVE_IN_HISTORY'; moveId: string } - | { type: 'SYNC_CURRENT_MOVE_ID'; moveId: string } | { type: 'SYNC_SHAPES'; shapes: DrawShape[] } - | { type: 'SYNC_COMMENT'; comment: JSONContent | null } - | { type: 'ADD_MOVE_TO_HISTORY'; move: Move }; - -const findMoveIndex = ( - moves: ChessStudyMove[], - moveId: string -): MovePosition => { - for (const [iMainLine, move] of moves.entries()) { - if (move.moveId === moveId) return { variant: null, moveIndex: iMainLine }; - - for (const [iVariant, variant] of move.variants.entries()) { - const moveIndex = variant.moves.findIndex( - (move) => move.moveId === moveId - ); - - if (moveIndex >= 0) - return { - variant: { parentMoveIndex: iMainLine, variantIndex: iVariant }, - moveIndex: moveIndex, - }; - } - } - - return { variant: null, moveIndex: -1 }; -}; + | { type: 'SYNC_COMMENT'; comment: JSONContent | null }; export const ChessStudy = ({ source, @@ -85,7 +56,11 @@ export const ChessStudy = ({ source ); - const chessLogic = useMemo(() => { + // Setup Chessground API + const [chessView, setChessView] = useState(null); + + // Setup Chess.js API + const initialChessLogic = useMemo(() => { const chess = new Chess(); chessStudyData.moves.forEach((move) => { @@ -98,166 +73,45 @@ export const ChessStudy = ({ return chess; }, [chessStudyData.moves]); - // Setup Chessboard and Chess.js APIs - const [chessView, setChessView] = useState(null); + const [chessLogic, setChessLogic] = useState(initialChessLogic); - //? Maybe remodel all of the moves as a tree const [gameState, dispatch] = useImmerReducer( (draft, action) => { switch (action.type) { case 'DISPLAY_NEXT_MOVE_IN_HISTORY': { - //TODO: chess.js - const currentMoveId = draft.currentMove.moveId; - const moves = draft.study.moves; + if (!chessView) return draft; - const { variant, moveIndex } = findMoveIndex(moves, currentMoveId); - - if (variant) { - const variantMoves = - moves[variant.parentMoveIndex].variants[variant.variantIndex] - .moves; - - if (moveIndex < variantMoves.length - 1) { - const move = variantMoves[moveIndex + 1]; - const tempChessLogic = new Chess(move.after); - - chessView?.set({ - fen: move.after, - check: tempChessLogic.isCheck(), - }); - - draft.currentMove = move; - } - } else { - if (moveIndex < moves.length - 1) { - const move = moves[moveIndex + 1]; - const tempChessLogic = new Chess(move.after); - - chessView?.set({ - fen: move.after, - check: tempChessLogic.isCheck(), - }); - - draft.currentMove = move; - } - } + displayMoveInHistory(draft, chessView, setChessLogic, { + offset: 1, + selectedMoveId: null, + }); return draft; } case 'DISPLAY_PREVIOUS_MOVE_IN_HISTORY': { - //TODO: chess.js - const currentMoveId = draft.currentMove.moveId; - const moves = draft.study.moves; + if (!chessView) return draft; - const { variant, moveIndex } = findMoveIndex(moves, currentMoveId); - - if (variant) { - const variantMoves = - moves[variant.parentMoveIndex].variants[variant.variantIndex] - .moves; - - if (moveIndex > 0) { - const move = variantMoves[moveIndex - 1]; - const tempChessLogic = new Chess(move.after); - - chessView?.set({ - fen: move.after, - check: tempChessLogic.isCheck(), - }); - - draft.currentMove = move; - } - } else { - if (moveIndex > 0) { - const move = moves[moveIndex - 1]; - const tempChessLogic = new Chess(move.after); - - chessView?.set({ - fen: move.after, - check: tempChessLogic.isCheck(), - }); - - draft.currentMove = move; - } - } + displayMoveInHistory(draft, chessView, setChessLogic, { + offset: -1, + selectedMoveId: null, + }); return draft; } case 'DISPLAY_SELECTED_MOVE_IN_HISTORY': { - const currentMoveId = draft.currentMove.moveId; - const moves = draft.study.moves; + if (!chessView) return draft; - const moveId = action.moveId; + const selectedMoveId = action.moveId; - const { variant, moveIndex } = findMoveIndex(moves, moveId); - - if (currentMoveId === moveId) return draft; - - if (variant) { - const parent = moves[variant.parentMoveIndex]; - const variantMoves = parent.variants[variant.variantIndex].moves; - - const move = variantMoves[moveIndex]; - - const chess = new Chess(move.after); - - //TODO: Make viewOnly if its not the last move in the variant - chessView?.set({ - fen: move.after, - check: chess.isCheck(), - movable: { - free: false, - color: toColor(chess), - dests: toDests(chess), - events: { - //Hook up the Chessground UI changes to our App State - after: (orig, dest, _metadata) => { - const handler = playOtherSide(chessView, chess); - - dispatch({ - type: 'ADD_MOVE_TO_HISTORY', - move: handler(orig, dest), - }); - }, - }, - }, - turnColor: toColor(chess), - }); - - draft.currentMove = move; - } else { - const move = moves[moveIndex]; - - const chess = new Chess(move.after); - - chessView?.set({ - fen: move.after, - check: chess.isCheck(), - movable: { - free: false, - color: toColor(chess), - dests: toDests(chess), - events: { - //Hook up the Chessground UI changes to our App State - after: (orig, dest, _metadata) => { - const handler = playOtherSide(chessView, chess); - - dispatch({ - type: 'ADD_MOVE_TO_HISTORY', - move: handler(orig, dest), - }); - }, - }, - }, - turnColor: toColor(chess), - }); - draft.currentMove = move; - } + displayMoveInHistory(draft, chessView, setChessLogic, { + offset: 0, + selectedMoveId: selectedMoveId, + }); return draft; } case 'SYNC_SHAPES': { - const currentMoveId = draft.currentMove.moveId; + const currentMoveId = draft.currentMove?.moveId; const moves = draft.study.moves; const { variant, moveIndex } = findMoveIndex(moves, currentMoveId); @@ -279,7 +133,7 @@ export const ChessStudy = ({ return draft; } case 'SYNC_COMMENT': { - const currentMoveId = draft.currentMove.moveId; + const currentMoveId = draft.currentMove?.moveId; const moves = draft.study.moves; const { variant, moveIndex } = findMoveIndex(moves, currentMoveId); @@ -299,13 +153,12 @@ export const ChessStudy = ({ } return draft; - return draft; } case 'ADD_MOVE_TO_HISTORY': { const newMove = action.move; const moves = draft.study.moves; - const currentMoveId = draft.currentMove.moveId; + const currentMoveId = draft.currentMove?.moveId; const currentMoveIndex = moves.findIndex( (move) => move.moveId === currentMoveId @@ -358,28 +211,38 @@ export const ChessStudy = ({ } else { const currentMove = moves[moveIndex]; + //check if the next move is the same move + const nextMove = moves[moveIndex + 1]; + + if (nextMove.san === newMove.san) { + draft.currentMove = nextMove; + return draft; + } + //check if a variant with this first move already exists const sameVariant = currentMove.variants.findIndex( (variant) => variant.moves[0]?.san === newMove.san ); + if (sameVariant >= 0) { draft.currentMove = currentMove.variants[sameVariant].moves[0]; - } else { - const move = { - ...newMove, - moveId: moveId, - shapes: [], - comment: null, - }; - - currentMove.variants.push({ - parentMoveId: currentMove.moveId, - variantId: nanoid(), - moves: [move], - }); - - draft.currentMove = move; + return draft; } + + const move = { + ...newMove, + moveId: moveId, + shapes: [], + comment: null, + }; + + currentMove.variants.push({ + parentMoveId: currentMove.moveId, + variantId: nanoid(), + moves: [move], + }); + + draft.currentMove = move; } } @@ -449,7 +312,7 @@ export const ChessStudy = ({
dispatch({ type: 'SYNC_COMMENT', comment: comment }) } diff --git a/src/components/react/ChessgroundWrapper/index.tsx b/src/components/react/ChessgroundWrapper/index.tsx index c37dcc8..73a4864 100644 --- a/src/components/react/ChessgroundWrapper/index.tsx +++ b/src/components/react/ChessgroundWrapper/index.tsx @@ -1,11 +1,10 @@ -import { Chessground as ChessgroundApi } from 'chessground'; -import * as React from 'react'; -import { useEffect, useRef } from 'react'; - import { Chess, Move } from 'chess.js'; +import { Chessground as ChessgroundApi } from 'chessground'; import { Api } from 'chessground/api'; import { Config } from 'chessground/config'; import { DrawShape } from 'chessground/draw'; +import * as React from 'react'; +import { useEffect, useRef } from 'react'; import { playOtherSide, toColor, toDests } from 'src/lib/chess-logic'; export interface ChessgroundProps { @@ -45,18 +44,15 @@ export const ChessgroundWrapper = React.memo( free: false, color: toColor(chess), dests: toDests(chess), - events: { - //Hook up the Chessground UI changes to our App State - after: (orig, dest, _metadata) => { - const handler = playOtherSide(chessgroundApi, chess); - - addMoveToHistory(handler(orig, dest)); - }, - }, }, highlight: { check: true, }, + drawable: { + onChange: (shapes) => { + setShapes(shapes); + }, + }, turnColor: toColor(chess), ...config, }); @@ -65,24 +61,29 @@ export const ChessgroundWrapper = React.memo( } else if (ref.current && api) { api.set(config); } - }, [addMoveToHistory, api, chess, config, setApi]); + }, [addMoveToHistory, api, chess, config, setApi, setShapes]); + + //Sync Chess Logic + useEffect(() => { + api?.set({ + movable: { + events: { + //Hook up the Chessground UI changes to our App State + after: (orig, dest, _metadata) => { + const handler = playOtherSide(api, chess); + + addMoveToHistory(handler(orig, dest)); + }, + }, + }, + }); + }, [addMoveToHistory, api, chess]); //Sync View Only useEffect(() => { api?.set({ viewOnly: isViewOnly }); }, [isViewOnly, api]); - //Sync Shapes To State - useEffect(() => { - api?.set({ - drawable: { - onChange: (shapes) => { - setShapes(shapes); - }, - }, - }); - }, [api, setShapes]); - // Load Shapes useEffect(() => { if (shapes) { diff --git a/src/components/react/PgnViewer/index.tsx b/src/components/react/PgnViewer/index.tsx index 51560e7..604e59c 100644 --- a/src/components/react/PgnViewer/index.tsx +++ b/src/components/react/PgnViewer/index.tsx @@ -78,6 +78,7 @@ export const PgnViewer = React.memo(
{movePairs.map((pair, i) => { const [wMove, bMove] = pair; + const variants = wMove.variants.concat(bMove?.variants || []); return (

{i + 1}

@@ -95,16 +96,15 @@ export const PgnViewer = React.memo( )} {/* Add Variants */} -
- {wMove.variants - .concat(bMove?.variants || []) - .map((variant, i) => { + {!!variants.length && ( +
+ {variants.map((variant, i) => { return (
{variant.moves.map((move) => ( @@ -125,7 +125,8 @@ export const PgnViewer = React.memo(
); })} -
+
+ )}
); })} diff --git a/src/lib/ui-state/index.ts b/src/lib/ui-state/index.ts new file mode 100644 index 0000000..3ff215e --- /dev/null +++ b/src/lib/ui-state/index.ts @@ -0,0 +1,95 @@ +import { Chess } from 'chess.js'; +import { Api as ChessgroundApi } from 'chessground/api'; +import { Draft } from 'immer'; +import { GameState } from 'src/components/react/ChessStudy'; +import { toColor, toDests } from '../chess-logic'; +import { ChessStudyMove, VariantMove } from '../storage'; + +interface MovePosition { + variant: { parentMoveIndex: number; variantIndex: number } | null; + moveIndex: number; +} + +export const findMoveIndex = ( + moves: ChessStudyMove[], + moveId: string +): MovePosition => { + for (const [iMainLine, move] of moves.entries()) { + if (move.moveId === moveId) return { variant: null, moveIndex: iMainLine }; + + for (const [iVariant, variant] of move.variants.entries()) { + const moveIndex = variant.moves.findIndex( + (move) => move.moveId === moveId + ); + + if (moveIndex >= 0) + return { + variant: { parentMoveIndex: iMainLine, variantIndex: iVariant }, + moveIndex: moveIndex, + }; + } + } + + return { variant: null, moveIndex: -1 }; +}; + +export const displayMoveInHistory = ( + draft: Draft, + chessView: ChessgroundApi, + setChessLogic: React.Dispatch>, + options: { offset: number; selectedMoveId: string | null } = { + offset: 0, + selectedMoveId: null, + } +): Draft => { + let moveToDisplay: ChessStudyMove | VariantMove | null = null; + + const { offset, selectedMoveId } = options; + + //Figure out where we are + const currentMove = draft.currentMove; + const currentMoveId = currentMove.moveId; + + const moves = draft.study.moves; + + //If we pass a moveId, find out where that is and offset from there, otherwise take current moveId + const baseMoveId = selectedMoveId || currentMoveId; + + const { variant, moveIndex } = findMoveIndex(moves, baseMoveId); + //Are we in a variant? Are we not? Decide which move to display + + if (variant) { + const variantMoves = + moves[variant.parentMoveIndex].variants[variant.variantIndex].moves; + + if (typeof variantMoves[moveIndex + offset] !== 'undefined') { + moveToDisplay = variantMoves[moveIndex + offset]; + } + } else { + if (typeof moves[moveIndex + offset] !== 'undefined') { + moveToDisplay = moves[moveIndex + offset]; + } + } + + if (!moveToDisplay) return draft; + + const chess = new Chess(moveToDisplay.after); + + //TODO: Handle is view only if not the last move in variant - put this into a function also for inital setuo + chessView.set({ + fen: moveToDisplay.after, + check: chess.isCheck(), + movable: { + free: false, + color: toColor(chess), + dests: toDests(chess), + }, + turnColor: toColor(chess), + }); + + draft.currentMove = moveToDisplay; + + setChessLogic(chess); + + return draft; +}; diff --git a/storage/2m6QC6OcyGeusalNfUC7s.json b/storage/2m6QC6OcyGeusalNfUC7s.json new file mode 100644 index 0000000..1977224 --- /dev/null +++ b/storage/2m6QC6OcyGeusalNfUC7s.json @@ -0,0 +1,233 @@ +{ + "header": { + "title": null + }, + "moves": [ + { + "color": "w", + "piece": "p", + "from": "d2", + "to": "d4", + "san": "d4", + "flags": "b", + "lan": "d2d4", + "before": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", + "after": "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1", + "moveId": "yAxdJXytOJhKCC9oCnc5J", + "variants": [], + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "p", + "from": "d7", + "to": "d5", + "san": "d5", + "flags": "b", + "lan": "d7d5", + "before": "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1", + "after": "rnbqkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2", + "moveId": "mfyQ0tk9mzDtv50N6wsqi", + "variants": [ + { + "parentMoveId": "mfyQ0tk9mzDtv50N6wsqi", + "variantId": "zawmwoiab39yMQU4sYsTP", + "moves": [ + { + "color": "w", + "piece": "b", + "from": "c1", + "to": "f4", + "san": "Bf4", + "flags": "n", + "lan": "c1f4", + "before": "rnbqkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2", + "after": "rnbqkbnr/ppp1pppp/8/3p4/3P1B2/8/PPP1PPPP/RN1QKBNR b KQkq - 1 2", + "moveId": "0FMCs4k6WYUvvOAXNOnHZ", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "n", + "from": "b8", + "to": "c6", + "san": "Nc6", + "flags": "n", + "lan": "b8c6", + "before": "rnbqkbnr/ppp1pppp/8/3p4/3P1B2/8/PPP1PPPP/RN1QKBNR b KQkq - 1 2", + "after": "r1bqkbnr/ppp1pppp/2n5/3p4/3P1B2/8/PPP1PPPP/RN1QKBNR w KQkq - 2 3", + "moveId": "cxdXqGBcpPbGwe7mxS8QJ", + "shapes": [ + { + "orig": "f4", + "dest": "e4", + "brush": "green" + }, + { + "orig": "e6", + "dest": "d8", + "brush": "green" + }, + { + "orig": "b5", + "dest": "d3", + "brush": "green" + }, + { + "orig": "f6", + "dest": "e5", + "brush": "green" + }, + { + "orig": "e3", + "dest": "e1", + "brush": "green" + }, + { + "orig": "e1", + "dest": "e5", + "brush": "green" + } + ], + "comment": null + }, + { + "color": "w", + "piece": "p", + "from": "e2", + "to": "e3", + "san": "e3", + "flags": "n", + "lan": "e2e3", + "before": "r1bqkbnr/ppp1pppp/2n5/3p4/3P1B2/8/PPP1PPPP/RN1QKBNR w KQkq - 2 3", + "after": "r1bqkbnr/ppp1pppp/2n5/3p4/3P1B2/4P3/PPP2PPP/RN1QKBNR b KQkq - 0 3", + "moveId": "aban_oJr55di5vn_wg-yK", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "n", + "from": "g8", + "to": "f6", + "san": "Nf6", + "flags": "n", + "lan": "g8f6", + "before": "r1bqkbnr/ppp1pppp/2n5/3p4/3P1B2/4P3/PPP2PPP/RN1QKBNR b KQkq - 0 3", + "after": "r1bqkb1r/ppp1pppp/2n2n2/3p4/3P1B2/4P3/PPP2PPP/RN1QKBNR w KQkq - 1 4", + "moveId": "3LqZHTTDtdu3V0pUDWY-a", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "p", + "from": "c2", + "to": "c3", + "san": "c3", + "flags": "n", + "lan": "c2c3", + "before": "r1bqkb1r/ppp1pppp/2n2n2/3p4/3P1B2/4P3/PPP2PPP/RN1QKBNR w KQkq - 1 4", + "after": "r1bqkb1r/ppp1pppp/2n2n2/3p4/3P1B2/2P1P3/PP3PPP/RN1QKBNR b KQkq - 0 4", + "moveId": "tNHpFahwg86SzVf7IZKBe", + "shapes": [], + "comment": null + } + ] + }, + { + "parentMoveId": "mfyQ0tk9mzDtv50N6wsqi", + "variantId": "F0HuRmNmRe_9VSV_anJ1B", + "moves": [ + { + "color": "w", + "piece": "n", + "from": "g1", + "to": "f3", + "san": "Nf3", + "flags": "n", + "lan": "g1f3", + "before": "rnbqkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2", + "after": "rnbqkbnr/ppp1pppp/8/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R b KQkq - 1 2", + "moveId": "IeC5BY-zuob3EmMCinr85", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "p", + "from": "c7", + "to": "c5", + "san": "c5", + "flags": "b", + "lan": "c7c5", + "before": "rnbqkbnr/ppp1pppp/8/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R b KQkq - 1 2", + "after": "rnbqkbnr/pp2pppp/8/2pp4/3P4/5N2/PPP1PPPP/RNBQKB1R w KQkq - 0 3", + "moveId": "uxnd32VynpYL7Rmmbv_DW", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "p", + "from": "e2", + "to": "e3", + "san": "e3", + "flags": "n", + "lan": "e2e3", + "before": "rnbqkbnr/pp2pppp/8/2pp4/3P4/5N2/PPP1PPPP/RNBQKB1R w KQkq - 0 3", + "after": "rnbqkbnr/pp2pppp/8/2pp4/3P4/4PN2/PPP2PPP/RNBQKB1R b KQkq - 0 3", + "moveId": "mUBsfyRfvdZh9rDXtZemJ", + "shapes": [ + { + "orig": "c1", + "dest": "e3", + "brush": "green" + }, + { + "orig": "e3", + "brush": "green" + } + ], + "comment": null + } + ] + } + ], + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "n", + "from": "g1", + "to": "f3", + "san": "Nf3", + "flags": "n", + "lan": "g1f3", + "before": "rnbqkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2", + "after": "rnbqkbnr/ppp1pppp/8/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R b KQkq - 1 2", + "moveId": "VanSTXnPwijGWGmQY8CSI", + "variants": [], + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "n", + "from": "b8", + "to": "c6", + "san": "Nc6", + "flags": "n", + "lan": "b8c6", + "before": "rnbqkbnr/ppp1pppp/8/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R b KQkq - 1 2", + "after": "r1bqkbnr/ppp1pppp/2n5/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R w KQkq - 2 3", + "moveId": "7g_GlS7valHBNT5e7-kmM", + "variants": [], + "shapes": [], + "comment": null + } + ] +} diff --git a/storage/Pgx29Fy-EHIrzWKkp8fai.json b/storage/Pgx29Fy-EHIrzWKkp8fai.json new file mode 100644 index 0000000..0854294 --- /dev/null +++ b/storage/Pgx29Fy-EHIrzWKkp8fai.json @@ -0,0 +1,589 @@ +{ + "header": { + "title": null + }, + "moves": [ + { + "color": "w", + "piece": "p", + "from": "d2", + "to": "d4", + "san": "d4", + "flags": "b", + "lan": "d2d4", + "before": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", + "after": "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1", + "moveId": "K7IuFrVhWYx0tDWOgoed-", + "variants": [ + { + "parentMoveId": "K7IuFrVhWYx0tDWOgoed-", + "variantId": "iYWGTJLm5C4wGN1Mvo2UH", + "moves": [ + { + "color": "b", + "piece": "p", + "from": "e7", + "to": "e5", + "san": "e5", + "flags": "b", + "lan": "e7e5", + "before": "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1", + "after": "rnbqkbnr/pppp1ppp/8/4p3/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2", + "moveId": "ywV8sktmb4PuaTt4--_1x", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "p", + "from": "d4", + "to": "e5", + "san": "dxe5", + "flags": "c", + "lan": "d4e5", + "before": "rnbqkbnr/pppp1ppp/8/4p3/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2", + "after": "rnbqkbnr/pppp1ppp/8/4P3/8/8/PPP1PPPP/RNBQKBNR b KQkq - 0 2", + "captured": "p", + "moveId": "C7UqHuHOpCrLdbQSJs_bN", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "q", + "from": "d8", + "to": "e7", + "san": "Qe7", + "flags": "n", + "lan": "d8e7", + "before": "rnbqkbnr/pppp1ppp/8/4P3/8/8/PPP1PPPP/RNBQKBNR b KQkq - 0 2", + "after": "rnb1kbnr/ppppqppp/8/4P3/8/8/PPP1PPPP/RNBQKBNR w KQkq - 1 3", + "moveId": "KjRLrJAOKeThrdtQzUHXn", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "n", + "from": "g1", + "to": "f3", + "san": "Nf3", + "flags": "n", + "lan": "g1f3", + "before": "rnb1kbnr/ppppqppp/8/4P3/8/8/PPP1PPPP/RNBQKBNR w KQkq - 1 3", + "after": "rnb1kbnr/ppppqppp/8/4P3/8/5N2/PPP1PPPP/RNBQKB1R b KQkq - 2 3", + "moveId": "n39FgkmGmQh50lr75W_n3", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "q", + "from": "e7", + "to": "b4", + "san": "Qb4+", + "flags": "n", + "lan": "e7b4", + "before": "rnb1kbnr/ppppqppp/8/4P3/8/5N2/PPP1PPPP/RNBQKB1R b KQkq - 2 3", + "after": "rnb1kbnr/pppp1ppp/8/4P3/1q6/5N2/PPP1PPPP/RNBQKB1R w KQkq - 3 4", + "moveId": "q64HbI42DIRfeenIMKW0g", + "shapes": [ + { + "orig": "f8", + "dest": "b4", + "brush": "green" + }, + { + "orig": "b4", + "brush": "green" + }, + { + "orig": "b4", + "dest": "d2", + "brush": "green" + }, + { + "orig": "d2", + "brush": "green" + } + ], + "comment": null + }, + { + "color": "w", + "piece": "b", + "from": "c1", + "to": "d2", + "san": "Bd2", + "flags": "n", + "lan": "c1d2", + "before": "rnb1kbnr/pppp1ppp/8/4P3/1q6/5N2/PPP1PPPP/RNBQKB1R w KQkq - 3 4", + "after": "rnb1kbnr/pppp1ppp/8/4P3/1q6/5N2/PPPBPPPP/RN1QKB1R b KQkq - 4 4", + "moveId": "vbDAsX4SycrSNpGBxJU83", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "q", + "from": "b4", + "to": "b2", + "san": "Qxb2", + "flags": "c", + "lan": "b4b2", + "before": "rnb1kbnr/pppp1ppp/8/4P3/1q6/5N2/PPPBPPPP/RN1QKB1R b KQkq - 4 4", + "after": "rnb1kbnr/pppp1ppp/8/4P3/8/5N2/PqPBPPPP/RN1QKB1R w KQkq - 0 5", + "captured": "p", + "moveId": "ZjWKoHRclQZy-A-7iK5_y", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "b", + "from": "d2", + "to": "c3", + "san": "Bc3", + "flags": "n", + "lan": "d2c3", + "before": "rnb1kbnr/pppp1ppp/8/4P3/8/5N2/PqPBPPPP/RN1QKB1R w KQkq - 0 5", + "after": "rnb1kbnr/pppp1ppp/8/4P3/8/2B2N2/PqP1PPPP/RN1QKB1R b KQkq - 1 5", + "moveId": "r6Hps1FP7RuVqtsxk1qbh", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "b", + "from": "f8", + "to": "b4", + "san": "Bb4", + "flags": "n", + "lan": "f8b4", + "before": "rnb1kbnr/pppp1ppp/8/4P3/8/2B2N2/PqP1PPPP/RN1QKB1R b KQkq - 1 5", + "after": "rnb1k1nr/pppp1ppp/8/4P3/1b6/2B2N2/PqP1PPPP/RN1QKB1R w KQkq - 2 6", + "moveId": "QywnHUs1JvnVyqNwUFjIn", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "q", + "from": "d1", + "to": "d4", + "san": "Qd4", + "flags": "n", + "lan": "d1d4", + "before": "rnb1k1nr/pppp1ppp/8/4P3/1b6/2B2N2/PqP1PPPP/RN1QKB1R w KQkq - 2 6", + "after": "rnb1k1nr/pppp1ppp/8/4P3/1b1Q4/2B2N2/PqP1PPPP/RN2KB1R b KQkq - 3 6", + "moveId": "Qju81DkiAaQVECVdmOD7C", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "q", + "from": "b2", + "to": "c1", + "san": "Qc1+", + "flags": "n", + "lan": "b2c1", + "before": "rnb1k1nr/pppp1ppp/8/4P3/1b1Q4/2B2N2/PqP1PPPP/RN2KB1R b KQkq - 3 6", + "after": "rnb1k1nr/pppp1ppp/8/4P3/1b1Q4/2B2N2/P1P1PPPP/RNq1KB1R w KQkq - 4 7", + "moveId": "m4ojoMAcK45xkKp_hnnln", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "q", + "from": "d4", + "to": "d1", + "san": "Qd1", + "flags": "n", + "lan": "d4d1", + "before": "rnb1k1nr/pppp1ppp/8/4P3/1b1Q4/2B2N2/P1P1PPPP/RNq1KB1R w KQkq - 4 7", + "after": "rnb1k1nr/pppp1ppp/8/4P3/1b6/2B2N2/P1P1PPPP/RNqQKB1R b KQkq - 5 7", + "moveId": "qmdtI-fTQFJNuRST6SzGB", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "b", + "from": "b4", + "to": "c3", + "san": "Bxc3+", + "flags": "c", + "lan": "b4c3", + "before": "rnb1k1nr/pppp1ppp/8/4P3/1b6/2B2N2/P1P1PPPP/RNqQKB1R b KQkq - 5 7", + "after": "rnb1k1nr/pppp1ppp/8/4P3/8/2b2N2/P1P1PPPP/RNqQKB1R w KQkq - 0 8", + "captured": "b", + "moveId": "uZbFg5rGA_sNmp2ANJdfF", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "n", + "from": "f3", + "to": "d2", + "san": "Nfd2", + "flags": "n", + "lan": "f3d2", + "before": "rnb1k1nr/pppp1ppp/8/4P3/8/2b2N2/P1P1PPPP/RNqQKB1R w KQkq - 0 8", + "after": "rnb1k1nr/pppp1ppp/8/4P3/8/2b5/P1PNPPPP/RNqQKB1R b KQkq - 1 8", + "moveId": "UoR8Es1pB4YUa8zXnEwln", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "q", + "from": "c1", + "to": "b2", + "san": "Qb2", + "flags": "n", + "lan": "c1b2", + "before": "rnb1k1nr/pppp1ppp/8/4P3/8/2b5/P1PNPPPP/RNqQKB1R b KQkq - 1 8", + "after": "rnb1k1nr/pppp1ppp/8/4P3/8/2b5/PqPNPPPP/RN1QKB1R w KQkq - 2 9", + "moveId": "0afi6G4oToTJFL9-WRIgr", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "n", + "from": "b1", + "to": "c3", + "san": "Nxc3", + "flags": "c", + "lan": "b1c3", + "before": "rnb1k1nr/pppp1ppp/8/4P3/8/2b5/PqPNPPPP/RN1QKB1R w KQkq - 2 9", + "after": "rnb1k1nr/pppp1ppp/8/4P3/8/2N5/PqPNPPPP/R2QKB1R b KQkq - 0 9", + "captured": "b", + "moveId": "uURMx5l1nS2UuJhbf3E1z", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "q", + "from": "b2", + "to": "c3", + "san": "Qxc3", + "flags": "c", + "lan": "b2c3", + "before": "rnb1k1nr/pppp1ppp/8/4P3/8/2N5/PqPNPPPP/R2QKB1R b KQkq - 0 9", + "after": "rnb1k1nr/pppp1ppp/8/4P3/8/2q5/P1PNPPPP/R2QKB1R w KQkq - 0 10", + "captured": "n", + "moveId": "R8_lRLlgGr5c9ISlktSsf", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "q", + "from": "d1", + "to": "b1", + "san": "Qb1", + "flags": "n", + "lan": "d1b1", + "before": "rnb1k1nr/pppp1ppp/8/4P3/8/2q5/P1PNPPPP/R2QKB1R w KQkq - 0 10", + "after": "rnb1k1nr/pppp1ppp/8/4P3/8/2q5/P1PNPPPP/RQ2KB1R b KQkq - 1 10", + "moveId": "7Kdsg-dU5BR3ql_-dSZS2", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "n", + "from": "g8", + "to": "f6", + "san": "Nf6", + "flags": "n", + "lan": "g8f6", + "before": "rnb1k1nr/pppp1ppp/8/4P3/8/2q5/P1PNPPPP/RQ2KB1R b KQkq - 1 10", + "after": "rnb1k2r/pppp1ppp/5n2/4P3/8/2q5/P1PNPPPP/RQ2KB1R w KQkq - 2 11", + "moveId": "rDhVahgiTScPvLi8TVtpO", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "p", + "from": "e5", + "to": "f6", + "san": "exf6", + "flags": "c", + "lan": "e5f6", + "before": "rnb1k2r/pppp1ppp/5n2/4P3/8/2q5/P1PNPPPP/RQ2KB1R w KQkq - 2 11", + "after": "rnb1k2r/pppp1ppp/5P2/8/8/2q5/P1PNPPPP/RQ2KB1R b KQkq - 0 11", + "captured": "n", + "moveId": "1RPQpfvXkUFDCsZVCDb2J", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "k", + "from": "e8", + "to": "g8", + "san": "O-O", + "flags": "k", + "lan": "e8g8", + "before": "rnb1k2r/pppp1ppp/5P2/8/8/2q5/P1PNPPPP/RQ2KB1R b KQkq - 0 11", + "after": "rnb2rk1/pppp1ppp/5P2/8/8/2q5/P1PNPPPP/RQ2KB1R w KQ - 1 12", + "moveId": "1IAGBQM6P_G5Gm1xGso5F", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "p", + "from": "f6", + "to": "g7", + "san": "fxg7", + "flags": "c", + "lan": "f6g7", + "before": "rnb2rk1/pppp1ppp/5P2/8/8/2q5/P1PNPPPP/RQ2KB1R w KQ - 1 12", + "after": "rnb2rk1/pppp1pPp/8/8/8/2q5/P1PNPPPP/RQ2KB1R b KQ - 0 12", + "captured": "p", + "moveId": "gKLX3u-UUeiJCTxNP6h-0", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "q", + "from": "c3", + "to": "g7", + "san": "Qxg7", + "flags": "c", + "lan": "c3g7", + "before": "rnb2rk1/pppp1pPp/8/8/8/2q5/P1PNPPPP/RQ2KB1R b KQ - 0 12", + "after": "rnb2rk1/pppp1pqp/8/8/8/8/P1PNPPPP/RQ2KB1R w KQ - 0 13", + "captured": "p", + "moveId": "k0nLjnkIAIvIiV2r8aN0i", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "p", + "from": "e2", + "to": "e4", + "san": "e4", + "flags": "b", + "lan": "e2e4", + "before": "rnb2rk1/pppp1pqp/8/8/8/8/P1PNPPPP/RQ2KB1R w KQ - 0 13", + "after": "rnb2rk1/pppp1pqp/8/8/4P3/8/P1PN1PPP/RQ2KB1R b KQ - 0 13", + "moveId": "u2lNZ5yg8T0P9pYwo9_F7", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "p", + "from": "d7", + "to": "d5", + "san": "d5", + "flags": "b", + "lan": "d7d5", + "before": "rnb2rk1/pppp1pqp/8/8/4P3/8/P1PN1PPP/RQ2KB1R b KQ - 0 13", + "after": "rnb2rk1/ppp2pqp/8/3p4/4P3/8/P1PN1PPP/RQ2KB1R w KQ - 0 14", + "moveId": "22VZvkuhwF5ZEPMHm1VZ4", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "p", + "from": "e4", + "to": "d5", + "san": "exd5", + "flags": "c", + "lan": "e4d5", + "before": "rnb2rk1/ppp2pqp/8/3p4/4P3/8/P1PN1PPP/RQ2KB1R w KQ - 0 14", + "after": "rnb2rk1/ppp2pqp/8/3P4/8/8/P1PN1PPP/RQ2KB1R b KQ - 0 14", + "captured": "p", + "moveId": "LeIBTE8JPhv3hBiMuMX3b", + "shapes": [ + { + "orig": "c3", + "dest": "c8", + "brush": "green" + }, + { + "orig": "d7", + "brush": "green" + }, + { + "orig": "f5", + "dest": "e4", + "brush": "green" + }, + { + "orig": "e4", + "dest": "d4", + "brush": "green" + }, + { + "orig": "e4", + "brush": "green" + } + ], + "comment": null + }, + { + "color": "b", + "piece": "r", + "from": "f8", + "to": "e8", + "san": "Re8+", + "flags": "n", + "lan": "f8e8", + "before": "rnb2rk1/ppp2pqp/8/3P4/8/8/P1PN1PPP/RQ2KB1R b KQ - 0 14", + "after": "rnb1r1k1/ppp2pqp/8/3P4/8/8/P1PN1PPP/RQ2KB1R w KQ - 1 15", + "moveId": "NB92t5ZR0vlNnN9rVIyCV", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "n", + "from": "d2", + "to": "e4", + "san": "Ne4", + "flags": "n", + "lan": "d2e4", + "before": "rnb1r1k1/ppp2pqp/8/3P4/8/8/P1PN1PPP/RQ2KB1R w KQ - 1 15", + "after": "rnb1r1k1/ppp2pqp/8/3P4/4N3/8/P1P2PPP/RQ2KB1R b KQ - 2 15", + "moveId": "LxWOfH-f8a6wjZKPxoQCY", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "r", + "from": "e8", + "to": "e4", + "san": "Rxe4+", + "flags": "c", + "lan": "e8e4", + "before": "rnb1r1k1/ppp2pqp/8/3P4/4N3/8/P1P2PPP/RQ2KB1R b KQ - 2 15", + "after": "rnb3k1/ppp2pqp/8/3P4/4r3/8/P1P2PPP/RQ2KB1R w KQ - 0 16", + "captured": "n", + "moveId": "JaI-p1_NITz88XDPgeRdb", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "k", + "from": "e1", + "to": "d2", + "san": "Kd2", + "flags": "n", + "lan": "e1d2", + "before": "rnb3k1/ppp2pqp/8/3P4/4r3/8/P1P2PPP/RQ2KB1R w KQ - 0 16", + "after": "rnb3k1/ppp2pqp/8/3P4/4r3/8/P1PK1PPP/RQ3B1R b - - 1 16", + "moveId": "IRe9hR4tsqSSiUjRJRtdX", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "q", + "from": "g7", + "to": "d4", + "san": "Qd4+", + "flags": "n", + "lan": "g7d4", + "before": "rnb3k1/ppp2pqp/8/3P4/4r3/8/P1PK1PPP/RQ3B1R b - - 1 16", + "after": "rnb3k1/ppp2p1p/8/3P4/3qr3/8/P1PK1PPP/RQ3B1R w - - 2 17", + "moveId": "AI_nM6F28Pd6_fP5E4kg8", + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "k", + "from": "d2", + "to": "c1", + "san": "Kc1", + "flags": "n", + "lan": "d2c1", + "before": "rnb3k1/ppp2p1p/8/3P4/3qr3/8/P1PK1PPP/RQ3B1R w - - 2 17", + "after": "rnb3k1/ppp2p1p/8/3P4/3qr3/8/P1P2PPP/RQK2B1R b - - 3 17", + "moveId": "i8fhacks6siwZ59vneIBt", + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "r", + "from": "e4", + "to": "e1", + "san": "Re1#", + "flags": "n", + "lan": "e4e1", + "before": "rnb3k1/ppp2p1p/8/3P4/3qr3/8/P1P2PPP/RQK2B1R b - - 3 17", + "after": "rnb3k1/ppp2p1p/8/3P4/3q4/8/P1P2PPP/RQK1rB1R w - - 4 18", + "moveId": "9RCCfYS56nKp5LGlT0pm-", + "shapes": [], + "comment": null + } + ] + } + ], + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "p", + "from": "d7", + "to": "d5", + "san": "d5", + "flags": "b", + "lan": "d7d5", + "before": "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1", + "after": "rnbqkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2", + "moveId": "caq5T9snozEXHQJo96w6l", + "variants": [], + "shapes": [], + "comment": null + }, + { + "color": "w", + "piece": "n", + "from": "g1", + "to": "f3", + "san": "Nf3", + "flags": "n", + "lan": "g1f3", + "before": "rnbqkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBQKBNR w KQkq - 0 2", + "after": "rnbqkbnr/ppp1pppp/8/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R b KQkq - 1 2", + "moveId": "79E1Noq3U-uYA4t9ZDEj_", + "variants": [], + "shapes": [], + "comment": null + }, + { + "color": "b", + "piece": "n", + "from": "b8", + "to": "c6", + "san": "Nc6", + "flags": "n", + "lan": "b8c6", + "before": "rnbqkbnr/ppp1pppp/8/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R b KQkq - 1 2", + "after": "r1bqkbnr/ppp1pppp/2n5/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R w KQkq - 2 3", + "moveId": "EKWVgjt5Z2Cz8bqD5Ie0k", + "variants": [], + "shapes": [], + "comment": null + } + ] +} diff --git a/storage/R26qhQYNfcEEe2gVA6PaC.json b/storage/R26qhQYNfcEEe2gVA6PaC.json index c1f3e02..8f41934 100644 --- a/storage/R26qhQYNfcEEe2gVA6PaC.json +++ b/storage/R26qhQYNfcEEe2gVA6PaC.json @@ -15,7 +15,13 @@ "after": "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1", "moveId": "EAyuEJsIKY7Nvp9v20DdD", "variants": [], - "shapes": [], + "shapes": [ + { + "orig": "d2", + "dest": "d4", + "brush": "green" + } + ], "comment": null }, { @@ -185,7 +191,32 @@ ] } ], - "shapes": [], + "shapes": [ + { + "orig": "f4", + "dest": "c1", + "brush": "green" + }, + { + "orig": "e6", + "brush": "green" + }, + { + "orig": "d6", + "dest": "c5", + "brush": "green" + }, + { + "orig": "d3", + "dest": "b3", + "brush": "green" + }, + { + "orig": "b5", + "dest": "d6", + "brush": "green" + } + ], "comment": null }, { @@ -253,23 +284,69 @@ "variants": [], "shapes": [ { - "orig": "f2", - "dest": "d4", + "orig": "b7", + "dest": "b4", "brush": "green" }, { - "orig": "c3", + "orig": "e7", "dest": "d5", "brush": "green" }, { - "orig": "d6", - "dest": "c5", + "orig": "f7", + "dest": "e5", + "brush": "green" + } + ], + "comment": null + }, + { + "color": "w", + "piece": "n", + "from": "f3", + "to": "e5", + "san": "Ne5", + "flags": "n", + "lan": "f3e5", + "before": "r1bqkbnr/ppp1pppp/2n5/3p4/3P4/5N2/PPP1PPPP/RNBQKB1R w KQkq - 2 3", + "after": "r1bqkbnr/ppp1pppp/2n5/3pN3/3P4/8/PPP1PPPP/RNBQKB1R b KQkq - 3 3", + "moveId": "LqVKpTOqwUOa7ue7pbJ50", + "variants": [], + "shapes": [ + { + "orig": "d3", + "dest": "e5", "brush": "green" }, { - "orig": "e5", - "dest": "f5", + "orig": "f7", + "dest": "d7", + "brush": "green" + }, + { + "orig": "b6", + "dest": "b5", + "brush": "green" + }, + { + "orig": "d4", + "dest": "c2", + "brush": "green" + }, + { + "orig": "b2", + "dest": "d4", + "brush": "green" + }, + { + "orig": "g6", + "dest": "f6", + "brush": "green" + }, + { + "orig": "e4", + "dest": "e3", "brush": "green" } ],