Skip to content

Commit 2de7b68

Browse files
feat: set colours based on winrate loss instead of cp loss
1 parent 59c180b commit 2de7b68

File tree

1 file changed

+117
-38
lines changed

1 file changed

+117
-38
lines changed

src/hooks/useAnalysisController/useAnalysisController.ts

Lines changed: 117 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,30 @@ export const useAnalysisController = (game: AnalyzedGame) => {
155155
const moves = chess.moves({ verbose: true })
156156
const stockfish = controller.currentNode.analysis.stockfish
157157

158+
// Define thresholds for winrate loss
159+
const GOOD_THRESHOLD = -INACCURACY_THRESHOLD // -0.05 (less than 5% winrate loss)
160+
const OK_THRESHOLD = -BLUNDER_THRESHOLD // -0.1 (between 5% and 10% winrate loss)
161+
// Anything worse than -0.1 is a blunder
162+
158163
moves.forEach((m) => {
159164
const moveKey = `${m.from}${m.to}`
165+
// Use winrate_loss_vec if available, otherwise fall back to cp_relative_vec
166+
const winrateLoss = stockfish?.winrate_loss_vec?.[moveKey]
160167
const relativeEval = stockfish?.cp_relative_vec[moveKey]
161168

162169
let color = '#FFF'
163170

164-
if (relativeEval !== undefined) {
171+
if (winrateLoss !== undefined) {
172+
// Use winrate loss for coloring
173+
if (winrateLoss >= GOOD_THRESHOLD) {
174+
color = COLORS.good[0]
175+
} else if (winrateLoss >= OK_THRESHOLD) {
176+
color = COLORS.ok[0]
177+
} else {
178+
color = COLORS.blunder[0]
179+
}
180+
} else if (relativeEval !== undefined) {
181+
// Fall back to CP-based coloring if winrate is not available
165182
if (relativeEval >= -50) {
166183
color = COLORS.good[0]
167184
} else if (relativeEval >= -150) {
@@ -178,43 +195,105 @@ export const useAnalysisController = (game: AnalyzedGame) => {
178195
})
179196

180197
if (stockfish) {
181-
const goodMoves = moves
182-
.map((m) => `${m.from}${m.to}`)
183-
.filter((move) => stockfish.cp_relative_vec[move] >= -50)
184-
.sort(
185-
(a, b) => stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
186-
)
187-
188-
const okMoves = moves
189-
.map((m) => `${m.from}${m.to}`)
190-
.filter(
191-
(move) =>
192-
stockfish.cp_relative_vec[move] >= -150 &&
193-
stockfish.cp_relative_vec[move] < -50,
194-
)
195-
.sort(
196-
(a, b) => stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
197-
)
198-
199-
const blunderMoves = moves
200-
.map((m) => `${m.from}${m.to}`)
201-
.filter((move) => stockfish.cp_relative_vec[move] < -150)
202-
.sort(
203-
(a, b) => stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
204-
)
205-
206-
goodMoves.forEach((move, i) => {
207-
mapping[move].color = COLORS.good[Math.min(i, COLORS.good.length - 1)]
208-
})
209-
210-
okMoves.forEach((move, i) => {
211-
mapping[move].color = COLORS.ok[Math.min(i, COLORS.ok.length - 1)]
212-
})
213-
214-
blunderMoves.forEach((move, i) => {
215-
mapping[move].color =
216-
COLORS.blunder[Math.min(i, COLORS.blunder.length - 1)]
217-
})
198+
if (
199+
stockfish.winrate_loss_vec &&
200+
Object.keys(stockfish.winrate_loss_vec).length > 0
201+
) {
202+
const goodMoves = moves
203+
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
204+
.filter((move) => {
205+
const winrateLoss = stockfish.winrate_loss_vec?.[move]
206+
return winrateLoss !== undefined && winrateLoss >= GOOD_THRESHOLD
207+
})
208+
.sort((a, b) => {
209+
const aLoss = stockfish.winrate_loss_vec?.[a] || 0
210+
const bLoss = stockfish.winrate_loss_vec?.[b] || 0
211+
return bLoss - aLoss
212+
})
213+
214+
const okMoves = moves
215+
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
216+
.filter((move) => {
217+
const winrateLoss = stockfish.winrate_loss_vec?.[move]
218+
return (
219+
winrateLoss !== undefined &&
220+
winrateLoss >= OK_THRESHOLD &&
221+
winrateLoss < GOOD_THRESHOLD
222+
)
223+
})
224+
.sort((a, b) => {
225+
const aLoss = stockfish.winrate_loss_vec?.[a] || 0
226+
const bLoss = stockfish.winrate_loss_vec?.[b] || 0
227+
return bLoss - aLoss
228+
})
229+
230+
const blunderMoves = moves
231+
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
232+
.filter((move) => {
233+
const winrateLoss = stockfish.winrate_loss_vec?.[move]
234+
return winrateLoss !== undefined && winrateLoss < OK_THRESHOLD
235+
})
236+
.sort((a, b) => {
237+
const aLoss = stockfish.winrate_loss_vec?.[a] || 0
238+
const bLoss = stockfish.winrate_loss_vec?.[b] || 0
239+
return bLoss - aLoss
240+
})
241+
242+
goodMoves.forEach((move, i) => {
243+
mapping[move].color = COLORS.good[Math.min(i, COLORS.good.length - 1)]
244+
})
245+
246+
okMoves.forEach((move, i) => {
247+
mapping[move].color = COLORS.ok[Math.min(i, COLORS.ok.length - 1)]
248+
})
249+
250+
blunderMoves.forEach((move, i) => {
251+
mapping[move].color =
252+
COLORS.blunder[Math.min(i, COLORS.blunder.length - 1)]
253+
})
254+
} else {
255+
// Fall back to CP-based coloring if winrate is not available
256+
const goodMoves = moves
257+
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
258+
.filter((move) => stockfish.cp_relative_vec[move] >= -50)
259+
.sort(
260+
(a, b) =>
261+
stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
262+
)
263+
264+
const okMoves = moves
265+
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
266+
.filter(
267+
(move) =>
268+
stockfish.cp_relative_vec[move] >= -150 &&
269+
stockfish.cp_relative_vec[move] < -50,
270+
)
271+
.sort(
272+
(a, b) =>
273+
stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
274+
)
275+
276+
const blunderMoves = moves
277+
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
278+
.filter((move) => stockfish.cp_relative_vec[move] < -150)
279+
.sort(
280+
(a, b) =>
281+
stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
282+
)
283+
284+
goodMoves.forEach((move, i) => {
285+
mapping[move].color = COLORS.good[Math.min(i, COLORS.good.length - 1)]
286+
})
287+
288+
okMoves.forEach((move, i) => {
289+
mapping[move].color = COLORS.ok[Math.min(i, COLORS.ok.length - 1)]
290+
})
291+
292+
blunderMoves.forEach((move, i) => {
293+
mapping[move].color =
294+
COLORS.blunder[Math.min(i, COLORS.blunder.length - 1)]
295+
})
296+
}
218297
}
219298

220299
return mapping

0 commit comments

Comments
 (0)