fuzzyworld

dao-game / react-multiplayer / files / src / react / App.tsx

Branch react-multiplayer · default branch · all branches

App.tsx

4.4 KB · history · blame

1import * as React from 'react';
2import { useEffect, useState } from 'react';
3import { Coord } from '../game/coord';
4import { IGame, MoveResult } from '../game/game';
5import Modal from 'react-modal';
6import './App.css';
7import { Tile } from './Tile';
8import { Controls } from './Controls';
9import { delay } from '../utils/delay';
10import { Status } from './Status';
11
12export type Props = {
13 game: IGame;
14};
15
16export const App = (props: Props): React.ReactElement => {
17 const { game } = props;
18 const [selectedPiecePos, setSelectedPiecePos] = useState<Coord>()
19 const [validMoves, setValidMoves] = useState<Coord[]>([]);
20 const [currentPlayerId, setCurrentPlayerId] = useState<string>(game.currentPlayerId);
21 const [moveResult, setMoveResult] = useState<MoveResult>();
22 const [isModalOpen, setIsModalOpen] = useState(false);
23 const [isControlsDisabled, setIsControlsDisabled] = useState(!game.canUndoMove);
24
25 useEffect((): void => {
26 const slowUpdate = async () => {
27 if (moveResult && moveResult.isTerminal) {
28 await delay(750);
29 setIsModalOpen(true);
30 }
31 };
32 slowUpdate();
33 }, [moveResult]);
34
35 const makeMove = async (from: Coord, to: Coord) => {
36 const result = await game.makeMove(from, to);
37 setCurrentPlayerId(game.currentPlayerId);
38 setSelectedPiecePos(undefined);
39 setValidMoves([]);
40 setMoveResult(result);
41 setIsControlsDisabled(false);
42 };
43 const undoMove = () => {
44 const move = game.undoMove();
45 console.debug({ move });
46 setCurrentPlayerId(game.currentPlayerId);
47 setSelectedPiecePos(undefined);
48 setValidMoves([]);
49 setMoveResult(undefined);
50 setIsControlsDisabled(!game.canUndoMove);
51 };
52
53 const allTiles: React.ReactElement[] = [];
54 for (let r = 0; r < game.size.row; r++) {
55 for (let c = 0; c < game.size.col; c++) {
56 const pos = new Coord(r, c);
57 const pieceClickCb = () => {
58 const isUnselectClick = selectedPiecePos !== undefined && selectedPiecePos.equals(pos);
59 if (isUnselectClick) {
60 setSelectedPiecePos(undefined);
61 setValidMoves([]);
62 } else {
63 setSelectedPiecePos(pos);
64 setValidMoves([...game.getValidMoves(pos)]);
65 }
66 };
67 const validMoveClickCb = async () => {
68 await makeMove(selectedPiecePos!, pos)
69 };
70 const tile =
71 <Tile
72 pos={pos}
73 game={game}
74 validMoves={validMoves}
75 selectedPiecePos={selectedPiecePos}
76 currentPlayerId={currentPlayerId}
77 pieceClickCb={() => pieceClickCb()}
78 validMoveClickCb={() => validMoveClickCb()}
79 key={game.coordToBoardIndex(pos)}
80 />;
81 allTiles.push(tile);
82 }
83 }
84
85 return (
86 <div>
87 <Status
88 currentPlayerId={currentPlayerId}
89 player1Id={game.player1Id}
90 player1Name={game.player1Name}
91 player2Id={game.player2Id}
92 player2Name={game.player2Name}
93 />
94 <div className='grid-container'>
95 {allTiles}
96 </div>
97 <Controls onUndo={undoMove} isDisabled={isControlsDisabled} />
98 <div className='info'>
99 The game consists of only one simple rule and three ways to win. Rules:
100 <ul>
101 <li>Pieces move in a straight line, including diagonally, as far as possible with no jumps.</li>
102 </ul>
103 Ways to win:
104 <ol>
105 <li>Arrange your pieces in a straight line on the board (not diagonally)</li>
106 <li>Occupy four corners of the board</li>
107 <li>Form a 2x2 square anywhere on the board</li>
108 </ol>
109 </div>
110 <Modal isOpen={isModalOpen} className='modal'>
111 <h2>Game Over</h2>
112 <div>
113 {moveResult?.message}
114 </div>
115 <div>
116 <button onClick={() => location.reload()}>
117 Restart game
118 </button>
119 </div>
120 </Modal>
121 </div>
122 );
123}