From ccd65066f403588b7ad374a6ad7a4e0b0a903090 Mon Sep 17 00:00:00 2001 From: ThanushreeP Date: Wed, 22 Oct 2025 08:12:35 +0530 Subject: [PATCH 1/2] Add new mode player vs computer --- index.html | 49 +++++---- index.js | 300 ++++++++++++++++++++++++++++++++--------------------- style.css | 31 ++++++ 3 files changed, 244 insertions(+), 136 deletions(-) diff --git a/index.html b/index.html index 48ac21e..1042575 100644 --- a/index.html +++ b/index.html @@ -12,26 +12,37 @@

Tic-Tac-Toe

-

Player 1 Turn

-
-
-
-
-
-
-
-
-
-
-
- +
+ + + + + + + + + +

Player 1 Turn

+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+

Result

+ +
+
-
-
-

Result

- -
-
diff --git a/index.js b/index.js index f4b831f..94ed442 100644 --- a/index.js +++ b/index.js @@ -1,148 +1,214 @@ +let mode = "pvp"; // "pvp" = player vs player, "pvc" = player vs computer + var cube = document.getElementsByClassName("box"); var count = 0; let turn = 1; let green = "#5ef141"; +let humanVsComputer = true; // Set to true for human vs computer +let human = 0; // O +let computer = 1; // X +let humanMoves = []; +let computerMoves = []; +let magicSquare = [8, 1, 6, 3, 5, 7, 4, 9, 2]; // Magic square mapping function func(ths) { + if (ths.textContent) return; // Already clicked + + if (mode === "pvp") { + // Two-player logic + let playerTurn = document.getElementsByClassName("player_turn"); + ths.classList.add("click-disable"); + count++; + if (count % 2 === 0) { + ths.innerHTML = "X"; + ths.accessKey = 1; + turn = 1; + } else { + ths.innerHTML = "O"; + ths.accessKey = 0; + turn = 2; + } + playerTurn[0].innerHTML = turn === 1 ? "Player 2 Turn" : "Player 1 Turn"; + checkResult(); + } else if (mode === "pvc") { + // Player vs Computer logic + playerMove(ths); // your existing playerMove function + } +} + + +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) moves ths.innerHTML = "O"; ths.accessKey = 0; - turn = 2; + playerTurn[0].innerHTML = "Player 2 Turn"; // next turn + } else { + // Player 2 (X) moves + ths.innerHTML = "X"; + ths.accessKey = 1; + playerTurn[0].innerHTML = "Player 1 Turn"; // next turn } - 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; - } - //alert("X wins!! "); - document.getElementById("result").innerText = "Player 2 (X) wins!!"; + checkResult(); +} + + + +function playerMove(ths) { + // Human move + 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)) { + document.getElementById("result").innerText = "Human (O) wins!!"; + highlightWin(humanMoves); + on(); + return; + } + + if (count === 9) { + document.getElementById("result").innerText = "It's a Draw!!"; + on(); + 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)) { + document.getElementById("result").innerText = "Computer (X) wins!!"; + highlightWin(computerMoves); 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!!"; + return; + } + + if (count === 9) { + document.getElementById("result").innerText = "It's a Draw!!"; on(); + return; + } +} + +function findBestMove() { + // 1. Win if possible + for (let i = 0; i < 9; i++) { + if (!cube[i].textContent) { + let test = computerMoves.concat(magicSquare[i]); + if (checkWin(test)) return i; + } + } + // 2. Block human + for (let i = 0; i < 9; i++) { + if (!cube[i].textContent) { + let test = humanMoves.concat(magicSquare[i]); + if (checkWin(test)) return i; + } + } + // 3. Take center + if (!cube[4].textContent) return 4; + // 4. Take corners + const corners = [0, 2, 6, 8]; + for (let c of corners) { + if (!cube[c].textContent) return c; + } + // 5. Take any + for (let i = 0; i < 9; i++) { + if (!cube[i].textContent) return i; + } +} + +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; +} - 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; +function highlightWin(moves) { + // Highlight the winning combination + 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; } - } else if (a + b + c + d + e + f + g + h + i) { - //alert("Its a Draw !!!"); + } +} + +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] + ]; + + 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); + document.getElementById("result").innerText = "Player 2 (X) wins!!"; + on(); + return; + } else if (sum === 0) { + combo.forEach(idx => cube[idx].style.backgroundColor = green); + document.getElementById("result").innerText = "Player 1 (O) wins!!"; + on(); + return; + } + } + + if (keys.every(k => k === 0 || k === 1)) { document.getElementById("result").innerText = "It's a Draw!!"; on(); } } -function on(){ +function on() { document.getElementById("overlay").style.display = "block"; } -// 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() } - - if (confirm('Are you sure yo want to restart the game?')) { +//Reset the game +function restartGame(selectedMode) { + if (confirm('Are you sure you want to restart the game?')) { + mode = selectedMode; window.location.reload(); + } else { + // Revert the radio selection visually if user cancels + document.getElementById(mode).checked = true; } } - function reloadWindow() { window.location.reload(); } diff --git a/style.css b/style.css index 5485eff..e8f1093 100644 --- a/style.css +++ b/style.css @@ -88,6 +88,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; From 4ce174f7be3dd60645190b462f1e14619ed6b0e7 Mon Sep 17 00:00:00 2001 From: ThanushreeP Date: Wed, 22 Oct 2025 20:44:14 +0530 Subject: [PATCH 2/2] Updated changes --- index.html | 80 ++++++++++++++----------- index.js | 167 ++++++++++++++++++++++++----------------------------- style.css | 9 +++ 3 files changed, 131 insertions(+), 125 deletions(-) diff --git a/index.html b/index.html index 1042575..43b2ab2 100644 --- a/index.html +++ b/index.html @@ -1,41 +1,55 @@ - - - - - - Tic-Tac-Toe - - -

Tic-Tac-Toe

-
+ + + + + + Tic-Tac-Toe + + +

Tic-Tac-Toe

+
- - - + + + - - + + - -

Player 1 Turn

-
-
-
-
-
-
-
-
-
-
-
+

Player 1 Turn

+
+
+
+
+
+
+
+
+
+
+
+ +

Result

@@ -43,6 +57,6 @@

Player 1 Turn

- - + + diff --git a/index.js b/index.js index 94ed442..1ba24cd 100644 --- a/index.js +++ b/index.js @@ -1,66 +1,52 @@ let mode = "pvp"; // "pvp" = player vs player, "pvc" = player vs computer - -var cube = document.getElementsByClassName("box"); -var count = 0; +let cube = document.getElementsByClassName("box"); +let count = 0; let turn = 1; let green = "#5ef141"; -let humanVsComputer = true; // Set to true for human vs computer -let human = 0; // O -let computer = 1; // X 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") { - // Two-player logic - let playerTurn = document.getElementsByClassName("player_turn"); - ths.classList.add("click-disable"); - count++; - if (count % 2 === 0) { - ths.innerHTML = "X"; - ths.accessKey = 1; - turn = 1; - } else { - ths.innerHTML = "O"; - ths.accessKey = 0; - turn = 2; - } - playerTurn[0].innerHTML = turn === 1 ? "Player 2 Turn" : "Player 1 Turn"; - checkResult(); + twoPlayerMove(ths); } else if (mode === "pvc") { - // Player vs Computer logic - playerMove(ths); // your existing playerMove function + playerMove(ths); } } - function twoPlayerMove(ths) { let playerTurn = document.getElementsByClassName("player_turn"); ths.classList.add("click-disable"); count++; if (count % 2 !== 0) { - // Player 1 (O) moves + // Player 1 (O) ths.innerHTML = "O"; ths.accessKey = 0; - playerTurn[0].innerHTML = "Player 2 Turn"; // next turn + playerTurn[0].innerHTML = "Player 2 Turn"; } else { - // Player 2 (X) moves + // Player 2 (X) ths.innerHTML = "X"; ths.accessKey = 1; - playerTurn[0].innerHTML = "Player 1 Turn"; // next turn + playerTurn[0].innerHTML = "Player 1 Turn"; } checkResult(); } - - function playerMove(ths) { - // Human move ths.innerHTML = "O"; ths.accessKey = 0; ths.classList.add("click-disable"); @@ -69,15 +55,12 @@ function playerMove(ths) { count++; if (checkWin(humanMoves)) { - document.getElementById("result").innerText = "Human (O) wins!!"; - highlightWin(humanMoves); - on(); + endGame("Human (O) wins!!", humanMoves); return; } if (count === 9) { - document.getElementById("result").innerText = "It's a Draw!!"; - on(); + endGame("It's a Draw!!"); return; } @@ -93,65 +76,45 @@ function computerMove() { count++; if (checkWin(computerMoves)) { - document.getElementById("result").innerText = "Computer (X) wins!!"; - highlightWin(computerMoves); - on(); + endGame("Computer (X) wins!!", computerMoves); return; } if (count === 9) { - document.getElementById("result").innerText = "It's a Draw!!"; - on(); + endGame("It's a Draw!!"); return; } } function findBestMove() { - // 1. Win if possible for (let i = 0; i < 9; i++) { - if (!cube[i].textContent) { - let test = computerMoves.concat(magicSquare[i]); - if (checkWin(test)) return i; - } + if (!cube[i].textContent && checkWin(computerMoves.concat(magicSquare[i]))) return i; } - // 2. Block human for (let i = 0; i < 9; i++) { - if (!cube[i].textContent) { - let test = humanMoves.concat(magicSquare[i]); - if (checkWin(test)) return i; - } + if (!cube[i].textContent && checkWin(humanMoves.concat(magicSquare[i]))) return i; } - // 3. Take center if (!cube[4].textContent) return 4; - // 4. Take corners const corners = [0, 2, 6, 8]; - for (let c of corners) { - if (!cube[c].textContent) return c; - } - // 5. Take any - for (let i = 0; i < 9; i++) { - if (!cube[i].textContent) return i; - } + 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++) { + 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) { - // Highlight the winning combination 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] + [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) => { @@ -166,49 +129,69 @@ function highlightWin(moves) { } } +// 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] + [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 combos) { const sum = combo.reduce((a, idx) => a + keys[idx], 0); if (sum === 3) { combo.forEach(idx => cube[idx].style.backgroundColor = green); - document.getElementById("result").innerText = "Player 2 (X) wins!!"; - on(); + endGame("Player 2 (X) wins!!"); return; } else if (sum === 0) { combo.forEach(idx => cube[idx].style.backgroundColor = green); - document.getElementById("result").innerText = "Player 1 (O) wins!!"; - on(); + endGame("Player 1 (O) wins!!"); return; } } - if (keys.every(k => k === 0 || k === 1)) { - 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")); } -//Reset the game -function restartGame(selectedMode) { - if (confirm('Are you sure you want to restart the game?')) { - mode = selectedMode; - window.location.reload(); - } else { - // Revert the radio selection visually if user cancels - document.getElementById(mode).checked = true; +// 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 = ""; + }); + + // 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"; } + + // Re-enable mode selection + document.querySelectorAll('input[name="mode"]').forEach(r => r.disabled = false); } -function reloadWindow() { - window.location.reload(); -} + diff --git a/style.css b/style.css index e8f1093..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; */