|
3 | 3 |
|
4 | 4 | <script{{#if typescript}} lang="ts"{{/if}}> |
5 | 5 | import './board.css'; |
6 | | -import {onMount} from 'svelte'; |
| 6 | +import {createTable, createValues} from 'tinybase/ui-svelte'; |
7 | 7 | import Square from './Square.svelte'; |
8 | 8 | import {store} from './store'; |
| 9 | +{{#if schemas}} |
| 10 | + {{#if typescript}} |
| 11 | + import type {Store as TinyBaseStore} from 'tinybase'; |
| 12 | + {{/if}} |
| 13 | +{{/if}} |
9 | 14 |
|
10 | | -const getSquares = () => { |
11 | | -const gameStatus = |
12 | | - {{#if typescript}}(store.getValue('gameStatus') as string | undefined) ?? 'playing'{{else}}store.getValue('gameStatus') ?? 'playing'{{/if}}; |
13 | | -const winningLine = |
14 | | - {{#if typescript}}(store.getValue('winningLine') as string | undefined) ?? ''{{else}}store.getValue('winningLine') ?? ''{{/if}}; |
15 | | -const currentPlayer = |
16 | | - {{#if typescript}}(store.getValue('currentPlayer') as string | undefined) ?? 'X'{{else}}store.getValue('currentPlayer') ?? 'X'{{/if}}; |
| 15 | +const positions = Array.from({length: 9}, (_, i) => i.toString()); |
| 16 | +
|
| 17 | +const board = createTable( |
| 18 | +'board', |
| 19 | +{{#if schemas}}store as unknown as TinyBaseStore{{else}}store{{/if}}, |
| 20 | +){{#if typescript}} as {readonly current: Record<string, {value?: string}>}{{/if}}; |
| 21 | +
|
| 22 | +const gameState = createValues( |
| 23 | +{{#if schemas}}store as unknown as TinyBaseStore{{else}}store{{/if}}, |
| 24 | +){{#if typescript}} as { |
| 25 | + readonly current: { |
| 26 | + currentPlayer?: string; |
| 27 | + gameStatus?: string; |
| 28 | + winningLine?: string; |
| 29 | + }; |
| 30 | +}{{/if}}; |
| 31 | +
|
| 32 | +const getSquare = (position{{#if typescript}}: string{{/if}}) => { |
| 33 | +const gameStatus = gameState.current.gameStatus ?? 'playing'; |
| 34 | +const winningLine = gameState.current.winningLine ?? ''; |
17 | 35 | const winningPositions = new Set( |
18 | 36 | winningLine ? winningLine.split(',') : [], |
19 | 37 | ); |
20 | | -const disabled = gameStatus !== 'playing'; |
21 | | -
|
22 | | -return Array.from({length: 9}, (_, i) => { |
23 | | -const position = i.toString(); |
24 | | -const value = |
25 | | - {{#if typescript}}(store.getCell('board', position, 'value') as string | undefined) ?? ''{{else}}store.getCell('board', position, 'value') ?? ''{{/if}}; |
| 38 | +const value = board.current[position]?.value ?? ''; |
26 | 39 |
|
27 | 40 | return { |
28 | | -position, |
29 | 41 | value, |
30 | | -disabled: disabled || !!value, |
| 42 | +disabled: gameStatus !== 'playing' || !!value, |
31 | 43 | winning: winningPositions.has(position), |
32 | | -currentPlayer, |
33 | 44 | }; |
34 | | -}); |
35 | | -}; |
36 | | -
|
37 | | -let squares = $state(getSquares()); |
38 | | -
|
39 | | -const updateBoard = () => { |
40 | | -squares = getSquares(); |
41 | 45 | }; |
42 | 46 |
|
43 | 47 | const handleSquareClick = (position{{#if typescript}}: string{{/if}}) => { |
44 | | -const gameStatus = |
45 | | - {{#if typescript}}(store.getValue('gameStatus') as string | undefined) ?? 'playing'{{else}}store.getValue('gameStatus') ?? 'playing'{{/if}}; |
46 | | -const currentPlayer = |
47 | | - {{#if typescript}}(store.getValue('currentPlayer') as string | undefined) ?? 'X'{{else}}store.getValue('currentPlayer') ?? 'X'{{/if}}; |
48 | | -const value = store.getCell('board', position, 'value'); |
| 48 | +const gameStatus = gameState.current.gameStatus ?? 'playing'; |
| 49 | +const currentPlayer = gameState.current.currentPlayer ?? 'X'; |
| 50 | +const value = board.current[position]?.value; |
49 | 51 |
|
50 | 52 | if (gameStatus === 'playing' && !value && currentPlayer) { |
51 | 53 | store.setCell('board', position, 'value', currentPlayer); |
52 | 54 | } |
53 | 55 | }; |
54 | | -
|
55 | | -onMount(() => { |
56 | | -store.addValuesListener(updateBoard); |
57 | | -store.addTableListener('board', updateBoard); |
58 | | -updateBoard(); |
59 | | -}); |
60 | 56 | </script> |
61 | 57 |
|
62 | 58 | <div id="board"> |
63 | | - {#each squares as square (square.position)} |
| 59 | + {#each positions as position (position)} |
| 60 | + {@const square = getSquare(position)} |
64 | 61 | <Square |
65 | 62 | value={square.value} |
66 | 63 | disabled={square.disabled} |
67 | 64 | winning={square.winning} |
68 | | - handleClick={() => handleSquareClick(square.position)} |
| 65 | + handleClick={() => handleSquareClick(position)} |
69 | 66 | /> |
70 | 67 | {/each} |
71 | 68 | </div> |
0 commit comments