Skip to content

Commit e16b396

Browse files
feat: migrate train page to tree structure + handle all cases
1 parent 45507d3 commit e16b396

7 files changed

Lines changed: 143 additions & 389 deletions

File tree

src/components/Board/GameBoard.tsx

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,8 @@ interface Props {
1313
currentNode: GameNode
1414
orientation?: Color
1515
availableMoves?: Map<string, string[]>
16-
move?: {
17-
fen: string
18-
move: [string, string]
19-
check?: Check
20-
}
21-
onPlayerMakeMove?: (move: [string, string] | null) => void
16+
onSelectSquare?: (square: Key) => void
17+
onPlayerMakeMove?: (move: [string, string]) => void
2218
setCurrentSquare?: Dispatch<SetStateAction<Key | null>>
2319
shapes?: DrawShape[]
2420
brushes?: DrawBrushes
@@ -28,16 +24,16 @@ interface Props {
2824

2925
export const GameBoard: React.FC<Props> = ({
3026
game,
27+
shapes,
28+
brushes,
29+
goToNode,
30+
gameTree,
3131
currentNode,
3232
orientation = 'white',
3333
availableMoves,
34-
move,
3534
onPlayerMakeMove,
3635
setCurrentSquare,
37-
shapes,
38-
brushes,
39-
goToNode,
40-
gameTree,
36+
onSelectSquare,
4137
}: Props) => {
4238
const { playSound } = useChessSound()
4339

@@ -89,7 +85,6 @@ export const GameBoard: React.FC<Props> = ({
8985
}
9086
},
9187
[
92-
move,
9388
game,
9489
gameTree,
9590
goToNode,
@@ -100,29 +95,23 @@ export const GameBoard: React.FC<Props> = ({
10095
],
10196
)
10297

103-
// Determine board configuration
10498
const boardConfig = useMemo(() => {
105-
// For training: prioritize move result over currentNode when a move is made
106-
const fen = move ? move.fen : currentNode.fen
107-
108-
const lastMove = move
109-
? move.move
110-
: currentNode.move
111-
? ([currentNode.move.slice(0, 2), currentNode.move.slice(2, 4)] as [
112-
Key,
113-
Key,
114-
])
115-
: []
99+
const fen = currentNode.fen
116100

117-
const check = move ? move.check : currentNode.check
101+
const lastMove = currentNode.move
102+
? ([currentNode.move.slice(0, 2), currentNode.move.slice(2, 4)] as [
103+
Key,
104+
Key,
105+
])
106+
: []
118107

119108
return {
120109
fen,
121110
lastMove,
122-
check,
111+
check: currentNode.check,
123112
orientation: orientation as 'white' | 'black',
124113
}
125-
}, [move, currentNode, game, orientation])
114+
}, [currentNode, game, orientation])
126115

127116
return (
128117
<Chessground
@@ -137,7 +126,7 @@ export const GameBoard: React.FC<Props> = ({
137126
},
138127
events: {
139128
select: (key) => {
140-
onPlayerMakeMove && onPlayerMakeMove(null)
129+
onSelectSquare && onSelectSquare(key)
141130
setCurrentSquare && setCurrentSquare(key)
142131
},
143132
},

src/components/Training/Feedback.tsx

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,26 @@ import { Chess } from 'chess.ts'
22
import { useMemo, Dispatch, SetStateAction, useCallback } from 'react'
33

44
import { Markdown } from 'src/components'
5-
import { useTrainingTreeController } from 'src/hooks'
5+
import { useTrainingController } from 'src/hooks'
66
import { TrainingGame, Status } from 'src/types/training'
77

88
interface Props {
9-
latestGuess: string | null
10-
trainingController: ReturnType<typeof useTrainingTreeController>
9+
status: string
1110
game: TrainingGame
1211
setAndGiveUp: () => void
13-
status: string
14-
setStatus: Dispatch<SetStateAction<Status>>
1512
getNewGame: () => Promise<void>
13+
setStatus: Dispatch<SetStateAction<Status>>
14+
controller: ReturnType<typeof useTrainingController>
1615
}
1716

1817
export const Feedback: React.FC<Props> = ({
1918
game,
2019
status,
2120
setStatus,
2221
getNewGame,
23-
latestGuess,
2422
setAndGiveUp,
25-
trainingController,
23+
controller: controller,
2624
}: Props) => {
27-
const { controller, move, currentMove, setCurrentMove, moveEvaluation } =
28-
trainingController
29-
const { currentIndex, setCurrentIndex } = controller
3025
const { targetIndex } = game
3126

3227
const turn =
@@ -42,12 +37,12 @@ export const Feedback: React.FC<Props> = ({
4237
Find the best move for **${turn}**!
4338
`
4439
const incorrectContent = `
45-
##### ${latestGuess} is incorrect
40+
##### ${controller.currentNode.san} is incorrect
4641
Try again or give up to see the best move.
4742
`
4843

4944
const correctContent = `
50-
##### Correct! ${latestGuess} is the best move.
45+
##### Correct! ${controller.currentNode.san} is the best move.
5146
You can now explore the position.
5247
`
5348

@@ -67,22 +62,7 @@ export const Feedback: React.FC<Props> = ({
6762
} else {
6863
return defaultContent
6964
}
70-
}, [
71-
currentIndex,
72-
currentMove,
73-
defaultContent,
74-
move,
75-
incorrectContent,
76-
moveEvaluation,
77-
correctContent,
78-
status,
79-
targetIndex,
80-
])
81-
82-
const moveToTarget = useCallback(() => {
83-
setCurrentMove(null)
84-
setCurrentIndex(game.targetIndex)
85-
}, [game.targetIndex, setCurrentIndex])
65+
}, [defaultContent, incorrectContent, correctContent, status, targetIndex])
8666

8767
return (
8868
<div className="flex w-screen flex-1 flex-col justify-between gap-2 rounded-sm bg-background-1 p-3 md:w-auto md:gap-0 md:p-5">
@@ -92,11 +72,11 @@ export const Feedback: React.FC<Props> = ({
9272
<div className="flex flex-col gap-1.5">
9373
{status !== 'archived' && (
9474
<>
95-
{status === 'incorrect' && currentMove && (
75+
{status === 'incorrect' && (
9676
<button
9777
onClick={() => {
9878
setStatus('default')
99-
setCurrentMove(null)
79+
controller.reset()
10080
}}
10181
className="flex w-full justify-center rounded-sm bg-engine-3 py-1.5 text-sm font-medium text-primary transition duration-300 hover:bg-engine-4 disabled:bg-backdrop disabled:text-secondary"
10282
>
@@ -105,8 +85,8 @@ export const Feedback: React.FC<Props> = ({
10585
)}
10686
{status !== 'correct' && status !== 'incorrect' && (
10787
<button
108-
onClick={moveToTarget}
109-
disabled={status == 'loading' || !currentMove}
88+
onClick={() => controller.reset()}
89+
disabled={status == 'loading'}
11090
className="flex w-full justify-center rounded-sm bg-engine-3 py-1.5 text-sm font-medium text-primary transition duration-300 hover:bg-engine-4 disabled:bg-backdrop disabled:text-secondary"
11191
>
11292
Reset
@@ -123,7 +103,6 @@ export const Feedback: React.FC<Props> = ({
123103
{(status === 'forfeit' || status === 'correct') && (
124104
<button
125105
onClick={async () => {
126-
setCurrentMove(null)
127106
await getNewGame()
128107
}}
129108
className="flex w-full justify-center rounded-sm bg-human-3 py-1.5 text-sm font-medium text-primary transition duration-300 hover:bg-human-4 disabled:bg-backdrop disabled:text-secondary"

src/contexts/TrainingControllerContext/TrainingControllerContext.ts

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
1-
import { createContext } from 'react'
21
import { Chess } from 'chess.ts'
3-
import type { Key } from 'chessground/types'
2+
import { createContext } from 'react'
43
import { GameTree, GameNode } from 'src/types'
54
import { BaseTreeControllerContext } from '../BaseTreeControllerContext'
65

76
export interface ITrainingControllerContext extends BaseTreeControllerContext {
87
currentNode: GameNode
9-
setCurrentIndex: (indexOrUpdater: number | ((prev: number) => number)) => void
10-
118
moves?: Map<string, string[]>
12-
currentMove: [string, string] | null
13-
setCurrentMove: (move: [string, string] | null) => void
14-
currentSquare: Key | null
15-
setCurrentSquare: (square: Key | null) => void
16-
moveEvaluation: { maia: number; stockfish: number } | null
17-
data: any[]
18-
move?: any
19-
parseMove: (move: string[]) => any
209
}
2110

2211
const defaultContext: ITrainingControllerContext = {
@@ -34,28 +23,12 @@ const defaultContext: ITrainingControllerContext = {
3423
goToRootNode: () => {
3524
/* no-op */
3625
},
37-
currentIndex: 0,
38-
setCurrentIndex: () => {
39-
/* no-op */
40-
},
4126
plyCount: 0,
4227
orientation: 'white',
4328
setOrientation: () => {
4429
/* no-op */
4530
},
4631
moves: undefined,
47-
currentMove: null,
48-
setCurrentMove: () => {
49-
/* no-op */
50-
},
51-
currentSquare: null,
52-
setCurrentSquare: () => {
53-
/* no-op */
54-
},
55-
moveEvaluation: null,
56-
data: [],
57-
move: undefined,
58-
parseMove: () => undefined,
5932
}
6033

6134
export const TrainingControllerContext =

0 commit comments

Comments
 (0)