├── .idea
├── .gitignore
├── misc.xml
├── vcs.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── modules.xml
└── Tic-Tac-Toe.iml
├── .gitignore
├── README.md
├── style.css
├── LICENSE
├── index.html
└── script.js
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /workspace.xml
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Mac files
2 | .DS_Store
3 |
4 | # Dependency directories
5 | /node_modules
6 | */node_modules
7 |
8 | # lerna files
9 | /lerna-debug.log
10 |
11 | # Lock files
12 | /package-lock.json
13 | /yarn.lock
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tic-Tac-Toe
2 | Repository for a [Dev.to article](https://dev.to/bornasepic/pure-and-simple-tic-tac-toe-with-javascript-4pgn)
3 |
4 | #### Typescript
5 | If you're interested in a type supported version of the game checkout the `typescript` branch and follow the instructions from there.
6 |
7 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/Tic-Tac-Toe.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: "Arial", sans-serif;
3 | }
4 |
5 | section {
6 | text-align: center;
7 | }
8 |
9 | .game--container {
10 | display: grid;
11 | grid-template-columns: repeat(3, auto);
12 | width: 306px;
13 | margin: 50px auto;
14 | }
15 |
16 | .cell {
17 | font-family: "Permanent Marker", cursive;
18 | width: 100px;
19 | height: 100px;
20 | box-shadow: 0 0 0 1px #333333;
21 | border: 1px solid #333333;
22 | cursor: pointer;
23 |
24 | line-height: 100px;
25 | font-size: 60px;
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Borna Šepić
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 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 | Tic Tac Toe
9 |
10 |
11 |
12 |
13 | Tic Tac Toe
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/script.js:
--------------------------------------------------------------------------------
1 | const statusDisplay = document.querySelector('.game--status');
2 |
3 | let gameActive = true;
4 | let currentPlayer = "X";
5 | let gameState = ["", "", "", "", "", "", "", "", ""];
6 |
7 | const winningMessage = () => `Player ${currentPlayer} has won!`;
8 | const drawMessage = () => `Game ended in a draw!`;
9 | const currentPlayerTurn = () => `It's ${currentPlayer}'s turn`;
10 |
11 | statusDisplay.innerHTML = currentPlayerTurn();
12 |
13 | const winningConditions = [
14 | [0, 1, 2],
15 | [3, 4, 5],
16 | [6, 7, 8],
17 | [0, 3, 6],
18 | [1, 4, 7],
19 | [2, 5, 8],
20 | [0, 4, 8],
21 | [2, 4, 6]
22 | ];
23 |
24 | function handleCellPlayed(clickedCell, clickedCellIndex) {
25 | gameState[clickedCellIndex] = currentPlayer;
26 | clickedCell.innerHTML = currentPlayer;
27 | }
28 |
29 | function handlePlayerChange() {
30 | currentPlayer = currentPlayer === "X" ? "O" : "X";
31 | statusDisplay.innerHTML = currentPlayerTurn();
32 | }
33 |
34 | function handleResultValidation() {
35 | let roundWon = false;
36 | for (let i = 0; i <= 7; i++) {
37 | const winCondition = winningConditions[i];
38 | let a = gameState[winCondition[0]];
39 | let b = gameState[winCondition[1]];
40 | let c = gameState[winCondition[2]];
41 | if (a === '' || b === '' || c === '') {
42 | continue;
43 | }
44 | if (a === b && b === c) {
45 | roundWon = true;
46 | break
47 | }
48 | }
49 |
50 | if (roundWon) {
51 | statusDisplay.innerHTML = winningMessage();
52 | gameActive = false;
53 | return;
54 | }
55 |
56 | let roundDraw = !gameState.includes("");
57 | if (roundDraw) {
58 | statusDisplay.innerHTML = drawMessage();
59 | gameActive = false;
60 | return;
61 | }
62 |
63 | handlePlayerChange();
64 | }
65 |
66 | function handleCellClick(clickedCellEvent) {
67 | const clickedCell = clickedCellEvent.target;
68 | const clickedCellIndex = parseInt(clickedCell.getAttribute('data-cell-index'));
69 |
70 | if (gameState[clickedCellIndex] !== "" || !gameActive) {
71 | return;
72 | }
73 |
74 | handleCellPlayed(clickedCell, clickedCellIndex);
75 | handleResultValidation();
76 | }
77 |
78 | function handleRestartGame() {
79 | gameActive = true;
80 | currentPlayer = "X";
81 | gameState = ["", "", "", "", "", "", "", "", ""];
82 | statusDisplay.innerHTML = currentPlayerTurn();
83 | document.querySelectorAll('.cell').forEach(cell => cell.innerHTML = "");
84 | }
85 |
86 | document.querySelectorAll('.cell').forEach(cell => cell.addEventListener('click', handleCellClick));
87 | document.querySelector('.game--restart').addEventListener('click', handleRestartGame);
--------------------------------------------------------------------------------