Skip to content

Commit ee6aa64

Browse files
feat: add Stockfish readiness check and retry logic in engine analysis; refactor useAnalysisController and useEngineAnalysis hooks
1 parent 8bb7f6f commit ee6aa64

5 files changed

Lines changed: 72 additions & 23 deletions

File tree

src/hooks/useAnalysisController/useAnalysisController.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export const useAnalysisController = (
3131
downloadModel: downloadMaia,
3232
} = useMaiaEngine()
3333

34-
const { streamEvaluations, stopEvaluation } = useStockfishEngine()
34+
const { streamEvaluations, stopEvaluation, isReady: isStockfishReady } = useStockfishEngine()
3535
const [currentMove, setCurrentMove] = useState<[string, string] | null>()
3636
const [currentMaiaModel, setCurrentMaiaModel] = useLocalStorage(
3737
'currentMaiaModel',
@@ -51,6 +51,7 @@ export const useAnalysisController = (
5151
maia,
5252
streamEvaluations,
5353
stopEvaluation,
54+
isStockfishReady,
5455
currentMaiaModel,
5556
setAnalysisState,
5657
)

src/hooks/useAnalysisController/useEngineAnalysis.ts

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const useEngineAnalysis = (
3131
maia: { batchEvaluate: EngineHooks['maia']['batchEvaluate'] },
3232
streamEvaluations: EngineHooks['streamEvaluations'],
3333
stopEvaluation: EngineHooks['stopEvaluation'],
34+
isStockfishReady: () => boolean,
3435
currentMaiaModel: string,
3536
setAnalysisState: React.Dispatch<React.SetStateAction<number>>,
3637
) => {
@@ -63,15 +64,28 @@ export const useEngineAnalysis = (
6364
const board = new Chess(currentNode.fen)
6465
const nodeFen = currentNode.fen
6566

66-
;(async () => {
67+
const attemptMaiaAnalysis = async () => {
6768
if (
6869
!currentNode ||
69-
maiaStatus !== 'ready' ||
7070
currentNode.analysis.maia ||
7171
inProgressAnalyses.has(nodeFen)
7272
)
7373
return
7474

75+
// Add retry logic for Maia initialization
76+
let retries = 0
77+
const maxRetries = 30 // 3 seconds with 100ms intervals
78+
79+
while (retries < maxRetries && maiaStatus !== 'ready') {
80+
await new Promise(resolve => setTimeout(resolve, 100))
81+
retries++
82+
}
83+
84+
if (maiaStatus !== 'ready') {
85+
console.warn('Maia not ready after waiting, skipping analysis')
86+
return
87+
}
88+
7589
inProgressAnalyses.add(nodeFen)
7690

7791
try {
@@ -110,7 +124,9 @@ export const useEngineAnalysis = (
110124
} finally {
111125
inProgressAnalyses.delete(nodeFen)
112126
}
113-
})()
127+
}
128+
129+
attemptMaiaAnalysis()
114130
}, [
115131
maiaStatus,
116132
currentNode,
@@ -129,31 +145,51 @@ export const useEngineAnalysis = (
129145
)
130146
return
131147

132-
const evaluationStream = streamEvaluations(
133-
board.fen(),
134-
board.moves().length,
135-
)
148+
// Add retry logic for Stockfish initialization
149+
const attemptStockfishAnalysis = async () => {
150+
// Wait up to 3 seconds for Stockfish to be ready
151+
let retries = 0
152+
const maxRetries = 30 // 3 seconds with 100ms intervals
153+
154+
while (retries < maxRetries && !isStockfishReady()) {
155+
await new Promise(resolve => setTimeout(resolve, 100))
156+
retries++
157+
}
158+
159+
if (!isStockfishReady()) {
160+
console.warn('Stockfish not ready after waiting, skipping analysis')
161+
return
162+
}
163+
164+
const evaluationStream = streamEvaluations(
165+
board.fen(),
166+
board.moves().length,
167+
)
136168

137-
if (evaluationStream) {
138-
;(async () => {
139-
for await (const evaluation of evaluationStream) {
140-
if (!currentNode) {
141-
stopEvaluation()
142-
break
169+
if (evaluationStream) {
170+
;(async () => {
171+
for await (const evaluation of evaluationStream) {
172+
if (!currentNode) {
173+
stopEvaluation()
174+
break
175+
}
176+
currentNode.addStockfishAnalysis(evaluation, currentMaiaModel)
177+
setAnalysisState((state) => state + 1)
143178
}
144-
currentNode.addStockfishAnalysis(evaluation, currentMaiaModel)
145-
setAnalysisState((state) => state + 1)
146-
}
147-
})()
179+
})()
180+
}
148181
}
149182

183+
attemptStockfishAnalysis()
184+
150185
return () => {
151186
stopEvaluation()
152187
}
153188
}, [
154189
currentNode,
155190
streamEvaluations,
156191
stopEvaluation,
192+
isStockfishReady,
157193
currentMaiaModel,
158194
setAnalysisState,
159195
])

src/hooks/useStockfishEngine/engine.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class Engine {
99
private moves: string[]
1010
private isEvaluating: boolean
1111
private stockfish: StockfishWeb | null = null
12+
private isReady: boolean = false
1213

1314
private store: {
1415
[key: string]: StockfishEvaluation
@@ -40,14 +41,22 @@ class Engine {
4041
stockfish.uci('setoption name MultiPV value 100')
4142
stockfish.onError = this.onError
4243
stockfish.listen = this.onMessage
44+
this.isReady = true
45+
}).catch((error) => {
46+
console.error('Failed to initialize Stockfish:', error)
47+
this.isReady = false
4348
})
4449
}
4550

51+
get ready(): boolean {
52+
return this.isReady && this.stockfish !== null
53+
}
54+
4655
async *streamEvaluations(
4756
fen: string,
4857
legalMoveCount: number,
4958
): AsyncGenerator<StockfishEvaluation> {
50-
if (this.stockfish) {
59+
if (this.stockfish && this.isReady) {
5160
if (typeof global.gc === 'function') {
5261
global.gc()
5362
}

src/hooks/useStockfishEngine/useStockfishEngine.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@ export const useStockfishEngine = () => {
2323
engineRef.current?.stopEvaluation()
2424
}, [])
2525

26+
const isReady = useCallback(() => {
27+
return engineRef.current?.ready ?? false
28+
}, [])
29+
2630
return useMemo(
2731
() => ({
2832
streamEvaluations,
2933
stopEvaluation,
34+
isReady,
3035
}),
31-
[streamEvaluations, stopEvaluation],
36+
[streamEvaluations, stopEvaluation, isReady],
3237
)
3338
}

src/pages/train.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -944,9 +944,7 @@ const Train: React.FC<Props> = ({
944944
<span className="material-symbols-outlined mb-2 text-3xl text-human-3">
945945
lock
946946
</span>
947-
<p className="font-medium text-primary">
948-
Analysis Locked
949-
</p>
947+
<p className="font-medium text-primary">Analysis Locked</p>
950948
<p className="text-sm text-secondary">
951949
Complete the puzzle to unlock analysis
952950
</p>

0 commit comments

Comments
 (0)