UNPKG

@react-chess-tools/react-chess-game

Version:

react-chess-game is a React component bridging chess.js with react-chessboard to offer a full-featured, ready-to-integrate chess board experience.

135 lines (123 loc) 3.45 kB
import { Chess, Color, Square } from "chess.js"; import _ from "lodash"; /** * Creates a clone of the given Chess.js instance. This is needed to update the state * of react-chessboard component * @param game - The Chess.js instance to clone. * @returns A new Chess.js instance with the same state as the original. */ export const cloneGame = (game: Chess) => { try { const copy = new Chess(); const pgn = game?.pgn(); if (pgn) { copy.loadPgn(pgn); } return copy; } catch (e) { console.error("Failed to clone game:", e); return new Chess(); } }; /** * Returns an object with information about the current state of the game. This can be determined * using chess.js instance, but this function is provided for convenience. * @param game - The Chess.js instance representing the game. * @returns An object with information about the current state of the game. */ export const getGameInfo = (game: Chess, orientation: Color) => { const turn = game.turn(); const isPlayerTurn = turn === orientation; const isOpponentTurn = !isPlayerTurn; const moveNumber = game.history().length; const lastMove = _.last(game.history({ verbose: true })); const isCheck = game.isCheck(); const isCheckmate = game.isCheckmate(); const isDraw = game.isDraw(); const isStalemate = game.isStalemate(); const isThreefoldRepetition = game.isThreefoldRepetition(); const isInsufficientMaterial = game.isInsufficientMaterial(); const isGameOver = game.isGameOver(); const hasPlayerWon = isOpponentTurn && isGameOver && !isDraw; const hasPlayerLost = isPlayerTurn && isGameOver && !isDraw; const isDrawn = game.isDraw(); return { turn, isPlayerTurn, isOpponentTurn, moveNumber, lastMove, isCheck, isCheckmate, isDraw, isStalemate, isThreefoldRepetition, isInsufficientMaterial, isGameOver, isDrawn, hasPlayerWon, hasPlayerLost, }; }; export type GameInfo = ReturnType<typeof getGameInfo>; export const isLegalMove = ( game: Chess, move: Parameters<Chess["move"]>[0], ) => { try { const copy = cloneGame(game); copy.move(move); return true; } catch (e) { return false; } }; export const requiresPromotion = ( game: Chess, move: Parameters<Chess["move"]>[0], ) => { if (!game) { throw new Error("Game is required"); } try { const copy = cloneGame(game); const result = copy.move(move); return result.flags.indexOf("p") !== -1; } catch (e) { if (e instanceof Error && e.message.includes("Invalid move")) { return false; } throw e; } }; export const getDestinationSquares = (game: Chess, square: Square) => { const moves = game.moves({ square, verbose: true }); return moves.map((move) => move.to); }; export const getCurrentFen = ( fen: string | undefined, game: Chess, currentMoveIndex: number, ) => { const tempGame = new Chess(); if (currentMoveIndex === -1) { if (fen) { try { tempGame.load(fen); } catch (e) { console.error("Failed to load FEN in getCurrentFen:", fen, e); } } } else { const moves = game.history().slice(0, currentMoveIndex + 1); if (fen) { try { tempGame.load(fen); } catch (e) { console.error("Failed to load FEN in getCurrentFen:", fen, e); } } moves.forEach((move) => tempGame.move(move)); } return tempGame.fen(); };