@@ -88,7 +88,8 @@ const AnimatedGameReplay: React.FC<{
8888 openingFen : string
8989 playerColor : 'white' | 'black'
9090 gameTree : GameTree
91- } > = ( { openingFen, playerColor, gameTree } ) => {
91+ openingEndNode : GameNode
92+ } > = ( { openingFen, playerColor, gameTree, openingEndNode } ) => {
9293 const [ currentFen , setCurrentFen ] = useState ( openingFen )
9394 const [ currentNode , setCurrentNode ] = useState < GameNode | null > ( null )
9495
@@ -230,16 +231,15 @@ const AnimatedGameReplay: React.FC<{
230231
231232 { /* Move History - Use MovesContainer for consistency */ }
232233 < div className = "flex min-h-0 flex-1 flex-col border-t border-white/10" >
233- < TreeControllerContext . Provider value = { treeController } >
234- < MovesContainer
235- game = { {
236- id : 'drill-performance' ,
237- tree : gameTree ,
238- } }
239- showAnnotations = { true }
240- showVariations = { false }
241- />
242- </ TreeControllerContext . Provider >
234+ < MovesContainer
235+ game = { {
236+ id : 'drill-performance' ,
237+ tree : gameTree ,
238+ } }
239+ startFromNode = { openingEndNode }
240+ showAnnotations = { true }
241+ showVariations = { false }
242+ />
243243 </ div >
244244 </ div >
245245 )
@@ -728,6 +728,7 @@ const DesktopLayout: React.FC<{
728728 onNextDrill : ( ) => void
729729 isLastDrill : boolean
730730 gameTree : GameTree
731+ openingEndNode : GameNode
731732 playerMoveCount : number
732733 treeController : ReturnType < typeof useTreeController >
733734 gameNodesMap : Map < string , GameNode >
@@ -745,6 +746,7 @@ const DesktopLayout: React.FC<{
745746 onNextDrill,
746747 isLastDrill,
747748 gameTree,
749+ openingEndNode,
748750 playerMoveCount,
749751 treeController,
750752 gameNodesMap,
@@ -785,14 +787,15 @@ const DesktopLayout: React.FC<{
785787 < div className = "flex w-1/3 flex-col border-r border-white/10" >
786788 < TreeControllerContext . Provider
787789 value = { {
788- gameTree : treeController . tree ,
790+ gameTree : gameTree ,
789791 ...treeController ,
790792 } }
791793 >
792794 < AnimatedGameReplay
793795 openingFen = { openingFen }
794796 playerColor = { drill . selection . playerColor }
795797 gameTree = { gameTree }
798+ openingEndNode = { openingEndNode }
796799 />
797800 </ TreeControllerContext . Provider >
798801 </ div >
@@ -1041,6 +1044,7 @@ const MobileLayout: React.FC<{
10411044 activeTab : 'replay' | 'analysis' | 'insights'
10421045 setActiveTab : ( tab : 'replay' | 'analysis' | 'insights' ) => void
10431046 gameTree : GameTree
1047+ openingEndNode : GameNode
10441048 playerMoveCount : number
10451049 treeController : ReturnType < typeof useTreeController >
10461050 gameNodesMap : Map < string , GameNode >
@@ -1060,6 +1064,7 @@ const MobileLayout: React.FC<{
10601064 activeTab,
10611065 setActiveTab,
10621066 gameTree,
1067+ openingEndNode,
10631068 playerMoveCount,
10641069 treeController,
10651070 gameNodesMap,
@@ -1130,14 +1135,15 @@ const MobileLayout: React.FC<{
11301135 { activeTab === 'replay' && (
11311136 < TreeControllerContext . Provider
11321137 value = { {
1133- gameTree : treeController . tree ,
1138+ gameTree : gameTree ,
11341139 ...treeController ,
11351140 } }
11361141 >
11371142 < AnimatedGameReplay
11381143 openingFen = { openingFen }
11391144 playerColor = { drill . selection . playerColor }
11401145 gameTree = { gameTree }
1146+ openingEndNode = { openingEndNode }
11411147 />
11421148 </ TreeControllerContext . Provider >
11431149 ) }
@@ -1241,62 +1247,74 @@ export const DrillPerformanceModal: React.FC<Props> = ({
12411247 // For now, let's work directly with the nodes instead of trying to recreate the full tree
12421248 // This is a temporary solution until we can properly access the GameTree
12431249
1244- // Create a proper GameTree starting from the opening end node
1245- const gameTree = useMemo ( ( ) => {
1246- // Get the root node and build the tree from there
1247- let root = drill . finalNode
1248- while ( root . parent ) {
1249- root = root . parent
1250+ // Get the original game tree and opening end node for the drill context
1251+ const { gameTree, openingEndNode } = useMemo ( ( ) => {
1252+ // Get the original game tree from the drill
1253+ const originalRoot = ( ( ) => {
1254+ let root = drill . finalNode
1255+ while ( root . parent ) {
1256+ root = root . parent
1257+ }
1258+ return root
1259+ } ) ( )
1260+
1261+ // Create the original GameTree from root
1262+ const originalGameTree = new GameTree ( originalRoot . fen )
1263+ // Set the root to be the actual root node
1264+ Object . defineProperty ( originalGameTree , 'root' , { value : originalRoot } )
1265+
1266+ // Find the opening end node by working backwards from the final node
1267+ // The opening end should be the first move analysis that is NOT a player move
1268+ const firstPlayerMoveAnalysis = moveAnalyses . find ( move => move . isPlayerMove )
1269+ if ( firstPlayerMoveAnalysis && firstPlayerMoveAnalysis . fenBeforeMove ) {
1270+ // Find the node that represents the position before the first player move
1271+ const findNodeByFen = ( node : GameNode , targetFen : string ) : GameNode | null => {
1272+ if ( node . fen === targetFen ) {
1273+ return node
1274+ }
1275+ // Check main child
1276+ if ( node . mainChild ) {
1277+ const found = findNodeByFen ( node . mainChild , targetFen )
1278+ if ( found ) return found
1279+ }
1280+ // Check all children
1281+ for ( const child of node . children ) {
1282+ const found = findNodeByFen ( child , targetFen )
1283+ if ( found ) return found
1284+ }
1285+ return null
1286+ }
1287+
1288+ const foundOpeningEndNode = findNodeByFen ( originalRoot , firstPlayerMoveAnalysis . fenBeforeMove )
1289+ if ( foundOpeningEndNode ) {
1290+ return {
1291+ gameTree : originalGameTree ,
1292+ openingEndNode : foundOpeningEndNode ,
1293+ }
1294+ }
12501295 }
12511296
1252- // Find the opening end node from the drill selection
1297+ // Fallback: use the selection-based approach
12531298 const openingEndFen = drill . selection . variation
12541299 ? drill . selection . variation . fen
12551300 : drill . selection . opening . fen
12561301
12571302 // Find the actual opening end node in the tree
1258- let openingEndTreeNode = root
1259- let current : GameNode | null = root
1303+ let foundOpeningEndNode = originalRoot
1304+ let current : GameNode | null = originalRoot
12601305 while ( current ) {
12611306 if ( current . fen === openingEndFen ) {
1262- openingEndTreeNode = current
1307+ foundOpeningEndNode = current
12631308 break
12641309 }
12651310 current = current . mainChild
12661311 }
12671312
1268- // Create a new GameTree starting from the opening end node
1269- const newTree = new ( class extends GameTree {
1270- constructor ( startNode : GameNode ) {
1271- super ( startNode . fen )
1272- // Replace the root with our opening end node
1273- this . setRoot ( startNode )
1274- }
1275-
1276- private setRoot ( node : GameNode ) {
1277- // Use reflection to set the private root field
1278- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1279- ; ( this as any ) . root = node
1280- }
1281-
1282- getRoot ( ) : GameNode {
1283- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1284- return ( this as any ) . root
1285- }
1286-
1287- getMainLine ( ) : GameNode [ ] {
1288- const mainLine = [ ]
1289- let current : GameNode | null = this . getRoot ( )
1290- while ( current ) {
1291- mainLine . push ( current )
1292- current = current . mainChild
1293- }
1294- return mainLine
1295- }
1296- } ) ( openingEndTreeNode )
1297-
1298- return newTree
1299- } , [ drill . finalNode , drill . selection ] )
1313+ return {
1314+ gameTree : originalGameTree ,
1315+ openingEndNode : foundOpeningEndNode ,
1316+ }
1317+ } , [ drill . finalNode , drill . selection , moveAnalyses ] )
13001318
13011319 // Create tree controller for navigation
13021320 const treeController = useTreeController (
@@ -1377,10 +1395,8 @@ export const DrillPerformanceModal: React.FC<Props> = ({
13771395 return evaluationChart . slice ( startIndex )
13781396 } , [ evaluationChart , moveAnalyses ] )
13791397
1380- // Get opening FEN from the drill
1381- const openingFen = drill . selection . variation
1382- ? drill . selection . variation . fen
1383- : drill . selection . opening . fen
1398+ // Get opening FEN from the opening end node
1399+ const openingFen = openingEndNode . fen
13841400
13851401 return (
13861402 < ModalContainer dismiss = { onContinueAnalyzing } >
@@ -1396,6 +1412,7 @@ export const DrillPerformanceModal: React.FC<Props> = ({
13961412 activeTab = { activeTab }
13971413 setActiveTab = { setActiveTab }
13981414 gameTree = { gameTree }
1415+ openingEndNode = { openingEndNode }
13991416 playerMoveCount = { playerMoveCount }
14001417 treeController = { treeController }
14011418 gameNodesMap = { gameNodesMap }
@@ -1412,6 +1429,7 @@ export const DrillPerformanceModal: React.FC<Props> = ({
14121429 onNextDrill = { onNextDrill }
14131430 isLastDrill = { isLastDrill }
14141431 gameTree = { gameTree }
1432+ openingEndNode = { openingEndNode }
14151433 playerMoveCount = { playerMoveCount }
14161434 treeController = { treeController }
14171435 gameNodesMap = { gameNodesMap }
0 commit comments