Skip to content

Commit

Permalink
fix: stockfish eval orientation + blunder meter in tournament games
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinjosethomas committed Feb 10, 2025
1 parent ef165e4 commit 0ba7dd9
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 99 deletions.
106 changes: 60 additions & 46 deletions src/api/analysis/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,37 +36,6 @@ function buildGameTree(moves: any[], initialFen: string) {
return tree
}

function convertMoveMapToStockfishEval(
moveMap: MoveMap,
moveKey: string,
): StockfishEvaluation {
const cp_vec: { [key: string]: number } = {}
const cp_relative_vec: { [key: string]: number } = {}
let model_optimal_cp = -Infinity
let model_move = ''

for (const move in moveMap) {
cp_vec[move] = moveMap[move]
if (moveMap[move] > model_optimal_cp) {
model_optimal_cp = moveMap[move]
model_move = move
}
}

for (const move in cp_vec) {
cp_relative_vec[move] = model_optimal_cp - cp_vec[move]
}

return {
sent: true,
depth: 20,
model_move: model_move,
model_optimal_cp: model_optimal_cp,
cp_vec: cp_vec,
cp_relative_vec: cp_relative_vec,
}
}

const readStream = (processLine: (data: any) => void) => (response: any) => {
const stream = response.body.getReader()
const matcher = /\r?\n/
Expand Down Expand Up @@ -444,6 +413,49 @@ export const getLegacyAnalyzedUserGame = async (
} as LegacyAnalyzedGame
}

function convertMoveMapToStockfishEval(
moveMap: MoveMap,
turn: 'w' | 'b',
): StockfishEvaluation {
const cp_vec: { [key: string]: number } = {}
const cp_relative_vec: { [key: string]: number } = {}
let model_optimal_cp = -Infinity
let model_move = ''

for (const move in moveMap) {
const cp = moveMap[move]
cp_vec[move] = cp
if (cp > model_optimal_cp) {
model_optimal_cp = cp
model_move = move
}
}

for (const move in cp_vec) {
const cp = moveMap[move]
cp_relative_vec[move] = model_optimal_cp - cp
}

if (turn === 'b') {
model_optimal_cp *= -1
for (const move in cp_vec) {
cp_vec[move] *= -1
}
for (const move in cp_relative_vec) {
cp_relative_vec[move] *= -1
}
}

return {
sent: true,
depth: 20,
model_move: model_move,
model_optimal_cp: model_optimal_cp,
cp_vec: cp_vec,
cp_relative_vec: cp_relative_vec,
}
}

export const getAnalyzedTournamentGame = async (gameId = ['FkgYSri1']) => {
const res = await fetch(
buildUrl(`analysis/analysis_list/${gameId.join('/')}`),
Expand Down Expand Up @@ -514,24 +526,26 @@ export const getAnalyzedTournamentGame = async (gameId = ['FkgYSri1']) => {

const tree = buildGameTree(moves, moves[0].board)

let currentNode = tree.getRoot()
let currentNode: GameNode | null = tree.getRoot()

for (let i = 0; i < moves.length; i++) {
const move = moves[i]
if (!currentNode) {
break
}

if (move.lastMove) {
const [from, to] = move.lastMove
const moveKey = from + to
const stockfishEval = stockfishEvaluations[i]
? convertMoveMapToStockfishEval(stockfishEvaluations[i], moveKey)
: undefined

if (stockfishEval) {
currentNode = currentNode.mainChild as GameNode
if (currentNode) {
currentNode.addStockfishAnalysis(stockfishEval)
}
}
// console.log(currentNode.fen === moves[i].board)

const stockfishEval = stockfishEvaluations[i]
? convertMoveMapToStockfishEval(
stockfishEvaluations[i],
moves[i].board.split(' ')[1],
)
: undefined

if (stockfishEval) {
currentNode.addStockfishAnalysis(stockfishEval)
}
currentNode = currentNode?.mainChild
}

return {
Expand Down
4 changes: 1 addition & 3 deletions src/components/Analysis/Highlight.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { MovesByRating } from './MovesByRating'
import { LegacyBlunderMeter } from './LegacyBlunderMeter'
import { MaiaEvaluation, StockfishEvaluation, ColorSanMapping } from 'src/types'

interface Props {
Expand All @@ -20,7 +19,6 @@ interface Props {
export const Highlight: React.FC<Props> = ({
currentMaiaModel,
recommendations,

moveEvaluation,
colorSanMapping,
movesByRating,
Expand Down Expand Up @@ -51,7 +49,7 @@ export const Highlight: React.FC<Props> = ({
</p>
<p className="text-2xl font-bold text-engine-1">
{moveEvaluation?.stockfish
? `${moveEvaluation.stockfish.model_optimal_cp / 100 > 0 ? '+' : ''}${moveEvaluation.stockfish.model_optimal_cp / 100}`
? `${moveEvaluation.stockfish.model_optimal_cp > 0 ? '+' : ''}${moveEvaluation.stockfish.model_optimal_cp / 100}`
: '...'}
</p>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/Analysis/MoveMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ export const MoveMap: React.FC<Props> = ({
textAnchor="middle"
dx={x < 100 ? 24 : 0}
dy={x < 100 ? 0 : y < 55 ? 24 : -5}
fill={colorSanMapping[value].color || '#fff'}
fill={colorSanMapping[value]?.color ?? '#fff'}
>
{colorSanMapping[value].san}
{colorSanMapping[value]?.san ?? value}
</text>
)
}) as ContentType
Expand All @@ -166,7 +166,7 @@ export const MoveMap: React.FC<Props> = ({
{moveMap?.map((entry, index) => (
<Cell
key={`cell-${entry.move}${index}`}
fill={colorSanMapping[entry.move].color || '#fff'}
fill={colorSanMapping[entry.move]?.color ?? '#fff'}
onMouseEnter={() => onMouseEnter(entry.move)}
onMouseOutCapture={() => {
setHoverArrow(null)
Expand Down
17 changes: 11 additions & 6 deletions src/components/Analysis/MovesByRating.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,10 @@ export const MovesByRating: React.FC<Props> = ({
dataKey={move}
dot={{
r: 3,
stroke: colorSanMapping[move].color,
stroke: colorSanMapping[move]?.color ?? '#fff',
strokeWidth: 3,
}}
stroke={colorSanMapping[move].color}
stroke={colorSanMapping[move]?.color ?? '#fff'}
fill={`url(#color${move})`}
strokeWidth={3}
animationDuration={300}
Expand All @@ -147,7 +147,8 @@ export const MovesByRating: React.FC<Props> = ({
) : null}
</div>
{payload?.map((point) => {
const san = colorSanMapping[point.name as string].san
const san =
colorSanMapping[point.name as string]?.san ?? point.name
const prob = Math.round((point.value as number) * 10) / 10
return (
<div
Expand All @@ -156,15 +157,19 @@ export const MovesByRating: React.FC<Props> = ({
>
<p
style={{
color: colorSanMapping[point.name as string].color,
color:
colorSanMapping[point.name as string]?.color ??
'#fff',
}}
className="text-xs"
>
{san}
</p>
<p
style={{
color: colorSanMapping[point.name as string].color,
color:
colorSanMapping[point.name as string]?.color ??
'#fff',
}}
className="font-mono text-xs"
>
Expand All @@ -183,7 +188,7 @@ export const MovesByRating: React.FC<Props> = ({
wrapperStyle={{ top: -14, right: 20, fontSize: 14 }}
iconSize={0}
formatter={(value) => {
return colorSanMapping[value as string].san
return colorSanMapping[value as string]?.san ?? value
}}
/>
</AreaChart>
Expand Down
70 changes: 31 additions & 39 deletions src/hooks/useAnalysisController/useAnalysisController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,52 +203,44 @@ export const useAnalysisController = (game: AnalyzedGame) => {

const { maia, stockfish } = moveEvaluation

if (game.type === 'tournament') {
if (!maia || !stockfish)
return {
blunderMoves: { probability: 0, moves: [] },
okMoves: { probability: 0, moves: [] },
goodMoves: { probability: 0, moves: [] },
}
} else {
if (!maia || !stockfish)
return {
blunderMoves: { probability: 0, moves: [] },
okMoves: { probability: 0, moves: [] },
goodMoves: { probability: 0, moves: [] },
}
for (const [move, prob] of Object.entries(maia.policy)) {
const loss = stockfish.cp_relative_vec[move]

if (loss === undefined) continue

const probability = prob * 100

if (loss <= 50) {
goodMoveProbability += probability
goodMoveChanceInfo.push({ move, probability })
} else if (loss <= 150) {
okMoveProbability += probability
okMoveChanceInfo.push({ move, probability })
} else {
blunderMoveProbability += probability
blunderMoveChanceInfo.push({ move, probability })
}
for (const [move, prob] of Object.entries(maia.policy)) {
const loss = stockfish.cp_relative_vec[move]

if (loss === undefined) continue

const probability = prob * 100

if (loss <= 50) {
goodMoveProbability += probability
goodMoveChanceInfo.push({ move, probability })
} else if (loss <= 150) {
okMoveProbability += probability
okMoveChanceInfo.push({ move, probability })
} else {
blunderMoveProbability += probability
blunderMoveChanceInfo.push({ move, probability })
}
}

return {
blunderMoves: {
probability: blunderMoveProbability,
moves: blunderMoveChanceInfo,
},
okMoves: {
probability: okMoveProbability,
moves: okMoveChanceInfo,
},
goodMoves: {
probability: goodMoveProbability,
moves: goodMoveChanceInfo,
},
}
return {
blunderMoves: {
probability: blunderMoveProbability,
moves: blunderMoveChanceInfo,
},
okMoves: {
probability: okMoveProbability,
moves: okMoveChanceInfo,
},
goodMoves: {
probability: goodMoveProbability,
moves: goodMoveChanceInfo,
},
}
}, [moveEvaluation])

Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useStockfishEngine/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ class Engine {
}

const board = new Chess(this.fen)
const isWhiteTurn = board.turn() === 'w'
if (!isWhiteTurn) {
const isBlackTurn = board.turn() === 'b'
if (isBlackTurn) {
cp *= -1
}

Expand Down

0 comments on commit 0ba7dd9

Please sign in to comment.