diff --git a/packages/chess/src/app/App.tsx b/packages/chess/src/app/App.tsx
index 14decb3..d9a2dc7 100644
--- a/packages/chess/src/app/App.tsx
+++ b/packages/chess/src/app/App.tsx
@@ -1,32 +1,51 @@
-import { Routes, Route } from 'react-router-dom'
+import { Routes, Route, useNavigate } from 'react-router-dom'
import { GameView } from '../ui/GameView'
import { RulesView } from '../ui/RulesView'
+import { SavePanel } from '../ui/SavePanel'
+import { useChessEngine } from '../hooks/useChessEngine'
+import { ChessEngine } from '../engine'
+import type { AttrKey, FactValue } from '@paratype/rete'
export function App() {
+ const chessState = useChessEngine()
+
return (
} />
- } />
+ } />
} />
- } />
+ } />
)
}
+function SaveWrapper({ chessState }: { chessState: ReturnType }) {
+ const navigate = useNavigate()
+ return (
+ {
+ const newEngine = new ChessEngine()
+ const oldFacts = newEngine.session.allFacts();
+ for (const f of oldFacts) {
+ newEngine.session.retract(f.id, f.attr as AttrKey);
+ }
+ for (const fact of loadedFacts) {
+ newEngine.session.insert(fact.id, fact.attr as AttrKey, fact.value as FactValue)
+ }
+ chessState.loadEngine(newEngine)
+ navigate('/game')
+ }}
+ />
+ )
+}
+
function Home() {
return (
Home
)
-}
-
-function Save() {
- return (
-
- Save
-
- )
-}
+}
\ No newline at end of file
diff --git a/packages/chess/src/hooks/useChessEngine.ts b/packages/chess/src/hooks/useChessEngine.ts
index 5f37dde..056f3b1 100644
--- a/packages/chess/src/hooks/useChessEngine.ts
+++ b/packages/chess/src/hooks/useChessEngine.ts
@@ -4,6 +4,7 @@ import type { PieceType } from '../schema';
export function useChessEngine() {
const engineRef = useRef(null);
+ const moveHistoryRef = useRef>([]);
// Force re-render state
const [tick, setTick] = useState(0);
@@ -15,6 +16,12 @@ export function useChessEngine() {
const engine = engineRef.current;
+ const loadEngine = useCallback((newEngine: ChessEngine) => {
+ engineRef.current = newEngine;
+ moveHistoryRef.current = [];
+ setTick(t => t + 1);
+ }, []);
+
const getTurn = useCallback(() => {
return engine.getCurrentTurn();
}, [engine, tick]);
@@ -34,6 +41,7 @@ export function useChessEngine() {
const applyMove = useCallback((from: number, to: number, promoteTo: PieceType = 'queen'): GameResult | null => {
const move = engine.findMove(from, to, promoteTo);
if (move) {
+ moveHistoryRef.current.push({ from, to, promoteTo });
const result = engine.applyMove(move, promoteTo);
setTick(t => t + 1); // trigger re-render
return result;
@@ -41,6 +49,21 @@ export function useChessEngine() {
return null;
}, [engine]);
+ const undo = useCallback(() => {
+ if (moveHistoryRef.current.length > 0) {
+ moveHistoryRef.current.pop();
+ const newEngine = new ChessEngine();
+ for (const historyMove of moveHistoryRef.current) {
+ const move = newEngine.findMove(historyMove.from, historyMove.to, historyMove.promoteTo);
+ if (move) {
+ newEngine.applyMove(move, historyMove.promoteTo);
+ }
+ }
+ engineRef.current = newEngine;
+ setTick(t => t + 1);
+ }
+ }, []);
+
return {
engine,
turn: getTurn(),
@@ -48,5 +71,8 @@ export function useChessEngine() {
legalMoves: getLegalMoves(),
result: getResult(),
applyMove,
+ undo,
+ canUndo: moveHistoryRef.current.length > 0,
+ loadEngine,
};
}
diff --git a/packages/chess/src/ui/GameView.tsx b/packages/chess/src/ui/GameView.tsx
index 3771401..21657fa 100644
--- a/packages/chess/src/ui/GameView.tsx
+++ b/packages/chess/src/ui/GameView.tsx
@@ -1,14 +1,17 @@
-import { useChessEngine } from '../hooks/useChessEngine';
import { Board } from './Board';
-
+import { useChessEngine } from '../hooks/useChessEngine';
import type { ChessFact, ChessAttrMap } from '../schema';
interface GameViewProps {
- onUndo?: () => void;
+ engineState?: ReturnType;
}
-export function GameView({ onUndo }: GameViewProps) {
- const { facts, legalMoves, turn, result, applyMove } = useChessEngine();
+export function GameView({ engineState }: GameViewProps) {
+ // Use passed in engine state or create local state if none provided
+ const localChessState = useChessEngine();
+ const state = engineState || localChessState;
+
+ const { facts, legalMoves, turn, result, applyMove, undo, canUndo } = state;
const handleMove = (from: number, to: number) => {
applyMove(from, to, 'queen');
@@ -39,8 +42,9 @@ export function GameView({ onUndo }: GameViewProps) {