├── 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 | --------------------------------------------------------------------------------