tic / index.html
hiinikhil's picture
Add 3 files
15e9750 verified
Raw
History Blame Contribute Delete
11.3 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2-Player 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>
.cell {
transition: all 0.3s ease;
}
.cell:hover:not(.occupied) {
transform: scale(1.05);
box-shadow: 0 0 15px rgba(255, 255, 255, 0.3);
}
.winning-cell {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { background-color: rgba(134, 239, 172, 0.3); }
50% { background-color: rgba(134, 239, 172, 0.7); }
100% { background-color: rgba(134, 239, 172, 0.3); }
}
.modal {
transition: opacity 0.3s ease, transform 0.3s ease;
}
.modal.hidden {
opacity: 0;
transform: scale(0.9);
pointer-events: none;
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-center p-4">
<div class="max-w-md w-full">
<h1 class="text-4xl font-bold text-center mb-2 text-transparent bg-clip-text bg-gradient-to-r from-green-400 to-blue-500">
Tic Tac Toe
</h1>
<p class="text-center text-gray-400 mb-6">A classic game for two players</p>
<div class="bg-gray-800 rounded-xl p-6 shadow-2xl">
<!-- Player Info -->
<div class="flex justify-between mb-6">
<div id="player1" class="flex items-center space-x-2 bg-gray-700 px-4 py-2 rounded-lg transition-all duration-300">
<div class="w-8 h-8 rounded-full bg-green-500 flex items-center justify-center">
<i class="fas fa-times text-white"></i>
</div>
<span class="font-medium">Player X</span>
<div id="p1-score" class="ml-2 bg-gray-600 px-2 py-1 rounded text-sm">0</div>
</div>
<div id="player2" class="flex items-center space-x-2 px-4 py-2 rounded-lg transition-all duration-300">
<div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center">
<i class="far fa-circle text-white"></i>
</div>
<span class="font-medium">Player O</span>
<div id="p2-score" class="ml-2 bg-gray-600 px-2 py-1 rounded text-sm">0</div>
</div>
</div>
<!-- Game Board -->
<div class="grid grid-cols-3 gap-3 mb-6">
<!-- Cells will be generated by JavaScript -->
</div>
<!-- Game Controls -->
<div class="flex justify-between">
<button id="reset-btn" class="bg-gray-700 hover:bg-gray-600 px-4 py-2 rounded-lg transition">
<i class="fas fa-redo mr-2"></i>Reset Game
</button>
<button id="new-game-btn" class="bg-blue-600 hover:bg-blue-500 px-4 py-2 rounded-lg transition">
<i class="fas fa-plus-circle mr-2"></i>New Game
</button>
</div>
</div>
</div>
<!-- Winner Modal -->
<div id="winner-modal" class="modal fixed inset-0 flex items-center justify-center bg-black bg-opacity-70 z-50 hidden">
<div class="bg-gray-800 rounded-xl p-8 max-w-sm w-full mx-4 shadow-2xl text-center">
<h2 id="winner-text" class="text-3xl font-bold mb-4"></h2>
<p id="winner-message" class="text-gray-300 mb-6"></p>
<button id="close-modal-btn" class="bg-green-600 hover:bg-green-500 px-6 py-2 rounded-lg transition w-full">
Continue Playing
</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Game state
let board = ['', '', '', '', '', '', '', '', ''];
let currentPlayer = 'X';
let gameActive = true;
let scores = { X: 0, O: 0 };
let moveCount = 0;
// DOM elements
const boardElement = document.querySelector('.grid');
const player1Element = document.getElementById('player1');
const player2Element = document.getElementById('player2');
const p1ScoreElement = document.getElementById('p1-score');
const p2ScoreElement = document.getElementById('p2-score');
const resetBtn = document.getElementById('reset-btn');
const newGameBtn = document.getElementById('new-game-btn');
const winnerModal = document.getElementById('winner-modal');
const winnerText = document.getElementById('winner-text');
const winnerMessage = document.getElementById('winner-message');
const closeModalBtn = document.getElementById('close-modal-btn');
// Initialize the game board
function initializeBoard() {
boardElement.innerHTML = '';
for (let i = 0; i < 9; i++) {
const cell = document.createElement('div');
cell.className = 'cell bg-gray-700 h-24 md:h-32 flex items-center justify-center text-5xl font-bold rounded-lg cursor-pointer';
cell.dataset.index = i;
cell.addEventListener('click', () => handleCellClick(i));
boardElement.appendChild(cell);
}
}
// Handle cell click
function handleCellClick(index) {
if (!gameActive || board[index] !== '') return;
board[index] = currentPlayer;
moveCount++;
const cell = document.querySelector(`[data-index="${index}"]`);
cell.innerHTML = currentPlayer === 'X' ?
'<i class="fas fa-times text-green-500"></i>' :
'<i class="far fa-circle text-blue-500"></i>';
cell.classList.add('occupied');
if (checkWin()) {
handleWin();
return;
}
if (moveCount === 9) {
handleDraw();
return;
}
switchPlayer();
}
// Check for win
function checkWin() {
const winPatterns = [
[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
];
return winPatterns.some(pattern => {
const [a, b, c] = pattern;
if (board[a] && board[a] === board[b] && board[a] === board[c]) {
// Highlight winning cells
pattern.forEach(index => {
document.querySelector(`[data-index="${index}"]`).classList.add('winning-cell');
});
return true;
}
return false;
});
}
// Handle win
function handleWin() {
gameActive = false;
scores[currentPlayer]++;
updateScores();
winnerText.textContent = `Player ${currentPlayer} Wins!`;
winnerMessage.textContent = `Congratulations! Player ${currentPlayer} has won this round.`;
winnerText.className = currentPlayer === 'X' ? 'text-3xl font-bold mb-4 text-green-500' : 'text-3xl font-bold mb-4 text-blue-500';
winnerModal.classList.remove('hidden');
}
// Handle draw
function handleDraw() {
gameActive = false;
winnerText.textContent = "It's a Draw!";
winnerMessage.textContent = "The game ended in a tie. Try again!";
winnerText.className = 'text-3xl font-bold mb-4 text-yellow-500';
winnerModal.classList.remove('hidden');
}
// Switch player
function switchPlayer() {
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
updatePlayerUI();
}
// Update player UI
function updatePlayerUI() {
if (currentPlayer === 'X') {
player1Element.classList.add('bg-gray-700');
player2Element.classList.remove('bg-gray-700');
} else {
player1Element.classList.remove('bg-gray-700');
player2Element.classList.add('bg-gray-700');
}
}
// Update scores
function updateScores() {
p1ScoreElement.textContent = scores.X;
p2ScoreElement.textContent = scores.O;
}
// Reset game (keep scores)
function resetGame() {
board = ['', '', '', '', '', '', '', '', ''];
currentPlayer = 'X';
gameActive = true;
moveCount = 0;
initializeBoard();
updatePlayerUI();
// Remove winning cell highlights
document.querySelectorAll('.cell').forEach(cell => {
cell.classList.remove('winning-cell');
});
}
// New game (reset scores)
function newGame() {
scores = { X: 0, O: 0 };
updateScores();
resetGame();
}
// Event listeners
resetBtn.addEventListener('click', resetGame);
newGameBtn.addEventListener('click', newGame);
closeModalBtn.addEventListener('click', () => {
winnerModal.classList.add('hidden');
resetGame();
});
// Initialize the game
initializeBoard();
updatePlayerUI();
});
</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/tic" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>