@@ -193,6 +193,10 @@ export const useBroadcastController = (): BroadcastStreamController => {
193193 if ( roundData ) {
194194 const game = roundData . games . get ( gameId )
195195 if ( game ) {
196+ console . log (
197+ 'Manual game selection:' ,
198+ game . white + ' vs ' + game . black ,
199+ )
196200 setCurrentGame ( game )
197201 }
198202 }
@@ -226,46 +230,99 @@ export const useBroadcastController = (): BroadcastStreamController => {
226230 const startingFen =
227231 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
228232
229- // Build game tree from moves
230- const tree = new GameTree ( startingFen )
231- const chess = new Chess ( startingFen )
232- let currentNode = tree . getRoot ( )
233-
234- const gameStates = [
235- {
236- board : startingFen ,
237- lastMove : undefined as [ string , string ] | undefined ,
238- san : undefined as string | undefined ,
239- check : false ,
240- maia_values : { } ,
241- } ,
242- ]
233+ // Check if we have an existing game state to build upon
234+ const existingLiveGame = gameStates . current . get ( broadcastGame . id )
235+
236+ let tree : GameTree
237+ let movesList : any [ ]
238+ let existingMoveCount = 0
239+
240+ if ( existingLiveGame && existingLiveGame . tree ) {
241+ // Reuse existing tree and states - preserve all analysis and variations
242+ tree = existingLiveGame . tree
243+ movesList = [ ...existingLiveGame . moves ]
244+ existingMoveCount = movesList . length - 1 // Subtract 1 for initial position
245+ console . log (
246+ `Reusing existing tree with ${ existingMoveCount } moves, adding ${ broadcastGame . moves . length - existingMoveCount } new moves` ,
247+ )
248+ } else {
249+ // Create new tree only for new games
250+ tree = new GameTree ( startingFen )
251+ movesList = [
252+ {
253+ board : startingFen ,
254+ lastMove : undefined as [ string , string ] | undefined ,
255+ san : undefined as string | undefined ,
256+ check : false ,
257+ maia_values : { } ,
258+ } ,
259+ ]
260+ console . log (
261+ `Creating new tree for ${ broadcastGame . white } vs ${ broadcastGame . black } ` ,
262+ )
263+ }
243264
244- // Process each move
245- for ( const moveStr of broadcastGame . moves ) {
246- try {
247- const move = chess . move ( moveStr )
248- if ( move ) {
249- const newFen = chess . fen ( )
250- const uci =
251- move . from + move . to + ( move . promotion ? move . promotion : '' )
252-
253- gameStates . push ( {
254- board : newFen ,
255- lastMove : [ move . from , move . to ] ,
256- san : move . san ,
257- check : chess . inCheck ( ) ,
258- maia_values : { } ,
259- } )
260-
261- currentNode = tree . addMainMove ( currentNode , newFen , uci , move . san )
265+ // Only process new moves that we don't already have
266+ if ( broadcastGame . moves . length > existingMoveCount ) {
267+ const chess = new Chess ( startingFen )
268+ let currentNode = tree . getRoot ( )
269+
270+ // Replay existing moves to get to the current position
271+ for ( let i = 0 ; i < existingMoveCount ; i ++ ) {
272+ try {
273+ const move = chess . move ( broadcastGame . moves [ i ] )
274+ if ( move && currentNode . mainChild ) {
275+ currentNode = currentNode . mainChild
276+ }
277+ } catch ( error ) {
278+ console . warn (
279+ `Error replaying existing move ${ broadcastGame . moves [ i ] } :` ,
280+ error ,
281+ )
282+ break
283+ }
284+ }
285+
286+ // Add only the new moves
287+ for ( let i = existingMoveCount ; i < broadcastGame . moves . length ; i ++ ) {
288+ try {
289+ const moveStr = broadcastGame . moves [ i ]
290+ const move = chess . move ( moveStr )
291+ if ( move ) {
292+ const newFen = chess . fen ( )
293+ const uci =
294+ move . from + move . to + ( move . promotion ? move . promotion : '' )
295+
296+ movesList . push ( {
297+ board : newFen ,
298+ lastMove : [ move . from , move . to ] ,
299+ san : move . san ,
300+ check : chess . inCheck ( ) ,
301+ maia_values : { } ,
302+ } )
303+
304+ currentNode = tree . addMainMove ( currentNode , newFen , uci , move . san )
305+ console . log ( `Added new move: ${ move . san } ` )
306+ }
307+ } catch ( error ) {
308+ console . warn (
309+ `Error processing new move ${ broadcastGame . moves [ i ] } :` ,
310+ error ,
311+ )
312+ break
262313 }
263- } catch ( error ) {
264- console . warn ( `Error processing move ${ moveStr } :` , error )
265- break
266314 }
267315 }
268316
317+ // Preserve existing availableMoves array (legacy) and extend if needed
318+ const availableMoves =
319+ existingLiveGame ?. availableMoves || new Array ( movesList . length ) . fill ( { } )
320+
321+ // Extend availableMoves array if we have new moves
322+ while ( availableMoves . length < movesList . length ) {
323+ availableMoves . push ( { } )
324+ }
325+
269326 return {
270327 id : broadcastGame . id ,
271328 blackPlayer : {
@@ -278,10 +335,8 @@ export const useBroadcastController = (): BroadcastStreamController => {
278335 } ,
279336 gameType : 'broadcast' ,
280337 type : 'stream' as const ,
281- moves : gameStates ,
282- availableMoves : new Array ( gameStates . length ) . fill (
283- { } ,
284- ) as AvailableMoves [ ] ,
338+ moves : movesList ,
339+ availableMoves : availableMoves as AvailableMoves [ ] ,
285340 termination :
286341 broadcastGame . result === '*'
287342 ? undefined
@@ -294,8 +349,8 @@ export const useBroadcastController = (): BroadcastStreamController => {
294349 ? 'black'
295350 : 'none' ,
296351 } ,
297- maiaEvaluations : [ ] ,
298- stockfishEvaluations : [ ] ,
352+ maiaEvaluations : existingLiveGame ?. maiaEvaluations || [ ] ,
353+ stockfishEvaluations : existingLiveGame ?. stockfishEvaluations || [ ] ,
299354 loadedFen : broadcastGame . fen ,
300355 loaded : true ,
301356 tree,
@@ -366,15 +421,30 @@ export const useBroadcastController = (): BroadcastStreamController => {
366421
367422 // Update current game data if it's in the update, but don't switch to a different game
368423 if ( currentGame ) {
424+ console . log (
425+ 'Current game selected:' ,
426+ currentGame . white + ' vs ' + currentGame . black ,
427+ )
369428 const updatedCurrentGame = parseResult . games . find (
370429 ( g ) => g . id === currentGame . id ,
371430 )
372431 if ( updatedCurrentGame ) {
432+ console . log ( 'Updating current game with new data' )
373433 // Update the currently selected game with new data (including clocks)
374434 setCurrentGame ( updatedCurrentGame )
435+ } else {
436+ console . log (
437+ 'Current game not in update - keeping selection unchanged' ,
438+ )
375439 }
440+ // Important: Do NOT change game selection if current game is not in the update
376441 } else if ( parseResult . games . length > 0 ) {
377442 // Auto-select first game only if no game is currently selected
443+ console . log ( 'No game selected - auto-selecting first game' )
444+ console . log (
445+ 'Auto-selecting:' ,
446+ parseResult . games [ 0 ] . white + ' vs ' + parseResult . games [ 0 ] . black ,
447+ )
378448 setCurrentGame ( parseResult . games [ 0 ] )
379449 }
380450
0 commit comments