anycoder-2e46baeb / index.html
jeevav62's picture
Upload folder using huggingface_hub
7546ab1 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Neon Glass Tic Tac Toe</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700;900&display=swap" rel="stylesheet">
<style>
/* --- CSS VARIABLES & THEME --- */
:root {
--bg-color: #0f0c29;
--accent-x: #00f2ff;
/* Cyan */
--accent-o: #ff0055;
/* Neon Red */
--accent-draw: #ffd700;
/* Gold */
--glass-bg: rgba(255, 255, 255, 0.05);
--glass-border: rgba(255, 255, 255, 0.1);
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
--grid-gap: 15px;
--cell-size: 90px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Outfit', sans-serif;
color: white;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow-x: hidden;
/* Animated Deep Space Background */
background: linear-gradient(125deg, #0f0c29, #302b63, #24243e);
background-size: 400% 400%;
animation: gradientBG 15s ease infinite;
}
@keyframes gradientBG {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* --- Floating Background Orbs (Decor) --- */
.orb {
position: fixed;
border-radius: 50%;
filter: blur(80px);
z-index: -1;
opacity: 0.6;
animation: floatOrb 10s infinite alternate;
}
.orb-1 { top: 10%; left: 10%; width: 300px; height: 300px; background: var(--accent-x); opacity: 0.15; }
.orb-2 { bottom: 10%; right: 10%; width: 250px; height: 250px; background: var(--accent-o); opacity: 0.15; animation-delay: -5s; }
@keyframes floatOrb {
0% { transform: translate(0, 0); }
100% { transform: translate(30px, 50px); }
}
/* --- Header --- */
header {
position: absolute;
top: 30px;
text-align: center;
width: 100%;
z-index: 10;
}
h1 {
font-weight: 900;
letter-spacing: 4px;
text-transform: uppercase;
font-size: 2.5rem;
margin-bottom: 10px;
/* Neon Text Effect */
text-shadow:
0 0 10px rgba(0, 242, 255, 0.5),
0 0 20px rgba(0, 242, 255, 0.3),
0 0 40px rgba(0, 242, 255, 0.1);
background: linear-gradient(180deg, #fff, #aaa);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.anycoder-link {
font-size: 0.9rem;
color: rgba(255, 255, 255, 0.6);
text-decoration: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
transition: 0.3s;
padding-bottom: 2px;
}
.anycoder-link:hover {
color: white;
border-bottom: 1px solid white;
text-shadow: 0 0 10px white;
}
/* --- Main Container --- */
.container {
width: 100%;
max-width: 500px;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
z-index: 1;
}
/* --- Glassmorphism Card Base Class --- */
.glass-card {
background: var(--glass-bg);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--glass-border);
box-shadow: var(--glass-shadow);
border-radius: 24px;
}
/* --- Setup Screen --- */
#setup-screen {
padding: 40px;
width: 100%;
animation: fadeIn 0.8s ease-out;
text-align: center;
}
.input-group {
margin-bottom: 25px;
text-align: left;
}
label {
display: block;
font-size: 0.85rem;
font-weight: 700;
margin-bottom: 8px;
color: rgba(255, 255, 255, 0.8);
letter-spacing: 1px;
text-transform: uppercase;
}
input {
width: 100%;
padding: 15px;
background: rgba(0, 0, 0, 0.2);
border: 2px solid transparent;
border-radius: 12px;
color: white;
font-family: 'Outfit', sans-serif;
font-size: 1.1rem;
transition: 0.3s;
outline: none;
}
input::placeholder {
color: rgba(255, 255, 255, 0.3);
}
input:focus {
border-color: var(--accent-x);
background: rgba(0, 0, 0, 0.4);
box-shadow: 0 0 15px rgba(0, 242, 255, 0.2);
}
/* --- Buttons --- */
.btn {
background: linear-gradient(90deg, var(--accent-x), #00a8ff);
color: #000;
border: none;
padding: 15px 30px;
font-size: 1rem;
font-weight: 700;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
width: 100%;
margin-top: 15px;
text-transform: uppercase;
letter-spacing: 2px;
box-shadow: 0 0 20px rgba(0, 242, 255, 0.3);
}
.btn:hover {
transform: translateY(-3px) scale(1.02);
box-shadow: 0 0 30px rgba(0, 242, 255, 0.6);
}
.btn:active {
transform: scale(0.98);
}
.btn-secondary {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.2);
color: rgba(255, 255, 255, 0.8);
box-shadow: none;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.5);
color: white;
box-shadow: 0 0 15px rgba(255, 255, 255, 0.2);
}
/* --- Game Screen --- */
#game-screen {
display: none;
width: 100%;
flex-direction: column;
align-items: center;
animation: slideUp 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
/* Scoreboard */
.scoreboard {
display: flex;
justify-content: space-between;
width: 100%;
margin-bottom: 30px;
padding: 20px;
}
.player-score {
text-align: center;
flex: 1;
padding: 10px;
border-radius: 15px;
transition: 0.3s;
background: rgba(0,0,0,0.2);
}
.player-score h3 {
font-size: 0.8rem;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 5px;
text-transform: uppercase;
letter-spacing: 1px;
}
.score-num {
font-size: 2rem;
font-weight: 900;
text-shadow: 0 2px 10px rgba(0,0,0,0.5);
}
.p-x .score-num { color: var(--accent-x); text-shadow: 0 0 10px rgba(0, 242, 255, 0.4); }
.p-o .score-num { color: var(--accent-o); text-shadow: 0 0 10px rgba(255, 0, 85, 0.4); }
.p-d .score-num { color: var(--accent-draw); }
.active-turn {
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.2);
transform: scale(1.05);
}
.turn-indicator {
margin-bottom: 25px;
font-size: 1.3rem;
font-weight: 300;
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
}
.turn-indicator span {
font-weight: 700;
letter-spacing: 1px;
}
/* The Grid */
.board {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--grid-gap);
margin-bottom: 30px;
padding: 20px;
background: rgba(0, 0, 0, 0.2);
border-radius: 24px;
}
.cell {
width: var(--cell-size);
height: var(--cell-size);
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 18px;
display: flex;
align-items: center;
justify-content: center;
font-size: 3.5rem;
font-weight: 700;
cursor: pointer;
transition: all 0.2s ease;
}
.cell:hover:not(.taken) {
background: rgba(255, 255, 255, 0.1);
transform: scale(1.05);
border-color: rgba(255, 255, 255, 0.3);
}
.cell.x {
color: var(--accent-x);
text-shadow: 0 0 15px rgba(0, 242, 255, 0.6);
}
.cell.o {
color: var(--accent-o);
text-shadow: 0 0 15px rgba(255, 0, 85, 0.6);
}
/* Animations */
@keyframes pop {
0% { transform: scale(0); opacity: 0; }
70% { transform: scale(1.2); }
100% { transform: scale(1); opacity: 1; }
}
.cell.animate {
animation: pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideUp {
from { transform: translateY(100px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
/* Game Over Modal */
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(5px);
display: flex;
justify-content: center;
align-items: center;
z-index: 100;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.modal.show {
opacity: 1;
pointer-events: all;
}
.modal-content {
background: rgba(20, 20, 20, 0.85);
backdrop-filter: blur(20px);
padding: 50px;
border-radius: 30px;
text-align: center;
border: 1px solid rgba(255, 255, 255, 0.1);
transform: scale(0.8);
transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
box-shadow: 0 20px 50px rgba(0,0,0,0.5);
max-width: 90%;
}
.modal.show .modal-content {
transform: scale(1);
}
.modal h2 {
font-size: 3rem;
margin-bottom: 15px;
text-transform: uppercase;
font-weight: 900;
}
.modal p {
margin-bottom: 40px;
font-size: 1.2rem;
color: rgba(255, 255, 255, 0.7);
}
.modal-buttons {
display: flex;
gap: 15px;
flex-direction: column;
}
/* Responsive adjustments */
@media (max-width: 500px) {
:root {
--cell-size: 75px;
}
h1 { font-size: 2rem; }
#setup-screen, .board { padding: 20px; }
}
</style>
</head>
<body>
<!-- Background Decor -->
<div class="orb orb-1"></div>
<div class="orb orb-2"></div>
<header>
<h1>Tic Tac Toe</h1>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">Built with
anycoder</a>
</header>
<div class="container">
<!-- SETUP SCREEN -->
<div id="setup-screen" class="glass-card">
<h2 style="margin-bottom: 30px; font-weight: 300;">Enter Players</h2>
<div class="input-group">
<label for="p1-name">Player X</label>
<input type="text" id="p1-name" placeholder="Enter name..." maxlength="12">
</div>
<div class="input-group">
<label for="p2-name">Player O</label>
<input type="text" id="p2-name" placeholder="Enter name..." maxlength="12">
</div>
<button class="btn" onclick="startGame()">Start Game</button>
<button class="btn btn-secondary" onclick="resetHistory()">Reset History</button>
</div>
<!-- GAME SCREEN -->
<div id="game-screen">
<!-- Scoreboard -->
<div class="scoreboard glass-card">
<div class="player-score p-x" id="score-x-container">
<h3 id="p1-display">Player X</h3>
<div class="score-num" id="score-wins-x">0</div>
<div style="font-size: 0.7rem; opacity: 0.5;">WINS</div>
</div>
<div class="player-score p-d">
<h3>DRAWS</h3>
<div class="score-num" id="score-draws">0</div>
</div>
<div class="player-score p-o" id="score-o-container">
<h3 id="p2-display">Player O</h3>
<div class="score-num" id="score-wins-o">0</div>
<div style="font-size: 0.7rem; opacity: 0.5;">WINS</div>
</div>
</div>
<div class="turn-indicator">
Current Turn: <span id="current-turn-text">Player X</span>
</div>
<div class="board glass-card" id="board">
<!-- Cells generated by JS -->
</div>
<button class="btn btn-secondary" style="width: auto; min-width: 150px;" onclick="quitGame()">Quit Game</button>
</div>
</div>
<!-- RESULT MODAL -->
<div id="result-modal" class="modal">
<div class="modal-content glass-card">
<h2 id="modal-title">Winner!</h2>
<p id="modal-message">Player X Wins!</p>
<div class="modal-buttons">
<button class="btn" onclick="nextRound()">Next Round</button>
<button class="btn btn-secondary" onclick="quitGame()">Main Menu</button>
</div>
</div>
</div>
<script>
// Game State
let currentPlayer = 'X';
let gameActive = false;
let gameState = ["", "", "", "", "", "", "", "", ""];
let player1Name = "Player X";
let player2Name = "Player O";
// Stats Storage
let stats = {
'p1_wins': 0,
'p2_wins': 0,
'draws': 0
};
// DOM Elements
const setupScreen = document.getElementById('setup-screen');
const gameScreen = document.getElementById('game-screen');
const boardElement = document.getElementById('board');
const modal = document.getElementById('result-modal');
const modalTitle = document.getElementById('modal-title');
const modalMsg = document.getElementById('modal-message');
// Winning Combinations
const winningConditions = [
[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
];
// Initialize
loadStats();
createBoard();
function createBoard() {
boardElement.innerHTML = "";
for (let i = 0; i < 9; i++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.setAttribute('data-index', i);
cell.addEventListener('click', handleCellClick);
boardElement.appendChild(cell);
}
}
function startGame() {
const p1Input = document.getElementById('p1-name').value.trim();
const p2Input = document.getElementById('p2-name').value.trim();
player1Name = p1Input ? p1Input : "Player X";
player2Name = p2Input ? p2Input : "Player O";
setupScreen.style.display = 'none';
gameScreen.style.display = 'flex';
updateScoreboardUI();
handlePlayerTurnChange();
gameActive = true;
currentPlayer = 'X';
}
function handleCellClick(clickedCellEvent) {
const clickedCell = clickedCellEvent.target;
const clickedCellIndex = parseInt(clickedCell.getAttribute('data-index'));
if (gameState[clickedCellIndex] !== "" || !gameActive) {
return;
}
handleCellPlayed(clickedCell, clickedCellIndex);
handleResultValidation();
}
function handleCellPlayed(clickedCell, clickedCellIndex) {
gameState[clickedCellIndex] = currentPlayer;
clickedCell.innerHTML = currentPlayer;
clickedCell.classList.add('taken');
clickedCell.classList.add(currentPlayer.toLowerCase());
// Add pop animation
clickedCell.classList.add('animate');
}
function handleResultValidation() {
let roundWon = false;
for (let i = 0; i <= 7; i++) {
const winCondition = winningConditions[i];
let a = gameState[winCondition[0]];
let b = gameState[winCondition[1]];
let c = gameState[winCondition[2]];
if (a === '' || b === '' || c === '') {
continue;
}
if (a === b && b === c) {
roundWon = true;
break;
}
}
if (roundWon) {
endGame(false);
return;
}
let roundDraw = !gameState.includes("");
if (roundDraw) {
endGame(true);
return;
}
handlePlayerTurnChange();
}
function handlePlayerTurnChange() {
currentPlayer = currentPlayer === "X" ? "O" : "X";
const turnText = document.getElementById('current-turn-text');
const turnContainer = document.querySelector('.turn-indicator');
turnText.innerText = currentPlayer === 'X' ? player1Name : player2Name;
// Dynamic color for turn text
turnText.style.color = currentPlayer === 'X' ? 'var(--accent-x)' : 'var(--accent-o)';
turnText.style.textShadow = currentPlayer === 'X'
? '0 0 10px var(--accent-x)'
: '0 0 10px var(--accent-o)';
// Highlight active player in scoreboard
const pX = document.getElementById('score-x-container');
const pO = document.getElementById('score-o-container');
if(currentPlayer === 'X') {
pX.classList.add('active-turn');
pO.classList.remove('active-turn');
} else {
pX.classList.remove('active-turn');
pO.classList.add('active-turn');
}
}
function endGame(isDraw) {
gameActive = false;
if (isDraw) {
stats['draws']++;
modalTitle.innerText = "Draw!";
modalTitle.style.color = "var(--accent-draw)";
modalTitle.style.textShadow = "0 0 15px var(--accent-draw)";
modalMsg.innerText = `It's a tie!`;
} else {
if (currentPlayer === 'X') {
stats['p1_wins']++;
} else {
stats['p2_wins']++;
}
const winnerName = currentPlayer === 'X' ? player1Name : player2Name;
modalTitle.innerText = "Winner!";
modalTitle.style.color = currentPlayer === 'X' ? "var(--accent-x)" : "var(--accent-o)";
modalTitle.style.textShadow = `0 0 20px ${currentPlayer === 'X' ? 'var(--accent-x)' : 'var(--accent-o)'}`;
modalMsg.innerText = `${winnerName} takes the round!`;
}
saveStats();
updateScoreboardUI();
// Show Modal
setTimeout(() => {
modal.classList.add('show');
}, 300);
}
function nextRound() {
modal.classList.remove('show');
gameState = ["", "", "", "", "", "", "", "", ""];
gameActive = true;
currentPlayer = 'X';
// Reset board UI
document.querySelectorAll('.cell').forEach(cell => {
cell.innerHTML = "";
cell.classList.remove('x', 'o', 'taken', 'animate');
});
handlePlayerTurnChange();
}
function quitGame() {
modal.classList.remove('show');
gameScreen.style.display = 'none';
setupScreen.style.display = 'block';
// Reset Board
gameState = ["", "", "", "", "", "", "", "", ""];
document.querySelectorAll('.cell').forEach(cell => {
cell.innerHTML = "";
cell.classList.remove('x', 'o', 'taken');
});
}
// --- Stats Management ---
function updateScoreboardUI() {
document.getElementById('p1-display').innerText = player1Name;
document.getElementById('p2-display').innerText = player2Name;
document.getElementById('score-wins-x').innerText = stats['p1_wins'];
document.getElementById('score-wins-o').innerText = stats['p2_wins'];
document.getElementById('score-draws').innerText = stats['draws'];
}
function saveStats() {
localStorage.setItem('ttt_stats', JSON.stringify(stats));
}
function loadStats() {
const saved = localStorage.getItem('ttt_stats');
if (saved) {
stats = JSON.parse(saved);
}
}
function resetHistory() {
if(confirm("Are you sure you want to clear all game history?")) {
stats = {
'p1_wins': 0,
'p2_wins': 0,
'draws': 0
};
saveStats();
alert("History reset!");
}
}
</script>
</body>
</html>