@@ -38,14 +38,12 @@ const computeTermination = (chess: Chess): Termination | undefined => {
3838}
3939
4040export const usePlayMaiaController = ( id : string , config : PlayGameConfig ) => {
41- // Core game state
4241 const [ gameTree , setGameTree ] = useState < GameTree > (
4342 ( ) => new GameTree ( config . startFen || nullFen ) ,
4443 )
45- const [ moveTimes , setMoveTimes ] = useState < number [ ] > ( [ ] )
44+ const [ treeVersion , setTreeVersion ] = useState < number > ( 0 )
4645 const [ resigned , setResigned ] = useState < boolean > ( false )
4746
48- // Clock state
4947 const [ baseMinutes , incrementSeconds ] =
5048 config . timeControl == 'unlimited'
5149 ? [ 0 , 0 ]
@@ -56,16 +54,22 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
5654 const [ blackClock , setBlackClock ] = useState < number > ( initialClockValue )
5755 const [ lastMoveTime , setLastMoveTime ] = useState < number > ( 0 )
5856
59- // Navigation state
6057 const [ currentNode , setCurrentNode ] = useState < GameNode | undefined > ( ( ) =>
6158 gameTree . getRoot ( ) ,
6259 )
6360 const [ orientation , setOrientation ] = useState < 'white' | 'black' > (
6461 config . player ,
6562 )
6663
67- // Derived game state
68- const moveList = useMemo ( ( ) => gameTree . toMoveArray ( ) , [ gameTree ] )
64+ const moveList = useMemo (
65+ ( ) => gameTree . toMoveArray ( ) ,
66+ [ gameTree , treeVersion ] ,
67+ )
68+
69+ const moveTimes = useMemo (
70+ ( ) => gameTree . toTimeArray ( ) ,
71+ [ gameTree , treeVersion ] ,
72+ )
6973
7074 const game : PlayedGame = useMemo ( ( ) => {
7175 const mainLine = gameTree . getMainLine ( )
@@ -80,7 +84,6 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
8084 } as Termination )
8185 : computeTermination ( chess )
8286
83- // Build moves array for compatibility
8487 const moves = [ ]
8588 const rootNode = gameTree . getRoot ( )
8689 const rootChess = new Chess ( rootNode . fen )
@@ -114,12 +117,11 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
114117 termination,
115118 turn : chess . turn ( ) == 'b' ? 'black' : 'white' ,
116119 }
117- } , [ gameTree , resigned , whiteClock , blackClock , id ] )
120+ } , [ gameTree , treeVersion , resigned , whiteClock , blackClock , id ] )
118121
119122 const toPlay : Color | null = game . termination ? null : game . turn
120123 const playerActive = toPlay == config . player
121124
122- // Available moves and pieces
123125 const { availableMoves, pieces } = useMemo ( ( ) => {
124126 if ( ! currentNode ) return { availableMoves : [ ] , pieces : { } }
125127
@@ -146,9 +148,8 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
146148 }
147149
148150 return { availableMoves, pieces }
149- } , [ currentNode , playerActive , game . termination ] )
151+ } , [ currentNode , playerActive , game . termination , treeVersion ] )
150152
151- // Navigation helpers
152153 const goToNode = useCallback ( ( node : GameNode ) => setCurrentNode ( node ) , [ ] )
153154 const goToNextNode = useCallback ( ( ) => {
154155 if ( currentNode ?. mainChild ) setCurrentNode ( currentNode . mainChild )
@@ -161,13 +162,14 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
161162 [ gameTree ] ,
162163 )
163164
164- const plyCount = useMemo ( ( ) => gameTree . getMainLine ( ) . length , [ gameTree ] )
165+ const plyCount = useMemo (
166+ ( ) => gameTree . getMainLine ( ) . length ,
167+ [ gameTree , treeVersion ] ,
168+ )
165169
166- // Clock management
167170 const updateClock = useCallback (
168171 ( overrideTime : number | undefined = undefined ) : number => {
169172 if ( moveList . length < 2 ) {
170- setMoveTimes ( [ ...moveTimes , 0 ] )
171173 return 0 // Clock does not start until first two moves made
172174 }
173175
@@ -187,22 +189,19 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
187189 }
188190 }
189191
190- setMoveTimes ( [ ...moveTimes , elapsed ] )
191192 setLastMoveTime ( now )
192193 return elapsed
193194 } ,
194195 [
195196 moveList . length ,
196197 lastMoveTime ,
197- moveTimes ,
198198 toPlay ,
199199 whiteClock ,
200200 blackClock ,
201201 incrementSeconds ,
202202 ] ,
203203 )
204204
205- // Game end by time
206205 useEffect ( ( ) => {
207206 if (
208207 playerActive &&
@@ -227,76 +226,39 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
227226 whiteClock ,
228227 ] )
229228
230- // Move handling
231229 const addMove = useCallback (
232230 ( moveUci : string ) => {
233- const mainLine = gameTree . getMainLine ( )
234- const lastNode = mainLine [ mainLine . length - 1 ]
235- const chess = new Chess ( lastNode . fen )
236- const result = chess . move ( moveUci , { sloppy : true } )
237-
238- if ( result ) {
239- const newTree = new GameTree ( gameTree . getRoot ( ) . fen )
240- // Rebuild tree with existing moves plus new move
241- const existingMoves = gameTree . toMoveArray ( )
242- let node = newTree . getRoot ( )
243-
244- for ( const move of [ ...existingMoves , moveUci ] ) {
245- const tempChess = new Chess ( node . fen )
246- const tempResult = tempChess . move ( move , { sloppy : true } )
247- if ( tempResult ) {
248- node = newTree . addMainMove (
249- node ,
250- tempChess . fen ( ) ,
251- move ,
252- tempResult . san ,
253- )
254- }
255- }
256-
257- setGameTree ( newTree )
258- setCurrentNode ( node ) // Move to the new position
231+ const newNode = gameTree . addMoveToMainLine ( moveUci )
232+ if ( newNode ) {
233+ setCurrentNode ( newNode )
234+ // Force re-render by incrementing tree version
235+ setTreeVersion ( ( prev ) => prev + 1 )
259236 }
260237 } ,
261238 [ gameTree ] ,
262239 )
263240
264241 const addMoveWithTime = useCallback (
265242 ( moveUci : string , moveTime : number ) => {
266- addMove ( moveUci )
267- setMoveTimes ( [ ...moveTimes , moveTime ] )
268- } ,
269- [ addMove , moveTimes ] ,
270- )
271-
272- // Legacy compatibility
273- const setMoves = useCallback (
274- ( newMoves : string [ ] ) => {
275- const newTree = new GameTree ( config . startFen || nullFen )
276- let node = newTree . getRoot ( )
277-
278- for ( const move of newMoves ) {
279- const chess = new Chess ( node . fen )
280- const result = chess . move ( move , { sloppy : true } )
281- if ( result ) {
282- node = newTree . addMainMove ( node , chess . fen ( ) , move , result . san )
283- }
243+ const newNode = gameTree . addMoveToMainLine ( moveUci , moveTime )
244+ if ( newNode ) {
245+ setCurrentNode ( newNode )
246+ // Force re-render by incrementing tree version
247+ setTreeVersion ( ( prev ) => prev + 1 )
284248 }
285-
286- setGameTree ( newTree )
287- setCurrentNode ( node )
288249 } ,
289- [ config . startFen ] ,
250+ [ gameTree ] ,
290251 )
291252
292253 const reset = ( ) => {
293- setGameTree ( new GameTree ( config . startFen || nullFen ) )
294- setCurrentNode ( gameTree . getRoot ( ) )
295- setMoveTimes ( [ ] )
254+ const newTree = new GameTree ( config . startFen || nullFen )
255+ setGameTree ( newTree )
256+ setCurrentNode ( newTree . getRoot ( ) )
296257 setResigned ( false )
297258 setLastMoveTime ( 0 )
298259 setWhiteClock ( initialClockValue )
299260 setBlackClock ( initialClockValue )
261+ setTreeVersion ( ( prev ) => prev + 1 )
300262 }
301263
302264 const makeMove = async ( moveUci : string ) : Promise < void > => {
@@ -311,7 +273,6 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
311273 }
312274
313275 return {
314- // Game state
315276 game,
316277 gameTree,
317278 currentNode,
@@ -342,8 +303,6 @@ export const usePlayMaiaController = (id: string, config: PlayGameConfig) => {
342303
343304 addMove,
344305 addMoveWithTime,
345- setMoves,
346- setMoveTimes,
347306 setResigned,
348307 reset,
349308 makeMove,
0 commit comments