Skip to content

Commit 688da4a

Browse files
feat: migrate turing to use tree data structure
1 parent 08120de commit 688da4a

13 files changed

Lines changed: 715 additions & 24 deletions

File tree

src/api/turing/turing.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Color, TuringGame, TuringSubmissionResult } from 'src/types'
1+
import { Chess } from 'chess.ts'
2+
import { Color, TuringGame, TuringSubmissionResult, GameTree } from 'src/types'
23
import { buildUrl } from 'src/api'
34

45
export const getTuringGame = async () => {
@@ -30,16 +31,34 @@ export const getTuringGame = async () => {
3031
board: fen,
3132
lastMove,
3233
san,
34+
uci: lastMove ? lastMove.join('') : undefined,
3335
check,
3436
}
3537
},
3638
)
3739

40+
// Build game tree from moves
41+
const gameTree = new GameTree(moves[0].board)
42+
let currentNode = gameTree.getRoot()
43+
44+
for (let i = 1; i < moves.length; i++) {
45+
const move = moves[i]
46+
if (move.uci && move.san) {
47+
currentNode = gameTree.addMainMove(
48+
currentNode,
49+
move.board,
50+
move.uci,
51+
move.san,
52+
)
53+
}
54+
}
55+
3856
return {
3957
termination,
4058
id,
4159
gameStates,
4260
moves,
61+
tree: gameTree,
4362
} as TuringGame
4463
}
4564

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { useCallback, useContext, useEffect, useMemo } from 'react'
2+
3+
import { useWindowSize } from 'src/hooks'
4+
import { TuringTreeControllerContext } from 'src/contexts/'
5+
import { FlipIcon } from 'src/components/Icons/icons'
6+
7+
interface Props {
8+
setCurrentMove?: (move: [string, string] | null) => void
9+
}
10+
11+
export const TuringBoardController: React.FC<Props> = ({
12+
setCurrentMove,
13+
}: Props) => {
14+
const { width } = useWindowSize()
15+
const {
16+
orientation,
17+
setOrientation,
18+
setCurrentIndex,
19+
currentIndex,
20+
plyCount,
21+
goToRootNode,
22+
goToPreviousNode,
23+
goToNextNode,
24+
gameTree,
25+
} = useContext(TuringTreeControllerContext)
26+
27+
const toggleBoardOrientation = useCallback(() => {
28+
setOrientation(orientation === 'white' ? 'black' : 'white')
29+
}, [orientation, setOrientation])
30+
31+
const hasPrevious = useMemo(() => currentIndex > 0, [currentIndex])
32+
33+
const hasNext = useMemo(
34+
() => currentIndex < plyCount - 1,
35+
[currentIndex, plyCount],
36+
)
37+
38+
const getFirst = useCallback(() => {
39+
goToRootNode()
40+
if (setCurrentMove) setCurrentMove(null)
41+
}, [goToRootNode, setCurrentMove])
42+
43+
const getPrevious = useCallback(() => {
44+
goToPreviousNode()
45+
if (setCurrentMove) setCurrentMove(null)
46+
}, [goToPreviousNode, setCurrentMove])
47+
48+
const getNext = useCallback(() => {
49+
goToNextNode()
50+
if (setCurrentMove) setCurrentMove(null)
51+
}, [goToNextNode, setCurrentMove])
52+
53+
const getLast = useCallback(() => {
54+
const mainLine = gameTree.getMainLine()
55+
if (mainLine.length > 0) {
56+
setCurrentIndex(mainLine.length - 1)
57+
}
58+
if (setCurrentMove) setCurrentMove(null)
59+
}, [gameTree, setCurrentIndex, setCurrentMove])
60+
61+
useEffect(() => {
62+
if (width <= 670) return
63+
const onKeyDown = (e: KeyboardEvent) => {
64+
switch (e.key) {
65+
case 'Left':
66+
case 'ArrowLeft':
67+
if (hasPrevious) getPrevious()
68+
break
69+
case 'Right':
70+
case 'ArrowRight':
71+
if (hasNext) getNext()
72+
break
73+
case 'Down':
74+
case 'ArrowDown':
75+
if (hasNext) getLast()
76+
break
77+
case 'Up':
78+
case 'ArrowUp':
79+
if (hasPrevious) getFirst()
80+
break
81+
case 'f':
82+
toggleBoardOrientation()
83+
break
84+
default:
85+
}
86+
}
87+
88+
window.addEventListener('keydown', onKeyDown)
89+
return () => window.removeEventListener('keydown', onKeyDown)
90+
}, [
91+
getFirst,
92+
getLast,
93+
getNext,
94+
getPrevious,
95+
hasNext,
96+
hasPrevious,
97+
toggleBoardOrientation,
98+
width,
99+
currentIndex,
100+
])
101+
102+
return (
103+
<div className="flex w-full flex-row items-center gap-[1px] rounded">
104+
<button
105+
onClick={toggleBoardOrientation}
106+
className="flex h-7 flex-1 items-center justify-center rounded-sm bg-button-secondary transition duration-200 hover:bg-human-3 disabled:bg-button-secondary/40"
107+
>
108+
{FlipIcon}
109+
</button>
110+
<button
111+
onClick={getFirst}
112+
disabled={!hasPrevious}
113+
className="flex h-7 flex-1 items-center justify-center rounded-sm bg-button-secondary transition duration-200 hover:bg-human-3 disabled:bg-button-secondary/40"
114+
>
115+
&#8249;&#8249;&#8249;
116+
</button>
117+
<button
118+
onClick={getPrevious}
119+
disabled={!hasPrevious}
120+
className="flex h-7 flex-1 items-center justify-center rounded-sm bg-button-secondary transition duration-200 hover:bg-human-3 disabled:bg-button-secondary/40"
121+
>
122+
&#8249;
123+
</button>
124+
<button
125+
onClick={getNext}
126+
disabled={!hasNext}
127+
className="flex h-7 flex-1 items-center justify-center rounded-sm bg-button-secondary transition duration-200 hover:bg-human-3 disabled:bg-button-secondary/40"
128+
>
129+
&#8250;
130+
</button>
131+
<button
132+
onClick={getLast}
133+
disabled={!hasNext}
134+
className="flex h-7 flex-1 items-center justify-center rounded-sm bg-button-secondary transition duration-200 hover:bg-human-3 disabled:bg-button-secondary/40"
135+
>
136+
&#8250;&#8250;&#8250;
137+
</button>
138+
</div>
139+
)
140+
}

0 commit comments

Comments
 (0)