Skip to content

Commit 7a58cbd

Browse files
committed
Pushing completed TTT project for review
1 parent 01b113d commit 7a58cbd

8 files changed

Lines changed: 358 additions & 0 deletions

File tree

TicTacToe/CSS/game.css

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* This property centers the <h1>: */
2+
h1 {
3+
text-align: center;
4+
}
5+
6+
/* This container includes the table & canvas... */
7+
.center-container {
8+
/* This property sets the container's width: */
9+
width: 608px;
10+
/* This property centers the container: */
11+
margin: 0 auto;
12+
/* 50ox down from top */
13+
margin-top: 50px;
14+
}
15+
16+
table {
17+
/* This property collapses the table's borders into one border: */
18+
border-collapse: collapse;
19+
/* This hides the table's outer borders: */
20+
border-style: hidden;
21+
}
22+
23+
td {
24+
/* This property changes the cursor to the "index finger hand" when <td> elements are hovered over: */
25+
cursor: pointer;
26+
/* This property sets the table's border style: */
27+
border: 4px solid black;
28+
/* This property removes the default padding */
29+
padding: 0px;
30+
width: 200px;
31+
height: 200px;
32+
}
33+
34+
canvas {
35+
/* This property sets the canvas's position to the container's top-left corner: */
36+
position: absolute;
37+
/* This property places the canvas above the table */
38+
z-index: 10;
39+
/* This property makes the canvas invisible */
40+
pointer-events: none;
41+
}

TicTacToe/IMAGES/o.png

16.5 KB
Loading

TicTacToe/IMAGES/x.png

24 KB
Loading

TicTacToe/JS/tictactoe.js

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
// This variable keeps track of whose turn it is:
2+
let activePlayer = "X";
3+
// This [] stores an [] of moves; used to determine win conditions:
4+
let selectedSquares = [];
5+
6+
// This function places an "X" or "O" in a square:
7+
function placeXorO(squareNumber) {
8+
/* This condition ensures a square hasn't been selected already.
9+
The .some method is used to check each element of selectedSquare []
10+
to see if it contains the square number clicked on.*/
11+
if (!selectedSquares.some((element) => element.includes(squareNumber))) {
12+
// This variable retrieves the ID of the html element that was clicked:
13+
let select = document.getElementById(squareNumber);
14+
// This condition checks whose turn it is:
15+
if (activePlayer === "X") {
16+
// If activePlayer is equal to "X", place the x.png in HTML:
17+
select.style.backgroundImage = "url('IMAGES/x.png')";
18+
// Active player may only be "X" or "O"; if not "X", it must be "O":
19+
} else {
20+
// If activePlayer is equal to "O", place the o.png in HTML:
21+
select.style.backgroundImage = "url('IMAGES/o.png')";
22+
}
23+
// squareNumber & activePlayer are concatenated and added to []:
24+
selectedSquares.push(squareNumber + activePlayer);
25+
// This calls a function to check for any win conditions:
26+
checkWinConditions();
27+
// This condition changes activePlayer:
28+
if (activePlayer === "X") {
29+
// If activePlayer is "X", change it to "O":
30+
activePlayer = "O";
31+
// Vice versa:
32+
} else {
33+
activePlayer = "X";
34+
}
35+
36+
// This function plays the "placement" sound:
37+
audio("./MEDIA/place.mp3");
38+
// This condition checks if it is the computer's turn:
39+
if (activePlayer === "O") {
40+
// This function disables clicking for computer's choice:
41+
disableClick();
42+
// This function waits 1 second before computer places image & enables click:
43+
setTimeout(function () {
44+
computersTurn();
45+
}, 1000);
46+
}
47+
// Returning TRUE is needed for the computersTurn() to work:
48+
return true;
49+
}
50+
// This function results in a random square being selected:
51+
function computersTurn() {
52+
// This boolean is needed for our while loop:
53+
let success = false;
54+
// This variable stores a random number 0-8:
55+
let pickASquare;
56+
// This condition allows our while loop to keep trying if a square is selected already:
57+
while (!success) {
58+
// A random number between 0 & 8 is selected:
59+
pickASquare = String(Math.floor(Math.random() * 9));
60+
// If the random number evaluated returns TRUE, the square hasn't been selected yet:
61+
if (placeXorO(pickASquare)) {
62+
// This line calls the function:
63+
placeXorO(pickASquare);
64+
// This changes our boolean and ends the loop:
65+
success = true;
66+
}
67+
}
68+
}
69+
}
70+
71+
/* This function parses the selectedSquares [] to search for win conditions.
72+
drawWinLine() is called to draw a line if condition is met. */
73+
function checkWinConditions() {
74+
// X 0, 1, 2 condition:
75+
if (arrayIncludes("OX", "1X", "2X")) {
76+
drawWinLine(50, 100, 558, 100);
77+
}
78+
// X 3, 4, 5 condition:
79+
else if (arrayIncludes("3X", "4X", "5X")) {
80+
drawWinLine(50, 304, 558, 304);
81+
}
82+
// X 6, 7, 8 condition:
83+
else if (arrayIncludes("6X", "7X", "8X")) {
84+
drawWinLine(50, 508, 558, 508);
85+
}
86+
// X 0, 3, 6 condition:
87+
else if (arrayIncludes("0X", "3X", "6X")) {
88+
drawWinLine(100, 50, 100, 558);
89+
}
90+
// X 1, 4, 7 condition:
91+
else if (arrayIncludes("1X", "4X", "7X")) {
92+
drawWinLine(304, 50, 304, 558);
93+
}
94+
// X 2, 5, 8 condition:
95+
else if (arrayIncludes("2X", "5X", "8X")) {
96+
drawWinLine(508, 50, 508, 558);
97+
}
98+
// x 6, 4, 2 condition:
99+
else if (arrayIncludes("6X", "4X", "2X")) {
100+
drawWinLine(100, 508, 510, 90);
101+
}
102+
// X 0, 4, 8 condition:
103+
else if (arrayIncludes("0X", "4X", "8X")) {
104+
drawWinLine(100, 100, 520, 520);
105+
}
106+
// O 0, 1, 2 condition:
107+
else if (arrayIncludes("0O", "1O", "2O")) {
108+
drawWinLine(50, 100, 558, 100);
109+
}
110+
// O 3, 4, 5 condition:
111+
else if (arrayIncludes("3O", "4O", "5O")) {
112+
drawWinLine(50, 304, 558, 304);
113+
}
114+
// O 6, 7, 8 condition:
115+
else if (arrayIncludes("6O", "7O", "8O")) {
116+
drawWinLine(50, 508, 558, 508);
117+
}
118+
// O 0, 3, 6 condition:
119+
else if (arrayIncludes("0O", "3O", "6O")) {
120+
drawWinLine(100, 50, 100, 558);
121+
}
122+
// O 1, 4, 7 condition:
123+
else if (arrayIncludes("1O", "4O", "7O")) {
124+
drawWinLine(304, 50, 304, 558);
125+
}
126+
// O 2, 5, 8 condition:
127+
else if (arrayIncludes("2O", "5O", "8O")) {
128+
drawWinLine(508, 50, 508, 558);
129+
}
130+
// O 6, 4, 2 condition:
131+
else if (arrayIncludes("6O", "4O", "2O")) {
132+
drawWinLine(100, 508, 510, 90);
133+
}
134+
// O 0, 4, 8 condition:
135+
else if (arrayIncludes("0O", "4O", "8O")) {
136+
drawWinLine(100, 100, 520, 520);
137+
}
138+
//* This condition checks for a tie. If none of the above conditions register
139+
// and all 9 squares have been selected, the code executes
140+
else if (selectedSquares.length >= 9) {
141+
// This function plays the "tie game" sound:
142+
audio("./MEDIA/tie.mp3");
143+
// This function sets a .3 second timer before the resetGame() is called:
144+
setTimeout(function () {
145+
resetGame();
146+
}, 1000);
147+
}
148+
149+
// This function checks if an [] includes 3 strings (checks for each win condition):
150+
function arrayIncludes(squareA, squareB, squareC) {
151+
// These 3 variables will be used to check for 3 in a row:
152+
const a = selectedSquares.includes(squareA);
153+
const b = selectedSquares.includes(squareB);
154+
const c = selectedSquares.includes(squareC);
155+
/* If the 3 variables we pass are all included in our [], TRUE is returned,
156+
and our else/if condition executes drawWinLine() */
157+
if (a === true && b === true && c === true) {
158+
return true;
159+
}
160+
}
161+
}
162+
163+
// This function makes the body element temporarily unclickable:
164+
function disableClick() {
165+
// This makes the body unclickable:
166+
body.style.pointerEvents = "none";
167+
// This makes the body clickable again after 1 second:
168+
setTimeout(function () {
169+
body.style.pointerEvents = "auto";
170+
}, 1000);
171+
}
172+
173+
/* This function takes a string parameter of the path set eariler for the
174+
"placement" sound ("./MEDIA/place.mp3"): */
175+
function audio(audioURL) {
176+
// New audio object is created, passing the path as a parameter:
177+
let audio = new Audio(audioURL);
178+
// This ".play" method plays the audio sound:
179+
audio.play();
180+
}
181+
182+
// This function utilizes HTML canvas to draw win lines:
183+
function drawWinLine(coordX1, coordY1, coordX2, coordY2) {
184+
// This line accesses the HTML canvas element:
185+
const canvas = document.getElementById("win-lines");
186+
// This line gives us access to methods & properties to use on canvas:
187+
const c = canvas.getContext("2d");
188+
// This line indicates where a line's "X-axis" begins:
189+
let x1 = coordX1;
190+
// This line indicates where a line's "Y-axis" begins:
191+
y1 = coordY1;
192+
// This line indicates where a line's "X-axis" ends:
193+
x2 = coordX2;
194+
// This line indicates where a line's "Y-axis" ends:
195+
y2 = coordY2;
196+
// This variable stores temporary "X-axis" data we update in the animation loop:
197+
x = x1;
198+
// This variable stores temporary "Y-axis" data we update in the animation loop:
199+
y = y1;
200+
201+
// This function interacts with the canvas:
202+
function animateLineDrawing() {
203+
// This variable creates a loop:
204+
const animationLoop = requestAnimationFrame(animateLineDrawing);
205+
// This method clears content from last loop iteration:
206+
c.clearRect(0, 0, 608, 608);
207+
// This method starts a new path:
208+
c.beginPath();
209+
// This method moves us to the line's starting point:
210+
c.moveTo(x1, y1);
211+
// This method indicates the line's end point:
212+
c.lineTo(x, y);
213+
// This method sets the line's width:
214+
c.lineWidth = 10;
215+
// This method sets the line's color:
216+
c.strokeStyle = "rgba(70, 255, 33, .8)";
217+
// This method draws everything laid out above:
218+
c.stroke();
219+
// This condition checks if the endpoint's been reached:
220+
if (x1 <= x2 && y1 <= y2) {
221+
// This condition adds 10 to the previous end X point:
222+
if (x < x2) {
223+
x += 10;
224+
}
225+
// This condition adds 10 to the previous end Y point:
226+
if (y < y2) {
227+
y += 10;
228+
}
229+
// This condition cancels the animation loop if the end points are reached:
230+
if (x >= x2 && y >= y2) {
231+
cancelAnimationFrame(animationLoop);
232+
}
233+
}
234+
/* This condition is similar to the one above;
235+
(necessary for the "6, 4, 2" win condition): */
236+
if (x1 <= x2 && y1 >= y2) {
237+
if (x < x2) {
238+
x += 10;
239+
}
240+
if (y > y2) {
241+
y -= 10;
242+
}
243+
if (x >= x2 && y <= y2) {
244+
cancelAnimationFrame(animationLoop);
245+
}
246+
}
247+
}
248+
// This function clears the canvas after the win line is drawn:
249+
function clear() {
250+
// This line starts the animation loop:
251+
const animationLoop = requestAnimationFrame(clear);
252+
// This line clears the canvas:
253+
c.clearRect(0, 0, 608, 608);
254+
// This line stops the animation loop:
255+
cancelAnimationFrame(animationLoop);
256+
}
257+
258+
// This line disallows clicking while the "win" sound is playing:
259+
disableClick();
260+
// This line plays the "win" sound:
261+
audio("./MEDIA/winGame.mp3");
262+
// This line calls the main animation loop:
263+
animateLineDrawing();
264+
// This line waits 1 second, then clears canvas, resets game, & allows clicking again:
265+
setTimeout(function () {
266+
clear();
267+
resetGame();
268+
}, 1000);
269+
}
270+
271+
// This function resets the game in the event of a tie or a win:
272+
function resetGame() {
273+
// This "for loop" iterates through each HTML square element:
274+
for (let i = 0; i < 9; i++) {
275+
// This variable gets the HTML element of "i":
276+
let square = document.getElementById(String(i));
277+
// This removes our element's backgroundImage:
278+
square.style.backgroundImage = "";
279+
}
280+
// This resets our array so it is empty and we can start over:
281+
selectedSquares = [];
282+
}

TicTacToe/MEDIA/place.mp3

3.7 KB
Binary file not shown.

TicTacToe/MEDIA/tie.mp3

5.35 KB
Binary file not shown.

TicTacToe/MEDIA/winGame.mp3

36.8 KB
Binary file not shown.

TicTacToe/TicTacToe.html

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link rel="stylesheet" type="text/css" href="CSS/game.css" />
7+
<script src="./JS/tictactoe.js" async></script>
8+
<title>Interactive Tic-Tac-Toe</title>
9+
</head>
10+
<body id="body">
11+
<h1><u>Game</u>: Tic-Tac-Toe</h1>
12+
<!-- This container is needed to overlay the canvas over the table -->
13+
<div class="center-container">
14+
<!-- NOTE: Canvas width & height must be set within the element -->
15+
<canvas id="win-lines" width="608" height="608"></canvas>
16+
<table>
17+
<tr>
18+
<td id="0" onClick="placeXorO('0')"></td>
19+
<td id="1" onClick="placeXorO('1')"></td>
20+
<td id="2" onClick="placeXorO('2')"></td>
21+
</tr>
22+
<tr>
23+
<td id="3" onClick="placeXorO('3')"></td>
24+
<td id="4" onClick="placeXorO('4')"></td>
25+
<td id="5" onClick="placeXorO('5')"></td>
26+
</tr>
27+
<tr>
28+
<td id="6" onClick="placeXorO('6')"></td>
29+
<td id="7" onClick="placeXorO('7')"></td>
30+
<td id="8" onClick="placeXorO('8')"></td>
31+
</tr>
32+
</table>
33+
</div>
34+
</body>
35+
</html>

0 commit comments

Comments
 (0)