Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/hooks/useAnalysisController/useAnalysisController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,12 @@ export const useAnalysisController = (
}

if (moveEvaluation?.stockfish) {
const bestMove = Object.entries(moveEvaluation.stockfish.cp_vec)[0]
const bestMove = moveEvaluation.stockfish.model_move
if (bestMove) {
arrows.push({
brush: 'blue',
orig: bestMove[0].slice(0, 2) as Key,
dest: bestMove[0].slice(2, 4) as Key,
orig: bestMove.slice(0, 2) as Key,
dest: bestMove.slice(2, 4) as Key,
modifiers: { lineWidth: 8 },
} as DrawShape)
}
Expand Down
15 changes: 12 additions & 3 deletions src/hooks/useAnalysisController/useMoveRecommendations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useMemo } from 'react'
import { Chess } from 'chess.ts'
import { MAIA_MODELS } from 'src/constants/common'
import { GameNode, MaiaEvaluation, StockfishEvaluation } from 'src/types'
import { sortStockfishMoves } from './utils'

export const useMoveRecommendations = (
currentNode: GameNode | null,
Expand All @@ -23,6 +24,7 @@ export const useMoveRecommendations = (
cp: number
winrate?: number
winrate_loss?: number
cp_relative?: number
}[]
isBlackTurn?: boolean
} = {
Expand All @@ -44,10 +46,14 @@ export const useMoveRecommendations = (
const cp_relative_vec = moveEvaluation.stockfish.cp_relative_vec || {}
const winrate_vec = moveEvaluation.stockfish.winrate_vec || {}
const winrate_loss_vec = moveEvaluation.stockfish.winrate_loss_vec || {}
const sortedMoves = sortStockfishMoves(
moveEvaluation.stockfish,
Object.keys(cp_vec),
)

const stockfish = Object.entries(cp_vec).map(([move, cp]) => ({
const stockfish = sortedMoves.map((move) => ({
move,
cp,
cp: cp_vec[move] || 0,
winrate: winrate_vec[move] || 0,
winrate_loss: winrate_loss_vec[move] || 0,
cp_relative: cp_relative_vec[move] || 0,
Expand Down Expand Up @@ -80,7 +86,10 @@ export const useMoveRecommendations = (

// Get top 3 Stockfish moves
if (stockfish) {
for (const move of Object.keys(stockfish.cp_vec).slice(0, 3)) {
for (const move of sortStockfishMoves(
stockfish,
Object.keys(stockfish.cp_vec),
).slice(0, 3)) {
if (candidates.find((c) => c[0] === move)) continue
candidates.push([move, move])
}
Expand Down
129 changes: 77 additions & 52 deletions src/hooks/useAnalysisController/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,51 @@ type ColorSanMappingResult = {
}
}

const getStockfishMoveOrderingScore = (
stockfish: StockfishEvaluation,
move: string,
): number => {
const winrateLoss = stockfish.winrate_loss_vec?.[move]
if (winrateLoss !== undefined) {
return winrateLoss
}

const relativeEval = stockfish.cp_relative_vec?.[move]
if (relativeEval !== undefined) {
return relativeEval
}

const cp = stockfish.cp_vec?.[move]
if (cp !== undefined) {
return cp
}

return Number.NEGATIVE_INFINITY
}

export const sortStockfishMoves = (
stockfish: StockfishEvaluation,
moves: string[],
): string[] =>
[...moves].sort((a, b) => {
const scoreDiff =
getStockfishMoveOrderingScore(stockfish, b) -
getStockfishMoveOrderingScore(stockfish, a)

if (scoreDiff !== 0) {
return scoreDiff
}

const cpDiff =
(stockfish.cp_vec?.[b] ?? Number.NEGATIVE_INFINITY) -
(stockfish.cp_vec?.[a] ?? Number.NEGATIVE_INFINITY)
if (cpDiff !== 0) {
return cpDiff
}

return a.localeCompare(b)
})

// Unified function to calculate color for a single move
export const calculateMoveColor = (
stockfish: StockfishEvaluation | undefined,
Expand Down Expand Up @@ -56,6 +101,7 @@ export const generateColorSanMapping = (

const chess = new Chess(fen)
const moves = chess.moves({ verbose: true })
const moveKeys = moves.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
moves.forEach((m) => {
const moveKey = `${m.from}${m.to}${m.promotion || ''}`
mapping[moveKey] = {
Expand All @@ -81,51 +127,37 @@ export const generateColorSanMapping = (
stockfish.winrate_loss_vec &&
Object.keys(stockfish.winrate_loss_vec).length > 0
) {
const goodMoves = moves
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
.filter((move) => {
const goodMoves = sortStockfishMoves(
stockfish,
moveKeys.filter((move) => {
const winrateLoss = stockfish.winrate_loss_vec?.[move]
return (
winrateLoss !== undefined &&
winrateLoss >= -MOVE_CLASSIFICATION_THRESHOLDS.INACCURACY_THRESHOLD
)
})
.sort((a, b) => {
const aLoss = stockfish.winrate_loss_vec?.[a] || 0
const bLoss = stockfish.winrate_loss_vec?.[b] || 0
return bLoss - aLoss
})

const okMoves = moves
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
.filter((move) => {
}),
)
const okMoves = sortStockfishMoves(
stockfish,
moveKeys.filter((move) => {
const winrateLoss = stockfish.winrate_loss_vec?.[move]
return (
winrateLoss !== undefined &&
winrateLoss >= -MOVE_CLASSIFICATION_THRESHOLDS.BLUNDER_THRESHOLD &&
winrateLoss < -MOVE_CLASSIFICATION_THRESHOLDS.INACCURACY_THRESHOLD
)
})
.sort((a, b) => {
const aLoss = stockfish.winrate_loss_vec?.[a] || 0
const bLoss = stockfish.winrate_loss_vec?.[b] || 0
return bLoss - aLoss
})

const blunderMoves = moves
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
.filter((move) => {
}),
)
const blunderMoves = sortStockfishMoves(
stockfish,
moveKeys.filter((move) => {
const winrateLoss = stockfish.winrate_loss_vec?.[move]
return (
winrateLoss !== undefined &&
winrateLoss < -MOVE_CLASSIFICATION_THRESHOLDS.BLUNDER_THRESHOLD
)
})
.sort((a, b) => {
const aLoss = stockfish.winrate_loss_vec?.[a] || 0
const bLoss = stockfish.winrate_loss_vec?.[b] || 0
return bLoss - aLoss
})
}),
)

goodMoves.forEach((move, i) => {
mapping[move].color = COLORS.good[Math.min(i, COLORS.good.length - 1)]
Expand All @@ -140,30 +172,23 @@ export const generateColorSanMapping = (
COLORS.blunder[Math.min(i, COLORS.blunder.length - 1)]
})
} else {
const goodMoves = moves
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
.filter((move) => stockfish.cp_relative_vec[move] >= -50)
.sort(
(a, b) => stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
)

const okMoves = moves
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
.filter(
(move) =>
const goodMoves = sortStockfishMoves(
stockfish,
moveKeys.filter((move) => stockfish.cp_relative_vec[move] >= -50),
)
const okMoves = sortStockfishMoves(
stockfish,
moveKeys.filter((move) => {
return (
stockfish.cp_relative_vec[move] >= -150 &&
stockfish.cp_relative_vec[move] < -50,
)
.sort(
(a, b) => stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
)

const blunderMoves = moves
.map((m) => `${m.from}${m.to}${m.promotion || ''}`)
.filter((move) => stockfish.cp_relative_vec[move] < -150)
.sort(
(a, b) => stockfish.cp_relative_vec[b] - stockfish.cp_relative_vec[a],
)
stockfish.cp_relative_vec[move] < -50
)
}),
)
const blunderMoves = sortStockfishMoves(
stockfish,
moveKeys.filter((move) => stockfish.cp_relative_vec[move] < -150),
)

goodMoves.forEach((move, i) => {
mapping[move].color = COLORS.good[Math.min(i, COLORS.good.length - 1)]
Expand Down
Loading