@@ -14,6 +14,51 @@ type ColorSanMappingResult = {
1414 }
1515}
1616
17+ const getStockfishMoveOrderingScore = (
18+ stockfish : StockfishEvaluation ,
19+ move : string ,
20+ ) : number => {
21+ const winrateLoss = stockfish . winrate_loss_vec ?. [ move ]
22+ if ( winrateLoss !== undefined ) {
23+ return winrateLoss
24+ }
25+
26+ const relativeEval = stockfish . cp_relative_vec ?. [ move ]
27+ if ( relativeEval !== undefined ) {
28+ return relativeEval
29+ }
30+
31+ const cp = stockfish . cp_vec ?. [ move ]
32+ if ( cp !== undefined ) {
33+ return cp
34+ }
35+
36+ return Number . NEGATIVE_INFINITY
37+ }
38+
39+ export const sortStockfishMoves = (
40+ stockfish : StockfishEvaluation ,
41+ moves : string [ ] ,
42+ ) : string [ ] =>
43+ [ ...moves ] . sort ( ( a , b ) => {
44+ const scoreDiff =
45+ getStockfishMoveOrderingScore ( stockfish , b ) -
46+ getStockfishMoveOrderingScore ( stockfish , a )
47+
48+ if ( scoreDiff !== 0 ) {
49+ return scoreDiff
50+ }
51+
52+ const cpDiff =
53+ ( stockfish . cp_vec ?. [ b ] ?? Number . NEGATIVE_INFINITY ) -
54+ ( stockfish . cp_vec ?. [ a ] ?? Number . NEGATIVE_INFINITY )
55+ if ( cpDiff !== 0 ) {
56+ return cpDiff
57+ }
58+
59+ return a . localeCompare ( b )
60+ } )
61+
1762// Unified function to calculate color for a single move
1863export const calculateMoveColor = (
1964 stockfish : StockfishEvaluation | undefined ,
@@ -56,6 +101,7 @@ export const generateColorSanMapping = (
56101
57102 const chess = new Chess ( fen )
58103 const moves = chess . moves ( { verbose : true } )
104+ const moveKeys = moves . map ( ( m ) => `${ m . from } ${ m . to } ${ m . promotion || '' } ` )
59105 moves . forEach ( ( m ) => {
60106 const moveKey = `${ m . from } ${ m . to } ${ m . promotion || '' } `
61107 mapping [ moveKey ] = {
@@ -81,51 +127,37 @@ export const generateColorSanMapping = (
81127 stockfish . winrate_loss_vec &&
82128 Object . keys ( stockfish . winrate_loss_vec ) . length > 0
83129 ) {
84- const goodMoves = moves
85- . map ( ( m ) => ` ${ m . from } ${ m . to } ${ m . promotion || '' } ` )
86- . filter ( ( move ) => {
130+ const goodMoves = sortStockfishMoves (
131+ stockfish ,
132+ moveKeys . filter ( ( move ) => {
87133 const winrateLoss = stockfish . winrate_loss_vec ?. [ move ]
88134 return (
89135 winrateLoss !== undefined &&
90136 winrateLoss >= - MOVE_CLASSIFICATION_THRESHOLDS . INACCURACY_THRESHOLD
91137 )
92- } )
93- . sort ( ( a , b ) => {
94- const aLoss = stockfish . winrate_loss_vec ?. [ a ] || 0
95- const bLoss = stockfish . winrate_loss_vec ?. [ b ] || 0
96- return bLoss - aLoss
97- } )
98-
99- const okMoves = moves
100- . map ( ( m ) => `${ m . from } ${ m . to } ${ m . promotion || '' } ` )
101- . filter ( ( move ) => {
138+ } ) ,
139+ )
140+ const okMoves = sortStockfishMoves (
141+ stockfish ,
142+ moveKeys . filter ( ( move ) => {
102143 const winrateLoss = stockfish . winrate_loss_vec ?. [ move ]
103144 return (
104145 winrateLoss !== undefined &&
105146 winrateLoss >= - MOVE_CLASSIFICATION_THRESHOLDS . BLUNDER_THRESHOLD &&
106147 winrateLoss < - MOVE_CLASSIFICATION_THRESHOLDS . INACCURACY_THRESHOLD
107148 )
108- } )
109- . sort ( ( a , b ) => {
110- const aLoss = stockfish . winrate_loss_vec ?. [ a ] || 0
111- const bLoss = stockfish . winrate_loss_vec ?. [ b ] || 0
112- return bLoss - aLoss
113- } )
114-
115- const blunderMoves = moves
116- . map ( ( m ) => `${ m . from } ${ m . to } ${ m . promotion || '' } ` )
117- . filter ( ( move ) => {
149+ } ) ,
150+ )
151+ const blunderMoves = sortStockfishMoves (
152+ stockfish ,
153+ moveKeys . filter ( ( move ) => {
118154 const winrateLoss = stockfish . winrate_loss_vec ?. [ move ]
119155 return (
120156 winrateLoss !== undefined &&
121157 winrateLoss < - MOVE_CLASSIFICATION_THRESHOLDS . BLUNDER_THRESHOLD
122158 )
123- } )
124- . sort ( ( a , b ) => {
125- const aLoss = stockfish . winrate_loss_vec ?. [ a ] || 0
126- const bLoss = stockfish . winrate_loss_vec ?. [ b ] || 0
127- return bLoss - aLoss
128- } )
159+ } ) ,
160+ )
129161
130162 goodMoves . forEach ( ( move , i ) => {
131163 mapping [ move ] . color = COLORS . good [ Math . min ( i , COLORS . good . length - 1 ) ]
@@ -140,30 +172,23 @@ export const generateColorSanMapping = (
140172 COLORS . blunder [ Math . min ( i , COLORS . blunder . length - 1 ) ]
141173 } )
142174 } else {
143- const goodMoves = moves
144- . map ( ( m ) => `${ m . from } ${ m . to } ${ m . promotion || '' } ` )
145- . filter ( ( move ) => stockfish . cp_relative_vec [ move ] >= - 50 )
146- . sort (
147- ( a , b ) => stockfish . cp_relative_vec [ b ] - stockfish . cp_relative_vec [ a ] ,
148- )
149-
150- const okMoves = moves
151- . map ( ( m ) => `${ m . from } ${ m . to } ${ m . promotion || '' } ` )
152- . filter (
153- ( move ) =>
175+ const goodMoves = sortStockfishMoves (
176+ stockfish ,
177+ moveKeys . filter ( ( move ) => stockfish . cp_relative_vec [ move ] >= - 50 ) ,
178+ )
179+ const okMoves = sortStockfishMoves (
180+ stockfish ,
181+ moveKeys . filter ( ( move ) => {
182+ return (
154183 stockfish . cp_relative_vec [ move ] >= - 150 &&
155- stockfish . cp_relative_vec [ move ] < - 50 ,
156- )
157- . sort (
158- ( a , b ) => stockfish . cp_relative_vec [ b ] - stockfish . cp_relative_vec [ a ] ,
159- )
160-
161- const blunderMoves = moves
162- . map ( ( m ) => `${ m . from } ${ m . to } ${ m . promotion || '' } ` )
163- . filter ( ( move ) => stockfish . cp_relative_vec [ move ] < - 150 )
164- . sort (
165- ( a , b ) => stockfish . cp_relative_vec [ b ] - stockfish . cp_relative_vec [ a ] ,
166- )
184+ stockfish . cp_relative_vec [ move ] < - 50
185+ )
186+ } ) ,
187+ )
188+ const blunderMoves = sortStockfishMoves (
189+ stockfish ,
190+ moveKeys . filter ( ( move ) => stockfish . cp_relative_vec [ move ] < - 150 ) ,
191+ )
167192
168193 goodMoves . forEach ( ( move , i ) => {
169194 mapping [ move ] . color = COLORS . good [ Math . min ( i , COLORS . good . length - 1 ) ]
0 commit comments