UNPKG

@react-chess-puzzle-fix/react-chess-puzzle

Version:

A lightweight, customizable React component library for rendering and interacting with chess puzzles.

173 lines (158 loc) 3.88 kB
import { Chess, Move } from "chess.js"; import { type Puzzle, type Hint, type Status } from "../utils"; export type State = { puzzle: Puzzle; currentMoveIndex: number; status: Status; cpuMove?: string | null; nextMove?: string | null; hint: Hint; needCpuMove: boolean; isPlayerTurn: boolean; }; export type Action = | { type: "INITIALIZE"; payload: { puzzle: Puzzle; }; } | { type: "RESET"; } | { type: "TOGGLE_HINT" } | { type: "CPU_MOVE"; } | { type: "PLAYER_MOVE"; payload: { move?: Move | null; onSolve?: (changePuzzle: (puzzle: Puzzle) => void) => void; onFail?: (changePuzzle: (puzzle: Puzzle) => void) => void; changePuzzle: (puzzle: Puzzle) => void; game: Chess; }; } | { type: "AUTO_RETRY"; payload: { puzzle: Puzzle; }; }; export const initializePuzzle = ({ puzzle }: { puzzle: Puzzle }): State => { return { puzzle, currentMoveIndex: 0, status: "not-started", nextMove: puzzle.moves[0], hint: "none", cpuMove: null, needCpuMove: !!puzzle.makeFirstMove, isPlayerTurn: !puzzle.makeFirstMove, }; }; export const autoRetryPuzzle = ( { puzzle }: { puzzle: Puzzle }, currentMove: number, ): State => { return { puzzle, currentMoveIndex: currentMove, status: "in-progress", nextMove: puzzle.moves[currentMove], hint: "none", cpuMove: null, needCpuMove: false, isPlayerTurn: true, }; }; export const reducer = (state: State, action: Action): State => { switch (action.type) { case "INITIALIZE": return { ...state, ...initializePuzzle(action.payload), }; case "RESET": return { ...state, ...initializePuzzle({ puzzle: state.puzzle, }), }; case "TOGGLE_HINT": if (state.hint === "none") { return { ...state, hint: "piece" }; } return { ...state, hint: "move" }; case "CPU_MOVE": if (state.isPlayerTurn) { return state; } if (["solved", "failed"].includes(state.status)) { return state; } return { ...state, currentMoveIndex: state.currentMoveIndex + 1, cpuMove: state.puzzle.moves[state.currentMoveIndex], nextMove: state.currentMoveIndex < state.puzzle.moves.length - 1 ? state.puzzle.moves[state.currentMoveIndex + 1] : null, needCpuMove: false, isPlayerTurn: true, status: "in-progress", }; case "PLAYER_MOVE": { const { move, onSolve, onFail, changePuzzle } = action.payload; const isMoveRight = [move?.san, move?.lan].includes( state?.nextMove || "", ); const isPuzzleSolved = state.currentMoveIndex === state.puzzle.moves.length - 1; if (!isMoveRight) { if (onFail) { onFail(changePuzzle); } return { ...state, status: "failed", nextMove: null, hint: "none", isPlayerTurn: false, }; } if (isPuzzleSolved) { if (onSolve) { onSolve(changePuzzle); } return { ...state, status: "solved", nextMove: null, hint: "none", isPlayerTurn: false, }; } return { ...state, hint: "none", currentMoveIndex: state.currentMoveIndex + 1, nextMove: state.puzzle.moves[state.currentMoveIndex + 1], status: "in-progress", needCpuMove: true, isPlayerTurn: false, }; } case "AUTO_RETRY": { return { ...state, ...autoRetryPuzzle(action.payload, state.currentMoveIndex), }; } default: return state; } };