diff --git a/src-tauri/src/db/encoding.rs b/src-tauri/src/db/encoding.rs index a7bbad0a..4715550c 100644 --- a/src-tauri/src/db/encoding.rs +++ b/src-tauri/src/db/encoding.rs @@ -1,5 +1,5 @@ use crate::error::Error; -use shakmaty::{san::SanPlus, Chess, Move, Position}; +use shakmaty::{fen::Fen, san::SanPlus, CastlingMode, Chess, FromSetup, Move, Position}; pub fn encode_move(m: &Move, chess: &Chess) -> Result { let moves = chess.legal_moves(); @@ -11,8 +11,8 @@ pub fn decode_move(byte: u8, chess: &Chess) -> Option { legal_moves.get(byte as usize).cloned() } -pub fn decode_moves(moves_bytes: Vec) -> Result { - let mut chess = Chess::default(); +pub fn decode_moves(moves_bytes: Vec, initial_fen: Fen) -> Result { + let mut chess = Chess::from_setup(initial_fen.into(), CastlingMode::Standard).unwrap(); let mut moves = Vec::new(); for byte in moves_bytes { let m = decode_move(byte, &chess).unwrap(); diff --git a/src-tauri/src/db/mod.rs b/src-tauri/src/db/mod.rs index cf94472a..5b252217 100644 --- a/src-tauri/src/db/mod.rs +++ b/src-tauri/src/db/mod.rs @@ -21,7 +21,7 @@ use diesel::{ }; use pgn_reader::{BufferedReader, RawHeader, SanPlus, Skip, Visitor}; use serde::{Deserialize, Serialize}; -use shakmaty::{fen::Fen, Board, ByColor, Chess, Piece, Position}; +use shakmaty::{fen::Fen, Board, ByColor, Chess, FromSetup, Piece, Position}; use std::{ fs::{remove_file, File}, @@ -311,9 +311,10 @@ impl Visitor for Importer { if value.as_bytes() == b"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" { self.game.fen = None; } else { - // Don't process games that don't start in standard position - self.skip = true; - // self.current.fen = Some(value.decode_utf8_lossy().into_owned()); + let fen = Fen::from_ascii(value.as_bytes()).unwrap(); + self.game.fen = Some(value.decode_utf8_lossy().into_owned()); + self.game.position = + Chess::from_setup(fen.into_setup(), shakmaty::CastlingMode::Standard).unwrap(); } } } @@ -861,29 +862,36 @@ pub async fn get_games( fn normalize_games(games: Vec<(Game, Player, Player, Event, Site)>) -> Vec { games .into_iter() - .map(|(game, white, black, event, site)| NormalizedGame { - id: game.id, - event: event.name.unwrap_or_default(), - event_id: event.id, - site: site.name.unwrap_or_default(), - site_id: site.id, - date: game.date, - time: game.time, - round: game.round, - white: white.name.unwrap_or_default(), - white_id: game.white_id, - white_elo: game.white_elo, - black: black.name.unwrap_or_default(), - black_id: game.black_id, - black_elo: game.black_elo, - result: game.result, - time_control: game.time_control, - eco: game.eco, - white_material: game.white_material, - black_material: game.black_material, - ply_count: game.ply_count, - fen: game.fen.unwrap_or(Fen::default().to_string()), - moves: decode_moves(game.moves).unwrap_or_default(), + .map(|(game, white, black, event, site)| { + let fen: Fen = game + .fen + .map(|f| Fen::from_ascii(f.as_bytes()).unwrap()) + .unwrap_or_default(); + + NormalizedGame { + id: game.id, + event: event.name.unwrap_or_default(), + event_id: event.id, + site: site.name.unwrap_or_default(), + site_id: site.id, + date: game.date, + time: game.time, + round: game.round, + white: white.name.unwrap_or_default(), + white_id: game.white_id, + white_elo: game.white_elo, + black: black.name.unwrap_or_default(), + black_id: game.black_id, + black_elo: game.black_elo, + result: game.result, + time_control: game.time_control, + eco: game.eco, + white_material: game.white_material, + black_material: game.black_material, + ply_count: game.ply_count, + fen: fen.to_string(), + moves: decode_moves(game.moves, fen).unwrap_or_default(), + } }) .collect() } diff --git a/src/components/databases/GameCard.tsx b/src/components/databases/GameCard.tsx index ea36c850..e9e4dd51 100644 --- a/src/components/databases/GameCard.tsx +++ b/src/components/databases/GameCard.tsx @@ -9,7 +9,7 @@ function GameCard({ game }: { game: NormalizedGame }) { - + ); diff --git a/src/components/databases/GamePreview.tsx b/src/components/databases/GamePreview.tsx index 17940707..99ef6534 100644 --- a/src/components/databases/GamePreview.tsx +++ b/src/components/databases/GamePreview.tsx @@ -1,9 +1,8 @@ import { Box, Group, Stack, Text } from "@mantine/core"; -import { useHotkeys } from "react-hotkeys-hook"; import { useContext } from "react"; import { Chessground } from "@/chessground/Chessground"; import MoveControls from "../common/MoveControls"; -import { useAtomValue, useSetAtom } from "jotai"; +import { useSetAtom } from "jotai"; import { activeTabAtom } from "@/atoms/atoms"; import GameNotation from "../boards/GameNotation"; import { @@ -11,23 +10,24 @@ import { TreeStateContext, } from "../common/TreeStateContext"; import { useImmerReducer } from "use-immer"; -import treeReducer, { TreeState, getNodeAtPath } from "@/utils/treeReducer"; +import treeReducer, { GameHeaders, TreeState, getNodeAtPath } from "@/utils/treeReducer"; import { useNavigate } from "react-router-dom"; import { parsePGN } from "@/utils/chess"; import useSWR from "swr"; -import { keyMapAtom } from "@/atoms/keybinds"; function GamePreviewWrapper({ id, pgn, + headers, hideControls, }: { id?: string; pgn: string; + headers?: GameHeaders; hideControls?: boolean; }) { const { data: parsedGame, isLoading } = useSWR(pgn, async (game) => { - return await parsePGN(game); + return await parsePGN(game, headers?.fen); }); return ( @@ -62,10 +62,6 @@ function GamePreview({ const [treeState, dispatch] = useImmerReducer(treeReducer, game); - const keyMap = useAtomValue(keyMapAtom); - useHotkeys(keyMap.PREVIOUS_MOVE.keys, () => dispatch({ type: "GO_TO_PREVIOUS" })); - useHotkeys(keyMap.NEXT_MOVE.keys, () => dispatch({ type: "GO_TO_NEXT" })); - return ( diff --git a/src/utils/chess.ts b/src/utils/chess.ts index 3f4988ba..b4694c15 100644 --- a/src/utils/chess.ts +++ b/src/utils/chess.ts @@ -403,11 +403,11 @@ function innerParsePGN( return tree; } -export async function parsePGN(pgn: string, halfMoves = 0): Promise { +export async function parsePGN(pgn: string, initialFen?: string): Promise { const tokens = await invoke("lex_pgn", { pgn: pgn }); const headers = getPgnHeaders(tokens); - const tree = innerParsePGN(tokens, headers.fen, halfMoves); + const tree = innerParsePGN(tokens, initialFen || headers.fen, 0); tree.headers = headers; tree.position = headers.start ?? []; return tree; diff --git a/src/utils/tabs.ts b/src/utils/tabs.ts index 794b24d1..e260d2cf 100644 --- a/src/utils/tabs.ts +++ b/src/utils/tabs.ts @@ -42,7 +42,7 @@ export async function createTab({ const id = genID(); if (pgn) { - const tree = await parsePGN(pgn); + const tree = await parsePGN(pgn, headers?.fen); if (headers) { tree.headers = headers; }