1- import { useState , useMemo , useCallback , useEffect } from 'react'
1+ import { useState , useMemo , useCallback , useEffect , useRef } from 'react'
22import { Chess , PieceSymbol } from 'chess.ts'
33import { getGameMove } from 'src/api/play/play'
44import { useTreeController } from '../useTreeController'
@@ -96,12 +96,27 @@ export const useOpeningDrillController = (selections: OpeningSelection[]) => {
9696 currentSelection ?. playerColor || 'white' ,
9797 )
9898
99+ // Set board orientation based on player color
100+ useEffect ( ( ) => {
101+ if ( currentSelection ?. playerColor ) {
102+ controller . setOrientation ( currentSelection . playerColor )
103+ }
104+ } , [ currentSelection ?. playerColor , controller ] )
105+
99106 // Sync controller when switching selections
100107 useEffect ( ( ) => {
101- if ( currentDrillGame ?. tree ) {
108+ if ( currentDrillGame ?. tree && currentDrillGame . moves . length === 0 ) {
109+ // Only reset to root if no moves have been made
102110 controller . setCurrentNode ( currentDrillGame . tree . getRoot ( ) )
111+ } else if ( currentDrillGame ?. tree && currentDrillGame . moves . length > 0 ) {
112+ // Navigate to the last move if moves exist
113+ const mainLine = currentDrillGame . tree . getMainLine ( )
114+ const targetNode = mainLine [ currentDrillGame . moves . length ] // moves.length is 0-based, but mainLine includes root at index 0
115+ if ( targetNode ) {
116+ controller . setCurrentNode ( targetNode )
117+ }
103118 }
104- } , [ currentSelectionIndex , currentDrillGame ?. tree , controller ] )
119+ } , [ currentSelectionIndex , controller ] )
105120
106121 // Determine if it's the player's turn
107122 const isPlayerTurn = useMemo ( ( ) => {
@@ -135,35 +150,34 @@ export const useOpeningDrillController = (selections: OpeningSelection[]) => {
135150 if ( ! currentDrillGame || ! controller . currentNode || ! isPlayerTurn ) return
136151
137152 try {
138- // Add the player's move to the game tree
153+ // Validate the move first
139154 const chess = new Chess ( controller . currentNode . fen )
140- const moveObj = chess . move ( {
141- from : moveUci . slice ( 0 , 2 ) ,
142- to : moveUci . slice ( 2 , 4 ) ,
143- promotion : moveUci [ 4 ] ? ( moveUci [ 4 ] as PieceSymbol ) : undefined ,
144- } )
155+ const moveObj = chess . move ( moveUci , { sloppy : true } )
145156
146157 if ( ! moveObj ) return
147158
159+ // Add the move to the game tree
148160 const newNode = currentDrillGame . tree . addMoveToMainLine ( moveUci )
149161 if ( newNode ) {
150- controller . setCurrentNode ( newNode )
151-
152- // Update the drill game
162+ // Update the drill game state first
153163 const updatedGame = {
154164 ...currentDrillGame ,
155165 moves : [ ...currentDrillGame . moves , moveUci ] ,
156166 currentFen : newNode . fen ,
157167 }
168+
158169 setDrillGames ( ( prev ) => ( {
159170 ...prev ,
160171 [ currentSelection . id ] : updatedGame ,
161172 } ) )
162173
174+ // Then update the controller to the new node
175+ controller . setCurrentNode ( newNode )
176+
163177 // Get Maia's response after a short delay
164178 setTimeout ( async ( ) => {
165- await makeMaiaMove ( newNode )
166- } , 500 )
179+ await makeMaiaMoveRef . current ( newNode )
180+ } , 800 )
167181 }
168182 } catch ( error ) {
169183 console . error ( 'Error making player move:' , error )
@@ -179,7 +193,7 @@ export const useOpeningDrillController = (selections: OpeningSelection[]) => {
179193
180194 try {
181195 const response = await getGameMove (
182- currentDrillGame . moves ,
196+ [ ] ,
183197 currentSelection . maiaVersion ,
184198 fromNode . fen ,
185199 null ,
@@ -191,18 +205,20 @@ export const useOpeningDrillController = (selections: OpeningSelection[]) => {
191205 if ( maiaMove ) {
192206 const newNode = currentDrillGame . tree . addMoveToMainLine ( maiaMove )
193207 if ( newNode ) {
194- controller . setCurrentNode ( newNode )
195-
196- // Update the drill game
208+ // Update the drill game state first
197209 const updatedGame = {
198210 ...currentDrillGame ,
199211 moves : [ ...currentDrillGame . moves , maiaMove ] ,
200212 currentFen : newNode . fen ,
201213 }
214+
202215 setDrillGames ( ( prev ) => ( {
203216 ...prev ,
204217 [ currentSelection . id ] : updatedGame ,
205218 } ) )
219+
220+ // Then update the controller to the new node
221+ controller . setCurrentNode ( newNode )
206222 }
207223 }
208224 } catch ( error ) {
@@ -212,6 +228,10 @@ export const useOpeningDrillController = (selections: OpeningSelection[]) => {
212228 [ currentDrillGame , controller , currentSelection ] ,
213229 )
214230
231+ // Store makeMaiaMove in a ref to avoid circular dependencies
232+ const makeMaiaMoveRef = useRef ( makeMaiaMove )
233+ makeMaiaMoveRef . current = makeMaiaMove
234+
215235 // Handle initial Maia move if needed
216236 useEffect ( ( ) => {
217237 if (
@@ -222,10 +242,10 @@ export const useOpeningDrillController = (selections: OpeningSelection[]) => {
222242 ) {
223243 // It's Maia's turn to move first
224244 setTimeout ( ( ) => {
225- makeMaiaMove ( controller . currentNode )
245+ makeMaiaMoveRef . current ( controller . currentNode )
226246 } , 1000 )
227247 }
228- } , [ currentDrillGame , controller . currentNode , isPlayerTurn , makeMaiaMove ] )
248+ } , [ currentDrillGame , controller . currentNode , isPlayerTurn ] )
229249
230250 // Switch to a different opening selection
231251 const switchToSelection = useCallback (
0 commit comments