Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Neon Tic-Tac-Toe</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap'); | |
| body { | |
| font-family: 'Orbitron', sans-serif; | |
| background-color: #0f0f1a; | |
| overflow: hidden; | |
| perspective: 1000px; | |
| height: 100vh; | |
| width: 100vw; | |
| } | |
| .glass-box { | |
| background: rgba(15, 15, 30, 0.2); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); | |
| border-radius: 10px; | |
| transition: all 0.3s ease; | |
| } | |
| .cell { | |
| position: relative; | |
| transition: all 0.3s ease; | |
| transform-style: preserve-3d; | |
| } | |
| .cell:hover { | |
| transform: translateZ(20px); | |
| box-shadow: 0 0 20px rgba(0, 255, 255, 0.7); | |
| } | |
| .cell::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| border-radius: 8px; | |
| background: linear-gradient(135deg, rgba(0, 255, 255, 0.1), rgba(255, 0, 255, 0.1)); | |
| opacity: 0; | |
| transition: opacity 0.3s ease; | |
| } | |
| .cell:hover::before { | |
| opacity: 1; | |
| } | |
| .x-symbol { | |
| color: #ff2d75; | |
| text-shadow: 0 0 10px #ff2d75, 0 0 20px #ff2d75; | |
| } | |
| .o-symbol { | |
| color: #00ffff; | |
| text-shadow: 0 0 10px #00ffff, 0 0 20px #00ffff; | |
| } | |
| .winning-cell { | |
| animation: pulse 0.5s infinite alternate; | |
| } | |
| @keyframes pulse { | |
| 0% { | |
| transform: scale(1) translateZ(0); | |
| box-shadow: 0 0 10px currentColor; | |
| } | |
| 100% { | |
| transform: scale(1.1) translateZ(10px); | |
| box-shadow: 0 0 30px currentColor; | |
| } | |
| } | |
| .confetti { | |
| position: absolute; | |
| width: 10px; | |
| height: 10px; | |
| background-color: currentColor; | |
| opacity: 0; | |
| } | |
| .bg-pattern { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| z-index: -1; | |
| opacity: 0.1; | |
| } | |
| .bg-symbol { | |
| position: absolute; | |
| font-size: 1rem; | |
| opacity: 0; | |
| animation: float 15s linear infinite; | |
| pointer-events: none; | |
| } | |
| @keyframes float { | |
| 0% { | |
| transform: translateY(100vh) rotate(0deg); | |
| opacity: 0; | |
| } | |
| 10% { | |
| opacity: 0.3; | |
| } | |
| 90% { | |
| opacity: 0.3; | |
| } | |
| 100% { | |
| transform: translateY(-100px) rotate(360deg); | |
| opacity: 0; | |
| } | |
| } | |
| .explosion { | |
| position: absolute; | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| background-color: white; | |
| opacity: 0; | |
| } | |
| .smoke { | |
| position: absolute; | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| background-color: rgba(255, 255, 255, 0.3); | |
| opacity: 0; | |
| } | |
| .neon-text { | |
| text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #00ffff, 0 0 20px #00ffff; | |
| } | |
| .neon-border { | |
| box-shadow: 0 0 10px #00ffff, 0 0 20px #00ffff inset; | |
| } | |
| </style> | |
| </head> | |
| <body class="h-screen w-screen flex flex-col items-center justify-center p-4 overflow-hidden"> | |
| <div class="bg-pattern" id="bgPattern"></div> | |
| <div class="text-center mb-8"> | |
| <h1 class="text-4xl md:text-5xl font-bold text-white neon-text mb-2">NEON TIC-TAC-TOE</h1> | |
| <div class="flex justify-center space-x-8 text-white text-xl"> | |
| <div class="glass-box px-4 py-2 rounded-lg"> | |
| <span class="text-pink-500">X</span> Wins: <span id="xWins" class="text-white">0</span> | |
| </div> | |
| <div class="glass-box px-4 py-2 rounded-lg"> | |
| <span class="text-cyan-400">O</span> Wins: <span id="oWins" class="text-white">0</span> | |
| </div> | |
| <div class="glass-box px-4 py-2 rounded-lg"> | |
| <span class="text-yellow-400">Draws:</span> <span id="draws" class="text-white">0</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="relative"> | |
| <div id="gameBoard" class="grid grid-cols-3 gap-4 glass-box p-6 rounded-xl neon-border"> | |
| <!-- Cells will be generated by JavaScript --> | |
| </div> | |
| </div> | |
| <div class="mt-8"> | |
| <button id="resetBtn" class="glass-box px-6 py-3 rounded-lg text-white text-lg font-bold hover:bg-cyan-500 hover:text-white transition-all duration-300 hover:scale-105"> | |
| RESET GAME | |
| </button> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Game state | |
| let board = ['', '', '', '', '', '', '', '', '']; | |
| let currentPlayer = 'X'; | |
| let gameActive = true; | |
| let xWins = 0; | |
| let oWins = 0; | |
| let draws = 0; | |
| // DOM elements | |
| const gameBoard = document.getElementById('gameBoard'); | |
| const xWinsElement = document.getElementById('xWins'); | |
| const oWinsElement = document.getElementById('oWins'); | |
| const drawsElement = document.getElementById('draws'); | |
| const resetBtn = document.getElementById('resetBtn'); | |
| const bgPattern = document.getElementById('bgPattern'); | |
| // Create background floating symbols | |
| createFloatingSymbols(); | |
| // Create game board cells | |
| createBoard(); | |
| // Create floating symbols in background | |
| function createFloatingSymbols() { | |
| for (let i = 0; i < 30; i++) { | |
| const symbol = document.createElement('div'); | |
| symbol.className = `bg-symbol ${Math.random() > 0.5 ? 'x-symbol' : 'o-symbol'}`; | |
| symbol.innerHTML = Math.random() > 0.5 ? '×' : '○'; | |
| symbol.style.left = `${Math.random() * 100}%`; | |
| symbol.style.animationDuration = `${10 + Math.random() * 20}s`; | |
| symbol.style.animationDelay = `${Math.random() * 5}s`; | |
| bgPattern.appendChild(symbol); | |
| } | |
| } | |
| // Create game board | |
| function createBoard() { | |
| gameBoard.innerHTML = ''; | |
| for (let i = 0; i < 9; i++) { | |
| const cell = document.createElement('div'); | |
| cell.className = 'cell w-20 h-20 md:w-24 md:h-24 flex items-center justify-center text-5xl glass-box cursor-pointer'; | |
| cell.setAttribute('data-index', i); | |
| cell.addEventListener('click', handleCellClick); | |
| // Add hover effect that throws symbols | |
| cell.addEventListener('mousemove', (e) => { | |
| if (cell.textContent !== '' || !gameActive) return; | |
| const rect = cell.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| const symbol = document.createElement('div'); | |
| symbol.className = `absolute text-xl ${currentPlayer === 'X' ? 'x-symbol' : 'o-symbol'}`; | |
| symbol.textContent = currentPlayer === 'X' ? '×' : '○'; | |
| symbol.style.left = `${x}px`; | |
| symbol.style.top = `${y}px`; | |
| symbol.style.opacity = '0'; | |
| symbol.style.transform = 'scale(0)'; | |
| symbol.style.transition = 'all 0.5s ease-out'; | |
| cell.appendChild(symbol); | |
| setTimeout(() => { | |
| symbol.style.opacity = '0.7'; | |
| symbol.style.transform = 'scale(1) translate(-50%, -50%)'; | |
| setTimeout(() => { | |
| symbol.style.opacity = '0'; | |
| symbol.style.transform = 'scale(0.5) translate(-50%, -50%)'; | |
| setTimeout(() => { | |
| cell.removeChild(symbol); | |
| }, 500); | |
| }, 300); | |
| }, 10); | |
| }); | |
| gameBoard.appendChild(cell); | |
| } | |
| } | |
| // Handle cell click | |
| function handleCellClick(e) { | |
| const cell = e.target; | |
| const index = parseInt(cell.getAttribute('data-index')); | |
| if (board[index] !== '' || !gameActive) return; | |
| // Update board | |
| board[index] = currentPlayer; | |
| cell.textContent = currentPlayer; | |
| cell.classList.add(currentPlayer === 'X' ? 'x-symbol' : 'o-symbol'); | |
| // Add animation | |
| cell.style.transform = 'translateZ(30px)'; | |
| cell.style.boxShadow = `0 0 30px ${currentPlayer === 'X' ? '#ff2d75' : '#00ffff'}`; | |
| setTimeout(() => { | |
| cell.style.transform = 'translateZ(10px)'; | |
| cell.style.boxShadow = `0 0 20px ${currentPlayer === 'X' ? '#ff2d75' : '#00ffff'}`; | |
| }, 300); | |
| // Check for winner | |
| if (checkWinner()) { | |
| gameActive = false; | |
| celebrateWin(); | |
| return; | |
| } | |
| // Check for draw | |
| if (!board.includes('')) { | |
| gameActive = false; | |
| draws++; | |
| drawsElement.textContent = draws; | |
| setTimeout(() => { | |
| alert('Game ended in a draw!'); | |
| }, 500); | |
| return; | |
| } | |
| // Switch player | |
| currentPlayer = currentPlayer === 'X' ? 'O' : 'X'; | |
| // Add floating indicator | |
| const indicator = document.createElement('div'); | |
| indicator.className = `absolute -top-8 text-xl ${currentPlayer === 'X' ? 'x-symbol' : 'o-symbol'}`; | |
| indicator.textContent = currentPlayer === 'X' ? '×' : '○'; | |
| indicator.style.opacity = '0'; | |
| indicator.style.transform = 'translateY(20px)'; | |
| gameBoard.parentNode.appendChild(indicator); | |
| setTimeout(() => { | |
| indicator.style.opacity = '1'; | |
| indicator.style.transform = 'translateY(0)'; | |
| setTimeout(() => { | |
| indicator.style.opacity = '0'; | |
| indicator.style.transform = 'translateY(-20px)'; | |
| setTimeout(() => { | |
| gameBoard.parentNode.removeChild(indicator); | |
| }, 500); | |
| }, 1000); | |
| }, 10); | |
| } | |
| // Check for winner | |
| function checkWinner() { | |
| const winningCombos = [ | |
| [0, 1, 2], [3, 4, 5], [6, 7, 8], // rows | |
| [0, 3, 6], [1, 4, 7], [2, 5, 8], // columns | |
| [0, 4, 8], [2, 4, 6] // diagonals | |
| ]; | |
| for (let combo of winningCombos) { | |
| const [a, b, c] = combo; | |
| if (board[a] && board[a] === board[b] && board[a] === board[c]) { | |
| // Highlight winning cells | |
| document.querySelectorAll(`[data-index="${a}"], [data-index="${b}"], [data-index="${c}"]`).forEach(cell => { | |
| cell.classList.add('winning-cell'); | |
| }); | |
| // Update score | |
| if (board[a] === 'X') { | |
| xWins++; | |
| xWinsElement.textContent = xWins; | |
| } else { | |
| oWins++; | |
| oWinsElement.textContent = oWins; | |
| } | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // Celebrate win with confetti | |
| function celebrateWin() { | |
| const winner = currentPlayer; | |
| const color = winner === 'X' ? '#ff2d75' : '#00ffff'; | |
| for (let i = 0; i < 100; i++) { | |
| const confetti = document.createElement('div'); | |
| confetti.className = 'confetti'; | |
| confetti.style.backgroundColor = color; | |
| confetti.style.left = `${Math.random() * 100}%`; | |
| confetti.style.top = `${Math.random() * 100}%`; | |
| confetti.style.transform = `rotate(${Math.random() * 360}deg)`; | |
| const size = Math.random() * 10 + 5; | |
| confetti.style.width = `${size}px`; | |
| confetti.style.height = `${size}px`; | |
| if (Math.random() > 0.5) { | |
| confetti.style.borderRadius = '50%'; | |
| } | |
| document.body.appendChild(confetti); | |
| setTimeout(() => { | |
| confetti.style.opacity = '1'; | |
| confetti.style.transform = `translate(${Math.random() * 200 - 100}px, ${Math.random() * 200 + 100}px) rotate(${Math.random() * 360}deg)`; | |
| setTimeout(() => { | |
| confetti.style.opacity = '0'; | |
| setTimeout(() => { | |
| document.body.removeChild(confetti); | |
| }, 1000); | |
| }, 2000); | |
| }, i * 20); | |
| } | |
| // Add celebration text | |
| const celebration = document.createElement('div'); | |
| celebration.className = 'absolute inset-0 flex items-center justify-center pointer-events-none'; | |
| celebration.innerHTML = `<div class="text-6xl font-bold ${winner === 'X' ? 'x-symbol' : 'o-symbol'} opacity-0 transform scale(0)">${winner} WINS!</div>`; | |
| gameBoard.parentNode.appendChild(celebration); | |
| setTimeout(() => { | |
| celebration.firstChild.style.opacity = '1'; | |
| celebration.firstChild.style.transform = 'scale(1)'; | |
| setTimeout(() => { | |
| celebration.firstChild.style.opacity = '0'; | |
| celebration.firstChild.style.transform = 'scale(1.5)'; | |
| setTimeout(() => { | |
| gameBoard.parentNode.removeChild(celebration); | |
| }, 500); | |
| }, 2000); | |
| }, 100); | |
| } | |
| // Reset game | |
| resetBtn.addEventListener('click', () => { | |
| // Create explosion effect | |
| const cells = document.querySelectorAll('.cell'); | |
| cells.forEach(cell => { | |
| if (cell.textContent !== '') { | |
| // Create explosion particles | |
| for (let i = 0; i < 10; i++) { | |
| const particle = document.createElement('div'); | |
| particle.className = 'explosion'; | |
| particle.style.left = `${Math.random() * 80 + 10}%`; | |
| particle.style.top = `${Math.random() * 80 + 10}%`; | |
| particle.style.backgroundColor = cell.classList.contains('x-symbol') ? '#ff2d75' : '#00ffff'; | |
| cell.appendChild(particle); | |
| setTimeout(() => { | |
| particle.style.opacity = '1'; | |
| particle.style.transform = `translate(${Math.random() * 100 - 50}px, ${Math.random() * 100 - 50}px) scale(${Math.random() * 2 + 1})`; | |
| setTimeout(() => { | |
| particle.style.opacity = '0'; | |
| setTimeout(() => { | |
| if (cell.contains(particle)) { | |
| cell.removeChild(particle); | |
| } | |
| }, 500); | |
| }, 300); | |
| }, 10); | |
| } | |
| // Create smoke | |
| for (let i = 0; i < 5; i++) { | |
| const smoke = document.createElement('div'); | |
| smoke.className = 'smoke'; | |
| smoke.style.left = `${Math.random() * 80 + 10}%`; | |
| smoke.style.top = `${Math.random() * 80 + 10}%`; | |
| cell.appendChild(smoke); | |
| setTimeout(() => { | |
| smoke.style.opacity = '0.5'; | |
| smoke.style.transform = `translate(${Math.random() * 40 - 20}px, ${Math.random() * 40 - 20}px) scale(${Math.random() * 3 + 1})`; | |
| setTimeout(() => { | |
| smoke.style.opacity = '0'; | |
| setTimeout(() => { | |
| if (cell.contains(smoke)) { | |
| cell.removeChild(smoke); | |
| } | |
| }, 500); | |
| }, 1000); | |
| }, 10); | |
| } | |
| } | |
| }); | |
| // Reset game state after animation | |
| setTimeout(() => { | |
| board = ['', '', '', '', '', '', '', '', '']; | |
| currentPlayer = 'X'; | |
| gameActive = true; | |
| // Remove all winning cell classes | |
| document.querySelectorAll('.cell').forEach(cell => { | |
| cell.className = 'cell w-20 h-20 md:w-24 md:h-24 flex items-center justify-center text-5xl glass-box cursor-pointer'; | |
| cell.textContent = ''; | |
| }); | |
| // Create a new board (for visual refresh) | |
| createBoard(); | |
| }, 1000); | |
| }); | |
| }); | |
| </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=miiann/tic-toc-toe" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |