14 | )}
15 |
16 |
17 | )
18 | }
19 |
20 | export default GameInfo
21 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Tic Tac Toe
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/components/board/Board.js:
--------------------------------------------------------------------------------
1 | import Square from '../square/Square'
2 |
3 | const Board = ({ squares, onClick, jumpTo }) => {
4 | const renderSquare = (i) => {
5 | return onClick(i)} />
6 | }
7 | return (
8 |
9 |
10 |
11 | {renderSquare(0)}
12 | {renderSquare(1)}
13 | {renderSquare(2)}
14 |
15 |
16 | {renderSquare(3)}
17 | {renderSquare(4)}
18 | {renderSquare(5)}
19 |
20 |
21 | {renderSquare(6)}
22 | {renderSquare(7)}
23 | {renderSquare(8)}
24 |
25 |
26 |
29 |
30 | )
31 | }
32 |
33 | export default Board
34 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Ekaterine (Catherine) Mitagvaria
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tictactoe",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "https://catherineisonline.github.io/tic-tac-toe",
6 | "dependencies": {
7 | "@testing-library/jest-dom": "^5.16.5",
8 | "@testing-library/react": "^13.3.0",
9 | "@testing-library/user-event": "^13.5.0",
10 | "react": "^18.2.0",
11 | "react-dom": "^18.2.0",
12 | "react-router-dom": "^6.22.2",
13 | "react-scripts": "5.0.1",
14 | "web-vitals": "^2.1.4"
15 | },
16 | "scripts": {
17 | "predeploy": "npm run build",
18 | "deploy": "gh-pages -d build",
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test",
22 | "eject": "react-scripts eject"
23 | },
24 | "eslintConfig": {
25 | "extends": [
26 | "react-app",
27 | "react-app/jest"
28 | ]
29 | },
30 | "browserslist": {
31 | "production": [
32 | ">0.2%",
33 | "not dead",
34 | "not op_mini all"
35 | ],
36 | "development": [
37 | "last 1 chrome version",
38 | "last 1 firefox version",
39 | "last 1 safari version"
40 | ]
41 | },
42 | "devDependencies": {
43 | "gh-pages": "^6.1.1"
44 | }
45 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 
3 | # Tic Tac Toe
4 |
5 |
6 | [Tic Tac Toe](https://catherineisonline.github.io/tic-tac-toe/) game, a classic game for two players where each player takes turns marking a grid of 3x3 squares with their X or O. The player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row wins the game. It is also known as Noughts and Crosses or Xs and Os. The game is implemented using React and CSS
7 |
8 | ## Game rules
9 |
10 | 1. The game is played on a grid that is 3 squares by 3 squares
11 | 2. You are X, your friend is O. Players take turns putting their marks in empty squares
12 | 3. The first player to get 3 of their marks in a row (up, down, across, or diagonally) is the winner
13 | 4. When all 9 squares are full, the game is over
14 |
15 | ## Getting Started with Create React App
16 |
17 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
18 |
19 | ## Available Scripts
20 |
21 | In the project directory, you can run:
22 |
23 | ### `npm start`
24 |
25 | Runs the app in the development mode.\
26 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
27 |
28 | The page will reload when you make changes.\
29 | You may also see any lint errors in the console.
30 |
31 | ### `npm test`
32 |
33 | Launches the test runner in the interactive watch mode.\
34 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
35 |
36 | ### `npm run build`
37 |
38 | Builds the app for production to the `build` folder.\
39 | It correctly bundles React in production mode and optimizes the build for the best performance.
40 |
41 | The build is minified and the filenames include the hashes.\
42 | Your app is ready to be deployed!
43 |
44 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
45 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import './index.css'
4 | import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
5 | import calculateWinner from './helpers/calculateWinner'
6 | import Board from './components/board/Board'
7 | import GameInfo from './components/game-info/GameInfo'
8 |
9 | class Game extends React.Component {
10 | constructor(props) {
11 | super(props)
12 | this.state = {
13 | history: [
14 | {
15 | squares: Array(9).fill(null),
16 | },
17 | ],
18 | stepNumber: 0,
19 | xIsNext: true,
20 | }
21 | }
22 |
23 | handleClick(i) {
24 | const history = this.state.history.slice(0, this.state.stepNumber + 1)
25 | const current = history[history.length - 1]
26 | const squares = current.squares.slice()
27 | if (calculateWinner(squares) || squares[i]) {
28 | return
29 | }
30 | squares[i] = this.state.xIsNext ? 'X' : 'O'
31 | this.setState({
32 | history: history.concat([
33 | {
34 | squares: squares,
35 | },
36 | ]),
37 | stepNumber: history.length,
38 | xIsNext: !this.state.xIsNext,
39 | })
40 | }
41 |
42 | jumpTo(step) {
43 | console.log(step)
44 | this.setState({
45 | stepNumber: step,
46 | xIsNext: step % 2 === 0,
47 | })
48 | }
49 |
50 | render() {
51 | const history = this.state.history
52 | const current = history[this.state.stepNumber]
53 | const winner = calculateWinner(current.squares)
54 | let status
55 | if (winner) {
56 | status = 'Winner: ' + winner
57 | } else {
58 | status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O')
59 | }
60 | return (
61 |
62 |