diff --git a/index.html b/index.html
index 48ac21e..43b2ab2 100644
--- a/index.html
+++ b/index.html
@@ -1,37 +1,62 @@
-
-
-
-
-
- Tic-Tac-Toe
-
-
- Tic-Tac-Toe
- Player 1 Turn
-
-
+
+
+
+
+
+ Tic-Tac-Toe
+
+
+ Tic-Tac-Toe
+
-
-
-
+
+
+
+
+
+
+
+ Player 1 Turn
+
+
+
+
+
+
+
+
+
diff --git a/index.js b/index.js
index f4b831f..1ba24cd 100644
--- a/index.js
+++ b/index.js
@@ -1,148 +1,197 @@
-var cube = document.getElementsByClassName("box");
-var count = 0;
+let mode = "pvp"; // "pvp" = player vs player, "pvc" = player vs computer
+let cube = document.getElementsByClassName("box");
+let count = 0;
let turn = 1;
let green = "#5ef141";
+let humanMoves = [];
+let computerMoves = [];
+let magicSquare = [8, 1, 6, 3, 5, 7, 4, 9, 2]; // Magic square mapping
+
+// Disable mode selection after the first click
+let gameStarted = false;
function func(ths) {
+ if (!gameStarted) {
+ // Disable mode selection radios
+ document.querySelectorAll('input[name="mode"]').forEach(r => r.disabled = true);
+ gameStarted = true;
+ }
+
+ if (ths.textContent) return; // Already clicked
+
+ if (mode === "pvp") {
+ twoPlayerMove(ths);
+ } else if (mode === "pvc") {
+ playerMove(ths);
+ }
+}
+
+function twoPlayerMove(ths) {
let playerTurn = document.getElementsByClassName("player_turn");
- if (turn === 1) playerTurn[0].innerHTML = "Player 2 Turn";
- else if (turn === 2) playerTurn[0].innerHTML = "Player 1 Turn";
- ths.classList.add("click-disable");
ths.classList.add("click-disable");
count++;
- if (count % 2 == 0) {
- ths.innerHTML = "X";
- ths.accessKey = 1;
- turn = 1;
- } else {
+
+ if (count % 2 !== 0) {
+ // Player 1 (O)
ths.innerHTML = "O";
ths.accessKey = 0;
- turn = 2;
+ playerTurn[0].innerHTML = "Player 2 Turn";
+ } else {
+ // Player 2 (X)
+ ths.innerHTML = "X";
+ ths.accessKey = 1;
+ playerTurn[0].innerHTML = "Player 1 Turn";
+ }
+
+ checkResult();
+}
+
+function playerMove(ths) {
+ ths.innerHTML = "O";
+ ths.accessKey = 0;
+ ths.classList.add("click-disable");
+ let idx = Array.from(cube).indexOf(ths);
+ humanMoves.push(magicSquare[idx]);
+ count++;
+
+ if (checkWin(humanMoves)) {
+ endGame("Human (O) wins!!", humanMoves);
+ return;
+ }
+
+ if (count === 9) {
+ endGame("It's a Draw!!");
+ return;
+ }
+
+ setTimeout(computerMove, 200);
+}
+
+function computerMove() {
+ let moveIdx = findBestMove();
+ cube[moveIdx].innerHTML = "X";
+ cube[moveIdx].accessKey = 1;
+ cube[moveIdx].classList.add("click-disable");
+ computerMoves.push(magicSquare[moveIdx]);
+ count++;
+
+ if (checkWin(computerMoves)) {
+ endGame("Computer (X) wins!!", computerMoves);
+ return;
+ }
+
+ if (count === 9) {
+ endGame("It's a Draw!!");
+ return;
}
- const a = parseInt(cube[0].accessKey);
- const b = parseInt(cube[1].accessKey);
- const c = parseInt(cube[2].accessKey);
- const d = parseInt(cube[3].accessKey);
- const e = parseInt(cube[4].accessKey);
- const f = parseInt(cube[5].accessKey);
- const g = parseInt(cube[6].accessKey);
- const h = parseInt(cube[7].accessKey);
- const i = parseInt(cube[8].accessKey);
- if (
- a + b + c == 3 ||
- d + e + f == 3 ||
- g + h + i == 3 ||
- a + d + g == 3 ||
- b + e + h == 3 ||
- c + f + i == 3 ||
- a + e + i == 3 ||
- c + e + g == 3
- ) {
- if (a + b + c == 3) {
- cube[0].style.backgroundColor = green;
- cube[1].style.backgroundColor = green;
- cube[2].style.backgroundColor = green;
- }else if(d + e + f == 3){
- cube[3].style.backgroundColor = green;
- cube[4].style.backgroundColor = green;
- cube[5].style.backgroundColor = green;
- }else if(g + h + i == 3){
- cube[6].style.backgroundColor = green;
- cube[7].style.backgroundColor = green;
- cube[8].style.backgroundColor = green;
- }else if(a + d + g == 3){
- cube[0].style.backgroundColor = green;
- cube[3].style.backgroundColor = green;
- cube[6].style.backgroundColor = green;
- }else if(b + e + h == 3){
- cube[1].style.backgroundColor = green;
- cube[4].style.backgroundColor = green;
- cube[7].style.backgroundColor = green;
- }else if(c + f + i == 3){
- cube[2].style.backgroundColor = green;
- cube[5].style.backgroundColor = green;
- cube[8].style.backgroundColor = green;
- }else if(a + e + i == 3){
- cube[0].style.backgroundColor = green;
- cube[4].style.backgroundColor = green;
- cube[8].style.backgroundColor = green;
- }else if(c + e + g == 3){
- cube[2].style.backgroundColor = green;
- cube[4].style.backgroundColor = green;
- cube[6].style.backgroundColor = green;
+}
+
+function findBestMove() {
+ for (let i = 0; i < 9; i++) {
+ if (!cube[i].textContent && checkWin(computerMoves.concat(magicSquare[i]))) return i;
+ }
+ for (let i = 0; i < 9; i++) {
+ if (!cube[i].textContent && checkWin(humanMoves.concat(magicSquare[i]))) return i;
+ }
+ if (!cube[4].textContent) return 4;
+ const corners = [0, 2, 6, 8];
+ for (let c of corners) if (!cube[c].textContent) return c;
+ for (let i = 0; i < 9; i++) if (!cube[i].textContent) return i;
+}
+
+// Common win checker
+function checkWin(moves) {
+ if (moves.length < 3) return false;
+ for (let i = 0; i < moves.length; i++)
+ for (let j = i + 1; j < moves.length; j++)
+ for (let k = j + 1; k < moves.length; k++)
+ if (moves[i] + moves[j] + moves[k] === 15) return true;
+ return false;
+}
+
+// Highlight winning combination
+function highlightWin(moves) {
+ const winCombos = [
+ [0,1,2],[3,4,5],[6,7,8],
+ [0,3,6],[1,4,7],[2,5,8],
+ [0,4,8],[2,4,6]
+ ];
+ for (let combo of winCombos) {
+ let sum = combo.reduce((acc, idx) => {
+ if (cube[idx].textContent === "O") return acc + 0;
+ if (cube[idx].textContent === "X") return acc + 1;
+ return acc;
+ }, 0);
+ if (sum === 3 || sum === 0) {
+ combo.forEach(idx => cube[idx].style.backgroundColor = green);
+ break;
}
+ }
+}
+
+// Common result checker for PvP
+function checkResult() {
+ const keys = Array.from(cube).map(c => parseInt(c.accessKey));
+ const combos = [
+ [0,1,2],[3,4,5],[6,7,8],
+ [0,3,6],[1,4,7],[2,5,8],
+ [0,4,8],[2,4,6]
+ ];
- //alert("X wins!! ");
- document.getElementById("result").innerText = "Player 2 (X) wins!!";
- on();
- } else if (
- a + b + c == 0 ||
- d + e + f == 0 ||
- g + h + i == 0 ||
- a + d + g == 0 ||
- b + e + h == 0 ||
- c + f + i == 0 ||
- a + e + i == 0 ||
- c + e + g == 0
- ) {
- //alert("O wins!! ");
- document.getElementById("result").innerText = "Player 1 (O) wins!!";
- on();
-
- if (a + b + c == 0) {
- cube[0].style.backgroundColor = green;
- cube[1].style.backgroundColor = green;
- cube[2].style.backgroundColor = green;
- }else if(d + e + f == 0){
- cube[3].style.backgroundColor = green;
- cube[4].style.backgroundColor = green;
- cube[5].style.backgroundColor = green;
- }else if(g + h + i == 0){
- cube[6].style.backgroundColor = green;
- cube[7].style.backgroundColor = green;
- cube[8].style.backgroundColor = green;
- }else if(a + d + g == 0){
- cube[0].style.backgroundColor = green;
- cube[3].style.backgroundColor = green;
- cube[6].style.backgroundColor = green;
- }else if(b + e + h == 0){
- cube[1].style.backgroundColor = green;
- cube[4].style.backgroundColor = green;
- cube[7].style.backgroundColor = green;
- }else if(c + f + i == 0){
- cube[2].style.backgroundColor = green;
- cube[5].style.backgroundColor = green;
- cube[8].style.backgroundColor = green;
- }else if(a + e + i == 0){
- cube[0].style.backgroundColor = green;
- cube[4].style.backgroundColor = green;
- cube[8].style.backgroundColor = green;
- }else if(c + e + g == 0){
- cube[2].style.backgroundColor = green;
- cube[4].style.backgroundColor = green;
- cube[6].style.backgroundColor = green;
+ for (let combo of combos) {
+ const sum = combo.reduce((a, idx) => a + keys[idx], 0);
+ if (sum === 3) {
+ combo.forEach(idx => cube[idx].style.backgroundColor = green);
+ endGame("Player 2 (X) wins!!");
+ return;
+ } else if (sum === 0) {
+ combo.forEach(idx => cube[idx].style.backgroundColor = green);
+ endGame("Player 1 (O) wins!!");
+ return;
}
- } else if (a + b + c + d + e + f + g + h + i) {
- //alert("Its a Draw !!!");
- document.getElementById("result").innerText = "It's a Draw!!";
- on();
+ }
+
+ if (keys.every(k => k === 0 || k === 1) && count === 9) {
+ endGame("It's a Draw!!");
}
}
-function on(){
+// Show overlay and stop further moves
+function endGame(message, winningMoves=[]) {
+ document.getElementById("result").innerText = message;
+ if (winningMoves.length) highlightWin(winningMoves);
document.getElementById("overlay").style.display = "block";
+
+ // Disable all remaining cubes
+ Array.from(cube).forEach(c => c.classList.add("click-disable"));
}
-// Resets inmediatly the game if the user has finished. If not it will ask
-// for a confirmation alert
-function restart(isGameFinished) {
- if (isGameFinished) { return reloadWindow() }
+// Restart the game properly
+function restart(fromOverlay) {
+ // Reset variables
+ count = 0;
+ turn = 1;
+ humanMoves = [];
+ computerMoves = [];
+ gameStarted = false;
+
+ // Clear the board
+ Array.from(cube).forEach(c => {
+ c.textContent = "";
+ c.accessKey = "";
+ c.classList.remove("click-disable");
+ c.style.backgroundColor = "";
+ });
- if (confirm('Are you sure yo want to restart the game?')) {
- window.location.reload();
+ // Reset player turn display
+ document.getElementsByClassName("player_turn")[0].innerText = "Player 1 Turn";
+
+ // Hide overlay if restart is from popup
+ if (fromOverlay) {
+ document.getElementById("overlay").style.display = "none";
}
-}
-function reloadWindow() {
- window.location.reload();
+ // Re-enable mode selection
+ document.querySelectorAll('input[name="mode"]').forEach(r => r.disabled = false);
}
+
diff --git a/style.css b/style.css
index 5485eff..ad49fca 100644
--- a/style.css
+++ b/style.css
@@ -9,9 +9,18 @@ body {
height: 100vh;
place-content: center;
display: grid;
+ overflow: hidden; /* prevent scrolling */
background: url("https://images.squarespace-cdn.com/content/v1/5a2613f6be42d61192e3e478/1582999868688-PEVK3HU4FN1D9V5UDM4K/Screen+Shot+2020-02-29+at+1.07.46+PM.png?format=1000w");
}
+#board {
+ width: 300px;
+ height: 300px;
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ grid-gap: 5px;
+}
+
h3 {
text-align: center;
/* margin-bottom: 20px; */
@@ -88,6 +97,37 @@ button {
}
}
+/* Hide the native radio buttons */
+input[type="radio"] {
+ display: none;
+}
+
+/* Base style for the labels (buttons) */
+label {
+ background-color: #006eff; /* blue */
+ color: white;
+ padding: 10px 20px;
+ border-radius: 6px;
+ cursor: pointer;
+ margin-right: 8px;
+ transition: background-color 0.3s, transform 0.1s;
+ user-select: none;
+}
+
+/* Hover effect */
+label:hover {
+ background-color: #0057cc;
+}
+
+/* Active (clicked) effect */
+label:active {
+ transform: scale(0.97);
+}
+
+/* Selected (checked) radio button */
+input[type="radio"]:checked + label {
+ background-color: #00b33c; /* green when selected */
+}
/* Overlay for result display */
#overlay {
position: fixed;