├── README.md
├── package-lock.json
├── package.json
├── public
└── index.html
└── src
├── components
├── Board.js
├── Game.js
└── Square.js
├── helper.js
├── index.css
└── index.js
/README.md:
--------------------------------------------------------------------------------
1 | # react-tic-tac-toe-hooks
2 | React Tic Tac Toe Game using Functional Components and Hooks
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-tictactoe",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "react": "^16.13.1",
10 | "react-dom": "^16.13.1",
11 | "react-scripts": "3.4.1"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test",
17 | "eject": "react-scripts eject"
18 | },
19 | "eslintConfig": {
20 | "extends": "react-app"
21 | },
22 | "browserslist": {
23 | "production": [
24 | ">0.2%",
25 | "not dead",
26 | "not op_mini all"
27 | ],
28 | "development": [
29 | "last 1 chrome version",
30 | "last 1 firefox version",
31 | "last 1 safari version"
32 | ]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/components/Board.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Square from "./Square";
3 |
4 | const Board = ({ squares, onClick }) => (
5 |
6 | {squares.map((square, i) => (
7 | onClick(i)} />
8 | ))}
9 |
10 | );
11 |
12 | export default Board;
13 |
--------------------------------------------------------------------------------
/src/components/Game.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { calculateWinner } from "../helper";
3 | import Board from "./Board";
4 |
5 | const Game = () => {
6 | const [history, setHistory] = useState([Array(9).fill(null)]);
7 | const [stepNumber, setStepNumber] = useState(0);
8 | const [xIsNext, setXisNext] = useState(true);
9 | const winner = calculateWinner(history[stepNumber]);
10 | const xO = xIsNext ? "X" : "O";
11 |
12 | const handleClick = (i) => {
13 | const historyPoint = history.slice(0, stepNumber + 1);
14 | const current = historyPoint[stepNumber];
15 | const squares = [...current];
16 | // return if won or occupied
17 | if (winner || squares[i]) return;
18 | // select square
19 | squares[i] = xO;
20 | setHistory([...historyPoint, squares]);
21 | setStepNumber(historyPoint.length);
22 | setXisNext(!xIsNext);
23 | };
24 |
25 | const jumpTo = (step) => {
26 | setStepNumber(step);
27 | setXisNext(step % 2 === 0);
28 | };
29 |
30 | const renderMoves = () =>
31 | history.map((_step, move) => {
32 | const destination = move ? `Go to move #${move}` : "Go to Start";
33 | return (
34 |
35 |
36 |
37 | );
38 | });
39 |
40 | return (
41 | <>
42 | React Tic Tac Toe - With Hooks
43 |
44 |
45 |
46 |
History
47 | {renderMoves()}
48 |
49 |
{winner ? "Winner: " + winner : "Next Player: " + xO}
50 |
51 | >
52 | );
53 | };
54 |
55 | export default Game;
56 |
--------------------------------------------------------------------------------
/src/components/Square.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Square = ({ value, onClick }) => {
4 | const style = value ? `squares ${value}` : `squares`;
5 |
6 | return (
7 |
10 | );
11 | };
12 |
13 | export default Square;
14 |
--------------------------------------------------------------------------------
/src/helper.js:
--------------------------------------------------------------------------------
1 | export function calculateWinner(squares) {
2 | const lines = [
3 | [0, 1, 2],
4 | [3, 4, 5],
5 | [6, 7, 8],
6 | [0, 3, 6],
7 | [1, 4, 7],
8 | [2, 5, 8],
9 | [0, 4, 8],
10 | [2, 4, 6]
11 | ];
12 | for (let i = 0; i < lines.length; i++) {
13 | const [a, b, c] = lines[i];
14 | if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
15 | return squares[a];
16 | }
17 | }
18 | return null;
19 | }
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap");
2 |
3 | * {
4 | padding: 0;
5 | margin: 0;
6 | box-sizing: border-box;
7 | }
8 |
9 | body {
10 | background-color: black;
11 | color: white;
12 | font-family: "Roboto", sans-serif;
13 | display: flex;
14 | /* align-items: center; */
15 | justify-content: center;
16 | min-height: 100vh;
17 | padding: 2rem;
18 | }
19 |
20 | h1 {
21 | margin: 2rem;
22 | }
23 |
24 | .board {
25 | border: 1rem solid #ff652f;
26 | background: #ff652f;
27 | width: 500px;
28 | height: 500px;
29 | display: grid;
30 | grid-template: repeat(3, 1fr) / repeat(3, 1fr);
31 | gap: 1rem;
32 | }
33 |
34 | .squares {
35 | background: #272727;
36 | border: none;
37 | font-size: 5rem;
38 | /* font-weight: 800; */
39 | cursor: pointer;
40 | outline: none;
41 | }
42 |
43 | .X {
44 | color: red;
45 | }
46 | .O {
47 | color: green;
48 | }
49 |
50 | .info-wrapper {
51 | display: flex;
52 | justify-content: space-between;
53 | }
54 |
55 | h3 {
56 | padding: 1rem;
57 | }
58 |
59 | li {
60 | list-style: none;
61 | }
62 |
63 | .info-wrapper button {
64 | background: #272727;
65 | color: white;
66 | border: none;
67 | outline: none;
68 | cursor: pointer;
69 | padding: 0.5rem;
70 | margin: 0.5rem 1rem;
71 | }
72 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDom from "react-dom";
3 | import "./index.css";
4 | import Game from "./components/Game";
5 |
6 | ReactDom.render(, document.getElementById("root"));
7 |
--------------------------------------------------------------------------------