tic-toc-toe / index.html
miiann's picture
also add draw count - Initial Deployment
8dbc359 verified
<!DOCTYPE html>
<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>