@@ -89,10 +89,10 @@ export const useAnalysisController = (game: AnalyzedGame) => {
8989 maiaEval [ model ] = result [ index ]
9090 } )
9191
92- controller . currentNode . addMaiaAnalysis ( maiaEval )
92+ controller . currentNode . addMaiaAnalysis ( maiaEval , currentMaiaModel )
9393 setAnalysisState ( ( state ) => state + 1 )
9494 } ) ( )
95- } , [ maiaStatus , controller . currentNode , analysisState ] )
95+ } , [ maiaStatus , controller . currentNode , analysisState , currentMaiaModel ] )
9696
9797 useEffect ( ( ) => {
9898 if ( ! controller . currentNode ) return
@@ -115,7 +115,10 @@ export const useAnalysisController = (game: AnalyzedGame) => {
115115 stopEvaluation ( )
116116 break
117117 }
118- controller . currentNode . addStockfishAnalysis ( evaluation )
118+ controller . currentNode . addStockfishAnalysis (
119+ evaluation ,
120+ currentMaiaModel ,
121+ )
119122 setAnalysisState ( ( state ) => state + 1 )
120123 }
121124 } ) ( )
@@ -124,7 +127,13 @@ export const useAnalysisController = (game: AnalyzedGame) => {
124127 return ( ) => {
125128 stopEvaluation ( )
126129 }
127- } , [ controller . currentNode , game . type , streamEvaluations , stopEvaluation ] )
130+ } , [
131+ controller . currentNode ,
132+ game . type ,
133+ streamEvaluations ,
134+ stopEvaluation ,
135+ currentMaiaModel ,
136+ ] )
128137
129138 const moves = useMemo ( ( ) => {
130139 if ( ! controller . currentNode ) return new Map < string , string [ ] > ( )
@@ -551,6 +560,13 @@ export const useAnalysisController = (game: AnalyzedGame) => {
551560 const cpAdvantage = cp > 0 ? 'White' : cp < 0 ? 'Black' : 'Neither player'
552561 const topStockfishMove = topStockfishMoves [ 0 ]
553562
563+ // Calculate winrate for more nuanced description (using centipawn to approximate winrate)
564+ // Formula approximates winrate from CP value: 1/(1+10^(-cp/400))
565+ const rawWinrate = 1 / ( 1 + Math . pow ( 10 , - cp / 400 ) )
566+ const winrate = Math . max ( 0.01 , Math . min ( 0.99 , rawWinrate ) ) // Clamp between 1% and 99%
567+ const toMoveWinrate = isBlackTurn ? 1 - winrate : winrate
568+ const toMoveAdvantage = toMoveWinrate > 0.5
569+
554570 // Check if top Maia move matches top Stockfish move
555571 const maiaMatchesStockfish = topMaiaMove [ 0 ] === topStockfishMove [ 0 ]
556572
@@ -638,25 +654,49 @@ export const useAnalysisController = (game: AnalyzedGame) => {
638654 let evaluation = ''
639655 let suggestion = ''
640656
641- // Evaluation description
657+ // Evaluation description that considers whose turn it is
642658 if ( isOverwhelming ) {
643- evaluation = `${ cpAdvantage } is completely winning and should convert without difficulty.`
659+ if ( cpAdvantage === playerColor ) {
660+ evaluation = `${ playerColor } has a completely winning position with a ${ Math . round ( toMoveWinrate * 100 ) } % win probability.`
661+ } else {
662+ evaluation = `${ playerColor } faces a nearly lost position with only a ${ Math . round ( toMoveWinrate * 100 ) } % win probability.`
663+ }
644664 } else if ( cp === 0 ) {
645665 evaluation = isBalancedButComplex
646666 ? 'The position is balanced but filled with complications.'
647667 : 'The position is completely equal.'
648668 } else if ( absCP < 30 ) {
649- evaluation = `The evaluation is almost perfectly balanced with only the slightest edge for ${ cpAdvantage } .`
669+ evaluation = `The evaluation is almost perfectly balanced with only the slightest edge ${ cpAdvantage === playerColor ? ' for' : 'against' } ${ playerColor } .`
650670 } else if ( absCP < 80 ) {
651- evaluation = `${ cpAdvantage } has a slight but tangible advantage in this position.`
671+ if ( cpAdvantage === playerColor ) {
672+ evaluation = `${ playerColor } has a slight but tangible advantage with a win probability of ${ Math . round ( toMoveWinrate * 100 ) } %.`
673+ } else {
674+ evaluation = `${ playerColor } faces a slight disadvantage with a win probability of ${ Math . round ( toMoveWinrate * 100 ) } %.`
675+ }
652676 } else if ( absCP < 150 ) {
653- evaluation = `${ cpAdvantage } has a clear positional advantage that could be decisive with careful play.`
677+ if ( cpAdvantage === playerColor ) {
678+ evaluation = `${ playerColor } has a clear positional advantage that could be decisive with careful play.`
679+ } else {
680+ evaluation = `${ playerColor } must play accurately as ${ opponent } holds a clear positional advantage.`
681+ }
654682 } else if ( absCP < 300 ) {
655- evaluation = `${ cpAdvantage } has a significant advantage that should be convertible with proper technique.`
683+ if ( cpAdvantage === playerColor ) {
684+ evaluation = `${ playerColor } has a significant advantage (${ Math . round ( toMoveWinrate * 100 ) } % win rate) that should be convertible with proper technique.`
685+ } else {
686+ evaluation = `${ playerColor } faces a difficult position as ${ opponent } has a significant advantage (${ Math . round ( ( 1 - toMoveWinrate ) * 100 ) } % win rate).`
687+ }
656688 } else if ( absCP < 500 ) {
657- evaluation = `${ cpAdvantage } has a winning position that only requires avoiding major blunders.`
689+ if ( cpAdvantage === playerColor ) {
690+ evaluation = `${ playerColor } is winning and only needs to avoid major blunders to convert.`
691+ } else {
692+ evaluation = `${ playerColor } is in serious trouble and needs to find resilient defensive moves.`
693+ }
658694 } else {
659- evaluation = `${ cpAdvantage } has a completely winning position that should be straightforward to convert.`
695+ if ( cpAdvantage === playerColor ) {
696+ evaluation = `${ playerColor } has a completely winning position with a ${ Math . round ( toMoveWinrate * 100 ) } % win probability.`
697+ } else {
698+ evaluation = `${ playerColor } faces a nearly lost position with only a ${ Math . round ( toMoveWinrate * 100 ) } % win probability.`
699+ }
660700 }
661701
662702 // Suggestion/description of move quality
0 commit comments