| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Tic Tac Toe - Hard Mode</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <style> |
| .cell { |
| width: 100px; |
| height: 100px; |
| transition: all 0.3s ease; |
| } |
| .cell:hover:not(.occupied) { |
| background-color: #f3f4f6; |
| } |
| .winning-cell { |
| background-color: #dcfce7; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-100 min-h-screen flex flex-col items-center justify-center"> |
| <div class="text-center mb-8"> |
| <h1 class="text-3xl font-bold text-gray-800 mb-2">Tic Tac Toe</h1> |
| <p class="text-gray-600">You (X) vs Computer (O) - Hard Mode</p> |
| <div id="status" class="mt-4 text-lg font-semibold text-gray-700">Your turn (X)</div> |
| </div> |
|
|
| <div class="grid grid-cols-3 gap-2 mb-8"> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="0"></div> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="1"></div> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="2"></div> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="3"></div> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="4"></div> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="5"></div> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="6"></div> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="7"></div> |
| <div class="cell border-2 border-gray-300 rounded-lg flex items-center justify-center text-4xl font-bold cursor-pointer" data-index="8"></div> |
| </div> |
|
|
| <button id="reset" class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition">Reset Game</button> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', () => { |
| const cells = document.querySelectorAll('.cell'); |
| const status = document.getElementById('status'); |
| const resetBtn = document.getElementById('reset'); |
| let board = Array(9).fill(null); |
| let currentPlayer = 'X'; |
| let gameActive = true; |
| |
| |
| const winPatterns = [ |
| [0, 1, 2], [3, 4, 5], [6, 7, 8], |
| [0, 3, 6], [1, 4, 7], [2, 5, 8], |
| [0, 4, 8], [2, 4, 6] |
| ]; |
| |
| |
| function handleCellClick(e) { |
| const index = e.target.dataset.index; |
| |
| if (board[index] !== null || !gameActive || currentPlayer !== 'X') return; |
| |
| makeMove(index, 'X'); |
| |
| if (checkWinner()) return; |
| if (isBoardFull()) return; |
| |
| |
| currentPlayer = 'O'; |
| status.textContent = "Computer's turn (O)"; |
| |
| setTimeout(() => { |
| const bestMove = findBestMove(); |
| makeMove(bestMove, 'O'); |
| |
| checkWinner(); |
| isBoardFull(); |
| currentPlayer = 'X'; |
| status.textContent = "Your turn (X)"; |
| }, 500); |
| } |
| |
| |
| function makeMove(index, player) { |
| board[index] = player; |
| cells[index].textContent = player; |
| cells[index].classList.add('occupied'); |
| } |
| |
| |
| function checkWinner() { |
| for (const pattern of winPatterns) { |
| const [a, b, c] = pattern; |
| if (board[a] && board[a] === board[b] && board[a] === board[c]) { |
| gameActive = false; |
| cells[a].classList.add('winning-cell'); |
| cells[b].classList.add('winning-cell'); |
| cells[c].classList.add('winning-cell'); |
| |
| const winner = board[a] === 'X' ? 'You win!' : 'Computer wins!'; |
| status.textContent = winner; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| function isBoardFull() { |
| if (!board.includes(null)) { |
| gameActive = false; |
| status.textContent = "Game ended in a tie!"; |
| return true; |
| } |
| return false; |
| } |
| |
| |
| function findBestMove() { |
| let bestScore = -Infinity; |
| let bestMove = null; |
| |
| for (let i = 0; i < 9; i++) { |
| if (board[i] === null) { |
| board[i] = 'O'; |
| let score = minimax(board, 0, false); |
| board[i] = null; |
| |
| if (score > bestScore) { |
| bestScore = score; |
| bestMove = i; |
| } |
| } |
| } |
| return bestMove; |
| } |
| |
| function minimax(board, depth, isMaximizing) { |
| |
| const winner = checkTerminal(); |
| if (winner !== null) { |
| return winner === 'O' ? 10 - depth : |
| winner === 'X' ? depth - 10 : 0; |
| } |
| |
| if (isMaximizing) { |
| let bestScore = -Infinity; |
| for (let i = 0; i < 9; i++) { |
| if (board[i] === null) { |
| board[i] = 'O'; |
| let score = minimax(board, depth + 1, false); |
| board[i] = null; |
| bestScore = Math.max(score, bestScore); |
| } |
| } |
| return bestScore; |
| } else { |
| let bestScore = Infinity; |
| for (let i = 0; i < 9; i++) { |
| if (board[i] === null) { |
| board[i] = 'X'; |
| let score = minimax(board, depth + 1, true); |
| board[i] = null; |
| bestScore = Math.min(score, bestScore); |
| } |
| } |
| return bestScore; |
| } |
| } |
| |
| function checkTerminal() { |
| for (const pattern of winPatterns) { |
| const [a, b, c] = pattern; |
| if (board[a] && board[a] === board[b] && board[a] === board[c]) { |
| return board[a]; |
| } |
| } |
| return board.includes(null) ? null : 'tie'; |
| } |
| |
| |
| function resetGame() { |
| board = Array(9).fill(null); |
| gameActive = true; |
| currentPlayer = 'X'; |
| status.textContent = "Your turn (X)"; |
| |
| cells.forEach(cell => { |
| cell.textContent = ''; |
| cell.classList.remove('occupied', 'winning-cell'); |
| }); |
| } |
| |
| |
| cells.forEach(cell => cell.addEventListener('click', handleCellClick)); |
| resetBtn.addEventListener('click', resetGame); |
| }); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=hiinikhil/toe" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |