
This was my first attempt at writing a JS based program after about 2 months of study - about 1/3 way through Jonas Schmedtmann's Udemy Course, about 80% through Kyle Cook's webdevsimplified JS course and 60% into his CSS course - but without much ingrained yet, obviously - it's a massive amount of info to absorb - to see if I had enough skills to attempt a real world scenario.
I learnt a ton from this as it was fun, if very frustrating at times - as only by building stuff will you be able to overcome any hurdles encountered and learn to be stubborn and not give up until you get the bug for it.
I never regarded myself as a potential programmer as I've always hated it in the past, could never "do it", and found it boring. JS for me though opened a whole new area of creativity due to the visual design aspects of HTML and CSS involved, so having something visual and interactive while working and as an end product gives a sense of progress and satisfaction so spurs you on.
The code developed off the top of my head - as an experiment to see what I could produce and how my head works logically (or not!), so many experienced programmers will find it a "weird" approach and hugely over-complex as a design for a relatively simple game, doing it a difficult way with arrays that have to be added to, as more combinations of numerical order possibilities are found, but that's just the way it evolved and why it was interesting, as I didn't plan it or write pseudo code for it first, so it was hopping from one success to the next failure at each step and overcoming them with some odd ideas, sometimes thinking I'd dug impossible holes for myself at times and that the game could never work as the fundamental logic was unsound.
Consequently it has a loop bug that I haven't found yet that causes some valid win combinations not to be found, so calls a Draw instead - yet often it works as it should...?
The HTML code is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="script.js" defer></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div class="h3">
<button id="btn">Reload</button>
</div>
<h3 class="h3">Noughts and Crosses</h3>
<h3 class="h3">
Click in turns to block your opponents line of 3! Player1, click a square
to add your X:
</h3>
<section class="draw">
<div class="no-win-hidden">Game Over! Draw!</div>
</section>
<section class="X-win">
<div class="X-win-hidden">Game Over! X Wins!</div>
</section>
<section class="O-win">
<div class="O-win-hidden">Game Over! O Wins!</div>
</section>
<div class="container">
<div class="item item1">
<span class="one">1</span>
</div>
<div class="item item2">
<span class="two">2</span>
</div>
<div class="item item3">
<span class="three">3</span>
</div>
<div class="item item4">
<span class="four">4</span>
</div>
<div class="item item5">
<span class="five">5</span>
</div>
<div class="item item6">
<span class="six">6</span>
</div>
<div class="item item7">
<span class="seven">7</span>
</div>
<div class="item item8">
<span class="eight">8</span>
</div>
<div class="item item9">
<span class="nine">9</span>
</div>
</div>
</body>
</html>
CSS:
* {
box-sizing: border-box;
margin: 0;
}
body {
background-color: #555;
font-family: cursive;
/* Hide scrollbars */
/* overflow: hidden; */
}
.container {
display: grid;
/* max-width: fit-content; */
/* max-height: fit-content; */
justify-content: center;
margin: none;
grid-template-areas:
"item1 item2 item3"
"item4 item5 item6"
"item7 item8 item9";
}
.h3 {
color: yellow;
text-align: center;
}
.item {
margin: 2px;
border: 1px solid white;
min-height: 25vh;
min-width: 25vw;
background-color: #777;
}
#btn {
background-color: rgb(160, 158, 153);
text-align: left;
border-radius: 1000px;
border-color: white;
}
#btn:hover {
background-color: rgb(231, 220, 56);
cursor: pointer;
}
#itemX {
display: flex;
/* max-height: fit-content; */
color: black;
font-size: 8vw;
text-align: center;
justify-content: center;
align-items: center;
}
#itemO {
/* max-height: fit-content; */
display: flex;
color: white;
font-size: 8vw;
text-align: center;
justify-content: center;
align-items: center;
}
.draw {
color: aqua;
font-size: 4em;
text-align: center;
}
.X-win {
color: black;
font-size: 4em;
text-align: center;
}
.O-win {
color: white;
font-size: 4em;
text-align: center;
}
.no-win-hidden {
display: none;
}
.X-win-hidden {
display: none;
}
.O-win-hidden {
display: none;
}
.Xhidden {
display: none;
}
.Ohidden {
display: none;
}
.Xhidden,
.one {
display: none;
}
.Ohidden .one {
display: none;
}
.Xhidden,
.two {
display: none;
}
.Ohidden .two {
display: none;
}
.Xhidden,
.three {
display: none;
}
.Ohidden .three {
display: none;
}
.Xhidden,
.four {
display: none;
}
.Ohidden .four {
display: none;
}
.Xhidden,
.five {
display: none;
}
.Ohidden .five {
display: none;
}
.Xhidden,
.six {
display: none;
}
.Ohidden .six {
display: none;
}
.Xhidden,
.seven {
display: none;
}
.Ohidden .seven {
display: none;
}
.Xhidden,
.eight {
display: none;
}
.Ohidden .eight {
display: none;
}
.Xhidden,
.nine {
display: none;
}
.Ohidden .nine {
display: none;
}
Javascript:
"use strict";
// // 30 Array possibilites - now that it IS an array again and not an Object when child: was present - but still doesn't help..:
let arrayCheckWin = [
[1, 2, 3],
[1, 3, 2],
[1, 4, 7],
[2, 1, 3],
[2, 3, 1],
[2, 5, 8],
[3, 1, 2],
[3, 2, 1],
[3, 6, 9],
[4, 1, 7],
[4, 5, 6],
[4, 6, 5],
[5, 6, 4],
[5, 4, 6],
[5, 8, 2],
[6, 5, 4],
[6, 4, 5],
[7, 8, 9],
[7, 9, 8],
[8, 9, 7],
[8, 7, 9],
[9, 8, 7],
[9, 7, 8],
[1, 5, 9],
[1, 9, 5],
[5, 1, 9],
[5, 9, 1],
[5, 9, 1],
[5, 1, 9],
[3, 5, 7],
[3, 7, 5],
[5, 3, 7],
[5, 7, 3],
[7, 5, 3],
[7, 3, 5],
[9, 5, 1],
];
let arrayCheckWin2 = [
[1, 5, 4, 7],
[1, 3, 6, 9],
[1, 5, 4, 9],
[1, 7, 5, 3],
[1, 5, 3, 9],
[2, 9, 6, 4],
[1, 2, 7, 4],
[5, 4, 2, 8],
[8, 5, 3, 7],
[2, 5, 1, 3],
[7, 5, 1, 3],
[9, 8, 2, 7],
[1, 3, 5, 7],
[1, 3, 5, 9],
[9, 7, 5, 3],
[9, 7, 5, 1],
[5, 3, 1, 9],
[5, 3, 1, 7],
[7, 9, 5, 1],
[7, 9, 5, 3],
[5, 9, 7, 3],
[5, 7, 9, 1],
[6, 4, 8, 1],
[5, 7, 9, 3],
[9, 4, 5, 1],
[5, 7, 6, 4],
[6, 2, 1, 3],
[6, 9, 5, 4],
[9, 4, 3, 6],
[5, 3, 9, 7],
[4, 8, 7, 9],
[1, 3, 7, 4],
[1, 8, 7, 4],
[2, 4, 5, 8],
[1, 5, 3, 7],
[1, 7, 3, 5],
[1, 7, 3, 4],
[1, 7, 3, 2],
[3, 5, 4, 7],
[2, 5, 6, 8],
[5, 2, 4, 8],
[2, 5, 4, 6],
[3, 1, 5, 9],
[5, 2, 4, 6],
[9, 3, 5, 7],
[5, 9, 3, 7],
];
let arrayCheckWin3 = [
[1, 3, 5, 8, 7],
[1, 3, 5, 4, 9],
[3, 1, 5, 8, 7],
[3, 1, 5, 8, 9],
[9, 4, 8, 1, 7],
[9, 5, 2, 4, 6],
[5, 2, 9, 4, 8],
[4, 9, 1, 7, 8],
[1, 3, 6, 8, 9],
[1, 3, 8, 6, 9],
[7, 9, 5, 2, 3],
[7, 9, 5, 2, 1],
[9, 7, 3, 2, 5],
[9, 7, 3, 1, 5],
[5, 6, 3, 8, 7],
[1, 5, 4, 2, 9],
[1, 7, 6, 8, 9],
[1, 3, 5, 4, 7],
[1, 3, 8, 7, 4],
[1, 8, 3, 7, 4],
[1, 4, 3, 5, 9],
[6, 8, 2, 7, 9],
[1, 3, 8, 7, 4],
[1, 3, 5, 8, 9],
[9, 7, 5, 2, 1],
[9, 7, 5, 2, 3],
[1, 3, 8, 4, 7],
[1, 3, 8, 5, 9],
[1, 7, 5, 6, 9],
[9, 7, 5, 2, 1],
[1, 9, 7, 6, 8],
[5, 1, 6, 8, 9],
];
let draws = [
[1, 2, 7, 6, 9],
[1, 3, 7, 6, 8],
[3, 7, 8, 6, 2],
[1, 3, 6, 5, 7],
[1, 3, 5, 7, 9],
[4, 6, 2, 7, 9],
[1, 2, 6, 7, 8],
[5, 1, 6, 8, 7],
[4, 3, 1, 5, 8],
[5, 6, 2, 7, 9],
[1, 3, 4, 8, 9],
[3, 1, 6, 7, 8],
[1, 5, 7, 8, 6],
[1, 5, 3, 4, 8],
[1, 3, 8, 4, 9],
[1, 3, 6, 4, 8],
[1, 3, 8, 6, 7],
];
let handleClickCount = 0;
const p1Array = [];
const p2Array = [];
// shows that itemsContainer is read as an HTML collection - class required due to multi items
const itemsContainer = document.getElementsByClassName("item");
//-----------HTML, Player 1 + 2 functions and Click count Section --------
// loop over HTML collection to read elements
for (let i = 0; i < itemsContainer.length; i++) {
// show each responds to click event with an event handler:
itemsContainer[i].addEventListener("click", function (event) {
// shows container number clicked
console.log("container number", i + 1);
// });
// counts up clicks so divisor by 2 decides even number so if player 2 or 1 and only up to 9 clicks max.
// Player X or O logic
if (handleClickCount < 9) {
handleClickCount = handleClickCount + 1;
console.log("clickCount", handleClickCount);
if (handleClickCount % 2 == 0) {
console.log("player2");
p2Array.push(i + 1);
console.log("p2 pushed i+1");
console.log("p2array", p2Array);
player2();
} else {
console.log("player1");
p1Array.push(i + 1);
console.log("p1 pushed i+1");
console.log("p1array", p1Array);
player1();
}
}
});
}
// --------------------------PLAYER 2 -----------------------------------------
const player2 = function () {
event.target.classList.add("itemO");
event.target.setAttribute("id", "itemO");
const O = document.createTextNode("O");
event.target.append(O);
// P2 section 6 clicks---------------------------------------
if (handleClickCount % 6 == 0) {
console.log("handleClickCount % 6");
for (let j = 0; j < arrayCheckWin.length; j++) {
console.log("start");
console.log("arrayCheckWin[j]", arrayCheckWin[j]);
console.log("arrayCheckWin.length", arrayCheckWin.length);
console.log("p2Array", p2Array);
console.log("index:", j);
const equals = (a, b) =>
arrayCheckWin[j].length === p2Array.length &&
arrayCheckWin[j].every((v, z) => v === p2Array[z]);
console.log("check arr1", arrayCheckWin);
if (equals(arrayCheckWin[j], p2Array)) {
console.log("are same", arrayCheckWin[j], p2Array);
console.log("Game Over, O wins");
const oWinHidden = document.querySelector(".O-win-hidden");
oWinHidden.classList.remove("O-win-hidden");
console.log("Game Over White Text");
break;
}
}
}
// P2 section 8 clicks---------------------------------------
if (handleClickCount % 8 == 0) {
console.log("handleClickCount % 8");
for (let j = 0; j < arrayCheckWin2.length; j++) {
console.log("start");
console.log("arrayCheckWin2[j]", arrayCheckWin2[j]);
console.log("arrayCheckWin2.length", arrayCheckWin2.length);
console.log("p2Array", p2Array);
console.log("index:", j);
const equals = (a, b) =>
arrayCheckWin2[j].length === p2Array.length &&
arrayCheckWin2[j].every((v, z) => v === p2Array[z]);
console.log("check arr2", arrayCheckWin2);
if (equals(arrayCheckWin2[j], p2Array)) {
console.log("are same", arrayCheckWin2[j], p2Array);
console.log("Game Over, O wins");
const oWinHidden = document.querySelector(".O-win-hidden");
oWinHidden.classList.remove("O-win-hidden");
console.log("Game Over White Text");
break;
}
}
}
};
// ---------------------P1 ------------------------
const player1 = function () {
event.target.classList.add("itemX");
event.target.setAttribute("id", "itemX");
const X = document.createTextNode("X");
event.target.append(X);
// P1 section 5 clicks---------------------------------------
if (handleClickCount % 5 == 0) {
console.log("handleClickCount % 5");
for (let j = 0; j < arrayCheckWin.length; j++) {
console.log("start");
console.log("arrayCheckWin[j]", arrayCheckWin[j]);
console.log("p1Array", p1Array);
console.log("index:", j);
console.log("arrayCheckWin.length", arrayCheckWin.length);
const equals = (a, b) =>
arrayCheckWin[j].length === p1Array.length &&
arrayCheckWin[j].every((v, z) => v === p1Array[z]);
console.log("check arr1", arrayCheckWin);
if (equals(arrayCheckWin[j], p1Array)) {
console.log("are same", arrayCheckWin[j], p1Array);
console.log("Game Over, X wins");
const xWinHidden = document.querySelector(".X-win-hidden");
xWinHidden.classList.remove("X-win-hidden");
console.log("Game Over Black Text");
break;
}
}
}
// P1 section 7 clicks---------------------------------------
if (handleClickCount % 7 == 0) {
console.log("handleClickCount % 7");
for (let j = 0; j < arrayCheckWin2.length; j++) {
console.log("start");
console.log("arrayCheckWin2[j]", arrayCheckWin2[j]);
console.log("arrayCheckWin2.length", arrayCheckWin2.length);
console.log("p1Array", p1Array);
console.log("index:", j);
const equals = (a, b) =>
arrayCheckWin2[j].length === p1Array.length &&
arrayCheckWin2[j].every((v, z) => v === p1Array[z]);
console.log("check arr2", arrayCheckWin2);
if (equals(arrayCheckWin2[j], p1Array)) {
console.log("are same", arrayCheckWin2[j], p1Array);
console.log("Game Over, X wins");
const xWinHidden = document.querySelector(".X-win-hidden");
xWinHidden.classList.remove("X-win-hidden");
console.log("Game Over Black Text");
break;
}
}
}
// P1 section 9 clicks---------------------------------------
if (handleClickCount % 9 == 0) {
console.log("handleClickCount % 9");
for (let j = 0; j < arrayCheckWin3.length; j++) {
console.log("start");
console.log("arrayCheckWin3[j]", arrayCheckWin3[j]);
console.log("arrayCheckWin3.length", arrayCheckWin3.length);
console.log("p1Array", p1Array);
console.log("index:", j);
const equals = (a, b) =>
arrayCheckWin3[j].length === p1Array.length &&
arrayCheckWin3[j].every((v, z) => v === p1Array[z]);
console.log("check arr3", arrayCheckWin3);
if (equals(arrayCheckWin3[j], p1Array)) {
console.log("are same", arrayCheckWin3[j], p1Array);
console.log("Game Over, X wins");
const xWinHidden = document.querySelector(".X-win-hidden");
xWinHidden.classList.remove("X-win-hidden");
console.log("Game Over, Black Text");
break;
} else {
console.log("Draw! Aqua text");
const noWinHidden = document.querySelector(".no-win-hidden");
noWinHidden.classList.add("no-win-hidden");
noWinHidden.classList.remove("no-win-hidden");
break;
}
}
}
// -----------------NEW GAME Reload -----------------------
const btn = document.querySelector("#btn");
btn.addEventListener("click", () => {
// console.log("click");
reload();
});
function reload() {
window.location.reload();
}
}
I haven't commented much yet as I wanted it working fully first so I could explain exactly what code does what for my own understanding.