jeevav62 commited on
Commit
7546ab1
·
verified ·
1 Parent(s): e327f8a

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +691 -600
index.html CHANGED
@@ -1,639 +1,730 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
 
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Neon Tic Tac Toe</title>
7
- <link rel="preconnect" href="https://fonts.googleapis.com">
8
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
- <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700&display=swap" rel="stylesheet">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- <style>
12
- :root {
13
- --bg-color: #121212;
14
- --card-bg: #1e1e1e;
15
- --text-color: #e0e0e0;
16
- --accent-x: #00f2ff; /* Cyan */
17
- --accent-o: #ff0055; /* Neon Red */
18
- --accent-draw: #ffd700; /* Gold */
19
- --grid-gap: 15px;
20
- --cell-size: 100px;
21
- }
22
-
23
- * {
24
- box-sizing: border-box;
25
- margin: 0;
26
- padding: 0;
27
- }
28
-
29
- body {
30
- font-family: 'Outfit', sans-serif;
31
- background-color: var(--bg-color);
32
- color: var(--text-color);
33
- display: flex;
34
- flex-direction: column;
35
- align-items: center;
36
- justify-content: center;
37
- min-height: 100vh;
38
- overflow-x: hidden;
39
- }
40
-
41
- /* --- Header --- */
42
- header {
43
- position: absolute;
44
- top: 20px;
45
- text-align: center;
46
- width: 100%;
47
- }
48
-
49
- h1 {
50
- font-weight: 700;
51
- letter-spacing: 2px;
52
- text-transform: uppercase;
53
- font-size: 2rem;
54
- background: linear-gradient(45deg, var(--accent-x), var(--accent-o));
55
- -webkit-background-clip: text;
56
- -webkit-text-fill-color: transparent;
57
- margin-bottom: 10px;
58
- }
59
-
60
- .anycoder-link {
61
- font-size: 0.8rem;
62
- color: #666;
63
- text-decoration: none;
64
- border-bottom: 1px solid transparent;
65
- transition: 0.3s;
66
- }
67
-
68
- .anycoder-link:hover {
69
- color: var(--accent-x);
70
- border-bottom: 1px solid var(--accent-x);
71
- }
72
-
73
- /* --- Containers --- */
74
- .container {
75
- width: 100%;
76
- max-width: 500px;
77
- padding: 20px;
78
- display: flex;
79
- flex-direction: column;
80
- align-items: center;
81
- }
82
-
83
- /* --- Setup Screen --- */
84
- #setup-screen {
85
- background: var(--card-bg);
86
- padding: 40px;
87
- border-radius: 20px;
88
- box-shadow: 0 10px 30px rgba(0,0,0,0.5);
89
- text-align: center;
90
- width: 100%;
91
- animation: fadeIn 0.5s ease-out;
92
- }
93
-
94
- .input-group {
95
- margin-bottom: 20px;
96
- text-align: left;
97
- }
98
-
99
- label {
100
- display: block;
101
- font-size: 0.9rem;
102
- margin-bottom: 8px;
103
- color: #aaa;
104
- }
105
-
106
- input {
107
- width: 100%;
108
- padding: 12px 15px;
109
- background: #2a2a2a;
110
- border: 2px solid transparent;
111
- border-radius: 8px;
112
- color: white;
113
- font-family: 'Outfit', sans-serif;
114
- font-size: 1rem;
115
- transition: 0.3s;
116
- outline: none;
117
- }
118
-
119
- input:focus {
120
- border-color: var(--accent-x);
121
- }
122
-
123
- .btn {
124
- background: linear-gradient(90deg, var(--accent-x), #00c2ff);
125
- color: #000;
126
- border: none;
127
- padding: 12px 30px;
128
- font-size: 1rem;
129
- font-weight: 700;
130
- border-radius: 50px;
131
- cursor: pointer;
132
- transition: transform 0.2s, box-shadow 0.2s;
133
- width: 100%;
134
- margin-top: 10px;
135
- text-transform: uppercase;
136
- letter-spacing: 1px;
137
- }
138
-
139
- .btn:hover {
140
- transform: translateY(-2px);
141
- box-shadow: 0 5px 15px rgba(0, 242, 255, 0.4);
142
- }
143
-
144
- .btn-secondary {
145
- background: transparent;
146
- border: 1px solid #444;
147
- color: #aaa;
148
- margin-top: 10px;
149
- }
150
-
151
- .btn-secondary:hover {
152
- background: #333;
153
- color: white;
154
- box-shadow: none;
155
- }
156
-
157
- /* --- Game Screen --- */
158
- #game-screen {
159
- display: none; /* Hidden by default */
160
- width: 100%;
161
- flex-direction: column;
162
- align-items: center;
163
- animation: slideUp 0.5s ease-out;
164
- }
165
-
166
- /* Scoreboard */
167
- .scoreboard {
168
- display: flex;
169
- justify-content: space-between;
170
- width: 100%;
171
- margin-bottom: 30px;
172
- background: var(--card-bg);
173
- padding: 15px;
174
- border-radius: 15px;
175
- box-shadow: 0 4px 10px rgba(0,0,0,0.3);
176
- }
177
-
178
- .player-score {
179
- text-align: center;
180
- flex: 1;
181
- }
182
-
183
- .player-score h3 {
184
- font-size: 0.9rem;
185
- color: #888;
186
- margin-bottom: 5px;
187
- }
188
-
189
- .score-num {
190
- font-size: 1.5rem;
191
- font-weight: 700;
192
- }
193
-
194
- .p-x .score-num { color: var(--accent-x); }
195
- .p-o .score-num { color: var(--accent-o); }
196
- .p-d .score-num { color: var(--accent-draw); }
197
-
198
- .active-turn {
199
- background: rgba(255,255,255,0.05);
200
- border-radius: 10px;
201
- }
202
-
203
- .turn-indicator {
204
- margin-bottom: 20px;
205
- font-size: 1.2rem;
206
- font-weight: 500;
207
- }
208
-
209
- .turn-text span {
210
- font-weight: 700;
211
- }
212
-
213
- /* The Grid */
214
- .board {
215
- display: grid;
216
- grid-template-columns: repeat(3, 1fr);
217
- gap: var(--grid-gap);
218
- margin-bottom: 30px;
219
- }
220
-
221
- .cell {
222
- width: var(--cell-size);
223
- height: var(--cell-size);
224
- background: var(--card-bg);
225
- border-radius: 15px;
226
- display: flex;
227
- align-items: center;
228
- justify-content: center;
229
- font-size: 3rem;
230
- font-weight: 700;
231
- cursor: pointer;
232
- transition: all 0.2s ease;
233
- box-shadow: 0 4px 6px rgba(0,0,0,0.2);
234
- }
235
-
236
- .cell:hover:not(.taken) {
237
- background: #2a2a2a;
238
- transform: scale(1.02);
239
- }
240
-
241
- .cell.x { color: var(--accent-x); text-shadow: 0 0 10px rgba(0, 242, 255, 0.5); }
242
- .cell.o { color: var(--accent-o); text-shadow: 0 0 10px rgba(255, 0, 85, 0.5); }
243
-
244
- /* Animations */
245
- @keyframes pop {
246
- 0% { transform: scale(0); }
247
- 80% { transform: scale(1.1); }
248
- 100% { transform: scale(1); }
249
- }
250
-
251
- .cell.animate {
252
- animation: pop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
253
- }
254
-
255
- @keyframes fadeIn {
256
- from { opacity: 0; }
257
- to { opacity: 1; }
258
- }
259
-
260
- @keyframes slideUp {
261
- from { transform: translateY(50px); opacity: 0; }
262
- to { transform: translateY(0); opacity: 1; }
263
- }
264
-
265
- /* Game Over Modal */
266
- .modal {
267
- position: fixed;
268
- top: 0;
269
- left: 0;
270
- width: 100%;
271
- height: 100%;
272
- background: rgba(0,0,0,0.8);
273
- display: flex;
274
- justify-content: center;
275
- align-items: center;
276
- z-index: 100;
277
- opacity: 0;
278
- pointer-events: none;
279
- transition: opacity 0.3s;
280
- backdrop-filter: blur(5px);
281
- }
282
-
283
- .modal.show {
284
- opacity: 1;
285
- pointer-events: all;
286
- }
287
-
288
- .modal-content {
289
- background: var(--card-bg);
290
- padding: 40px;
291
- border-radius: 20px;
292
- text-align: center;
293
- transform: scale(0.8);
294
- transition: transform 0.3s;
295
- border: 1px solid #333;
296
- }
297
-
298
- .modal.show .modal-content {
299
- transform: scale(1);
300
- }
301
-
302
- .modal h2 {
303
- font-size: 2rem;
304
- margin-bottom: 10px;
305
- }
306
-
307
- .modal p {
308
- margin-bottom: 30px;
309
- color: #aaa;
310
- }
311
-
312
- /* Responsive adjustments */
313
- @media (max-width: 400px) {
314
- :root {
315
- --cell-size: 80px;
316
- --grid-gap: 10px;
317
- }
318
- }
319
- </style>
320
  </head>
 
321
  <body>
322
 
323
- <header>
324
- <h1>Tic Tac Toe</h1>
325
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">Built with anycoder</a>
326
- </header>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
 
328
- <div class="container">
329
- <!-- SETUP SCREEN -->
330
- <div id="setup-screen">
331
- <h2 style="margin-bottom: 25px;">Enter Players</h2>
332
-
333
- <div class="input-group">
334
- <label for="p1-name">Player X Name</label>
335
- <input type="text" id="p1-name" placeholder="Player X" maxlength="12">
336
- </div>
337
-
338
- <div class="input-group">
339
- <label for="p2-name">Player O Name</label>
340
- <input type="text" id="p2-name" placeholder="Player O" maxlength="12">
341
- </div>
342
-
343
- <button class="btn" onclick="startGame()">Start Game</button>
344
- <button class="btn btn-secondary" onclick="resetHistory()">Reset History</button>
345
  </div>
346
 
347
- <!-- GAME SCREEN -->
348
- <div id="game-screen">
349
- <!-- Scoreboard -->
350
- <div class="scoreboard">
351
- <div class="player-score p-x" id="score-x-container">
352
- <h3 id="p1-display">Player X</h3>
353
- <div class="score-num" id="score-wins-x">0</div>
354
- <div style="font-size: 0.7rem; color: #666;">Wins</div>
355
- </div>
356
-
357
- <div class="player-score p-d">
358
- <h3>DRAWS</h3>
359
- <div class="score-num" id="score-draws">0</div>
360
- </div>
361
-
362
- <div class="player-score p-o" id="score-o-container">
363
- <h3 id="p2-display">Player O</h3>
364
- <div class="score-num" id="score-wins-o">0</div>
365
- <div style="font-size: 0.7rem; color: #666;">Wins</div>
366
- </div>
367
- </div>
368
-
369
- <div class="turn-indicator">
370
- <div class="turn-text">Current Turn: <span id="current-turn-text" style="color: var(--accent-x)">Player X</span></div>
371
- </div>
372
-
373
- <div class="board" id="board">
374
- <!-- Cells generated by JS -->
375
- </div>
376
-
377
- <button class="btn btn-secondary" style="width: auto; padding: 10px 20px;" onclick="quitGame()">Quit Game</button>
378
  </div>
379
- </div>
380
 
381
- <!-- RESULT MODAL -->
382
- <div id="result-modal" class="modal">
383
- <div class="modal-content">
384
- <h2 id="modal-title">Winner!</h2>
385
- <p id="modal-message">Player X Wins!</p>
386
- <button class="btn" onclick="nextRound()">Next Round</button>
387
- <button class="btn btn-secondary" onclick="quitGame()">Main Menu</button>
388
  </div>
389
- </div>
390
 
391
- <script>
392
- // Game State
393
- let currentPlayer = 'X';
394
- let gameActive = false;
395
- let gameState = ["", "", "", "", "", "", "", "", ""];
396
- let player1Name = "Player X";
397
- let player2Name = "Player O";
398
-
399
- // Stats Storage
400
- let stats = {
401
- 'default_X': { wins: 0, losses: 0 },
402
- 'default_O': { wins: 0, losses: 0 },
403
- 'draws': 0
404
- };
405
-
406
- // DOM Elements
407
- const setupScreen = document.getElementById('setup-screen');
408
- const gameScreen = document.getElementById('game-screen');
409
- const boardElement = document.getElementById('board');
410
- const modal = document.getElementById('result-modal');
411
-
412
- // Winning Combinations
413
- const winningConditions = [
414
- [0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows
415
- [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns
416
- [0, 4, 8], [2, 4, 6] // Diagonals
417
- ];
418
-
419
- // Initialize
420
- loadStats();
421
- createBoard();
422
-
423
- function createBoard() {
424
- boardElement.innerHTML = "";
425
- for (let i = 0; i < 9; i++) {
426
- const cell = document.createElement('div');
427
- cell.classList.add('cell');
428
- cell.setAttribute('data-index', i);
429
- cell.addEventListener('click', handleCellClick);
430
- boardElement.appendChild(cell);
431
- }
432
- }
433
-
434
- function startGame() {
435
- const p1Input = document.getElementById('p1-name').value.trim();
436
- const p2Input = document.getElementById('p2-name').value.trim();
437
 
438
- player1Name = p1Input ? p1Input : "Player X";
439
- player2Name = p2Input ? p2Input : "Player O";
 
440
 
441
- // Save custom names to local storage keys for persistence
442
- // Simplify keys for this demo: using fixed keys for X and O positions
443
- // In a real app, you'd map IDs to names.
444
- // Here we just reset the current session stats.
445
-
446
- setupScreen.style.display = 'none';
447
- gameScreen.style.display = 'flex';
448
-
449
- updateScoreboardUI();
450
- handlePlayerTurnChange();
451
-
452
- gameActive = true;
453
- currentPlayer = 'X';
454
- }
455
-
456
- function handleCellClick(clickedCellEvent) {
457
- const clickedCell = clickedCellEvent.target;
458
- const clickedCellIndex = parseInt(clickedCell.getAttribute('data-index'));
459
-
460
- if (gameState[clickedCellIndex] !== "" || !gameActive) {
461
- return;
462
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
 
464
- handleCellPlayed(clickedCell, clickedCellIndex);
465
- handleResultValidation();
466
- }
467
 
468
- function handleCellPlayed(clickedCell, clickedCellIndex) {
469
- gameState[clickedCellIndex] = currentPlayer;
470
- clickedCell.innerHTML = currentPlayer;
471
- clickedCell.classList.add('taken');
472
- clickedCell.classList.add(currentPlayer.toLowerCase());
473
-
474
- // Add pop animation
475
- clickedCell.classList.add('animate');
476
- setTimeout(() => clickedCell.classList.remove('animate'), 300);
477
  }
478
 
479
- function handleResultValidation() {
480
- let roundWon = false;
481
- for (let i = 0; i <= 7; i++) {
482
- const winCondition = winningConditions[i];
483
- let a = gameState[winCondition[0]];
484
- let b = gameState[winCondition[1]];
485
- let c = gameState[winCondition[2]];
486
-
487
- if (a === '' || b === '' || c === '') {
488
- continue;
489
- }
490
- if (a === b && b === c) {
491
- roundWon = true;
492
- break;
493
- }
494
- }
495
-
496
- if (roundWon) {
497
- endGame(false); // false means not a draw
498
- return;
499
- }
500
 
501
- let roundDraw = !gameState.includes("");
502
- if (roundDraw) {
503
- endGame(true); // true means draw
504
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  }
506
-
507
- handlePlayerTurnChange();
508
- }
509
-
510
- function handlePlayerTurnChange() {
511
- currentPlayer = currentPlayer === "X" ? "O" : "X";
512
- const turnText = document.getElementById('current-turn-text');
513
- turnText.innerText = currentPlayer === 'X' ? player1Name : player2Name;
514
- turnText.style.color = currentPlayer === 'X' ? 'var(--accent-x)' : 'var(--accent-o)';
515
-
516
- // Highlight active player in scoreboard
517
- if(currentPlayer === 'X') {
518
- document.getElementById('score-x-container').classList.add('active-turn');
519
- document.getElementById('score-o-container').classList.remove('active-turn');
520
- } else {
521
- document.getElementById('score-x-container').classList.remove('active-turn');
522
- document.getElementById('score-o-container').classList.add('active-turn');
523
  }
524
  }
525
 
526
- function endGame(isDraw) {
527
- gameActive = false;
528
- const modalTitle = document.getElementById('modal-title');
529
- const modalMsg = document.getElementById('modal-message');
530
-
531
- // Update Stats Logic
532
- if (isDraw) {
533
- stats['draws']++;
534
- modalTitle.innerText = "Draw!";
535
- modalTitle.style.color = "var(--accent-draw)";
536
- modalMsg.innerText = `It's a tie between ${player1Name} and ${player2Name}`;
537
- } else {
538
- if (currentPlayer === 'X') {
539
- stats['p1_wins'] = (stats['p1_wins'] || 0) + 1;
540
- // p1 losses implies p2 wins
541
- stats['p2_losses'] = (stats['p2_losses'] || 0) + 1;
542
- } else {
543
- stats['p2_wins'] = (stats['p2_wins'] || 0) + 1;
544
- stats['p1_losses'] = (stats['p1_losses'] || 0) + 1;
545
- }
546
-
547
- const winnerName = currentPlayer === 'X' ? player1Name : player2Name;
548
- modalTitle.innerText = "Winner!";
549
- modalTitle.style.color = currentPlayer === 'X' ? "var(--accent-x)" : "var(--accent-o)";
550
- modalMsg.innerText = `${winnerName} takes the round!`;
551
- }
552
-
553
- saveStats();
554
- updateScoreboardUI();
555
-
556
- // Show Modal
557
- setTimeout(() => {
558
- modal.classList.add('show');
559
- }, 500);
560
  }
561
 
562
- function nextRound() {
563
- modal.classList.remove('show');
564
- gameState = ["", "", "", "", "", "", "", "", ""];
565
- gameActive = true;
566
- currentPlayer = 'X';
567
-
568
- // Reset board UI
569
- document.querySelectorAll('.cell').forEach(cell => {
570
- cell.innerHTML = "";
571
- cell.classList.remove('x', 'o', 'taken');
572
- });
573
-
574
- handlePlayerTurnChange();
575
  }
576
 
577
- function quitGame() {
578
- modal.classList.remove('show');
579
- gameScreen.style.display = 'none';
580
- setupScreen.style.display = 'block';
581
-
582
- // Reset Board
583
- gameState = ["", "", "", "", "", "", "", "", ""];
584
- document.querySelectorAll('.cell').forEach(cell => {
585
- cell.innerHTML = "";
586
- cell.classList.remove('x', 'o', 'taken');
587
- });
588
- }
589
 
590
- // --- Stats Management ---
 
 
 
591
 
592
- function updateScoreboardUI() {
593
- // Update Names
594
- document.getElementById('p1-display').innerText = player1Name;
595
- document.getElementById('p2-display').innerText = player2Name;
596
-
597
- // Update Counts
598
- // We are tracking wins generally in this session based on who was X or O
599
- // For a persistent history across name changes, we usually use IDs,
600
- // but here we just show "X Wins" and "O Wins" based on the current session logic
601
- // or if we want history to persist by name, we need to store an object.
602
-
603
- // Let's implement session specific tracking
604
- let xWins = stats[`x_session_${player1Name}`] || 0;
605
- let oWins = stats[`o_session_${player2Name}`] || 0;
606
-
607
- // Actually, let's just use the global counters for simplicity in this single file:
608
- // Wins for whoever played X in this specific setup
609
- document.getElementById('score-wins-x').innerText = stats['p1_wins'] || 0;
610
- document.getElementById('score-wins-o').innerText = stats['p2_wins'] || 0;
611
- document.getElementById('score-draws').innerText = stats['draws'] || 0;
612
- }
613
-
614
- function saveStats() {
615
- localStorage.setItem('ttt_stats', JSON.stringify(stats));
616
  }
 
617
 
618
- function loadStats() {
619
- const saved = localStorage.getItem('ttt_stats');
620
- if (saved) {
621
- stats = JSON.parse(saved);
 
 
 
 
 
 
 
 
 
 
622
  }
 
 
 
 
 
 
623
  }
624
 
625
- function resetHistory() {
626
- if(confirm("Are you sure you want to clear all game history?")) {
627
- stats = {
628
- 'p1_wins': 0, 'p1_losses': 0,
629
- 'p2_wins': 0, 'p2_losses': 0,
630
- 'draws': 0
631
- };
632
- saveStats();
633
- alert("History reset!");
634
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
635
  }
636
-
637
- </script>
638
  </body>
639
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
+
4
  <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Neon Glass Tic Tac Toe</title>
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700;900&display=swap" rel="stylesheet">
11
+
12
+ <style>
13
+ /* --- CSS VARIABLES & THEME --- */
14
+ :root {
15
+ --bg-color: #0f0c29;
16
+ --accent-x: #00f2ff;
17
+ /* Cyan */
18
+ --accent-o: #ff0055;
19
+ /* Neon Red */
20
+ --accent-draw: #ffd700;
21
+ /* Gold */
22
+ --glass-bg: rgba(255, 255, 255, 0.05);
23
+ --glass-border: rgba(255, 255, 255, 0.1);
24
+ --glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
25
+ --grid-gap: 15px;
26
+ --cell-size: 90px;
27
+ }
28
+
29
+ * {
30
+ box-sizing: border-box;
31
+ margin: 0;
32
+ padding: 0;
33
+ }
34
+
35
+ body {
36
+ font-family: 'Outfit', sans-serif;
37
+ color: white;
38
+ min-height: 100vh;
39
+ display: flex;
40
+ flex-direction: column;
41
+ align-items: center;
42
+ justify-content: center;
43
+ overflow-x: hidden;
44
+ /* Animated Deep Space Background */
45
+ background: linear-gradient(125deg, #0f0c29, #302b63, #24243e);
46
+ background-size: 400% 400%;
47
+ animation: gradientBG 15s ease infinite;
48
+ }
49
+
50
+ @keyframes gradientBG {
51
+ 0% { background-position: 0% 50%; }
52
+ 50% { background-position: 100% 50%; }
53
+ 100% { background-position: 0% 50%; }
54
+ }
55
+
56
+ /* --- Floating Background Orbs (Decor) --- */
57
+ .orb {
58
+ position: fixed;
59
+ border-radius: 50%;
60
+ filter: blur(80px);
61
+ z-index: -1;
62
+ opacity: 0.6;
63
+ animation: floatOrb 10s infinite alternate;
64
+ }
65
+ .orb-1 { top: 10%; left: 10%; width: 300px; height: 300px; background: var(--accent-x); opacity: 0.15; }
66
+ .orb-2 { bottom: 10%; right: 10%; width: 250px; height: 250px; background: var(--accent-o); opacity: 0.15; animation-delay: -5s; }
67
+
68
+ @keyframes floatOrb {
69
+ 0% { transform: translate(0, 0); }
70
+ 100% { transform: translate(30px, 50px); }
71
+ }
72
+
73
+ /* --- Header --- */
74
+ header {
75
+ position: absolute;
76
+ top: 30px;
77
+ text-align: center;
78
+ width: 100%;
79
+ z-index: 10;
80
+ }
81
+
82
+ h1 {
83
+ font-weight: 900;
84
+ letter-spacing: 4px;
85
+ text-transform: uppercase;
86
+ font-size: 2.5rem;
87
+ margin-bottom: 10px;
88
+ /* Neon Text Effect */
89
+ text-shadow:
90
+ 0 0 10px rgba(0, 242, 255, 0.5),
91
+ 0 0 20px rgba(0, 242, 255, 0.3),
92
+ 0 0 40px rgba(0, 242, 255, 0.1);
93
+ background: linear-gradient(180deg, #fff, #aaa);
94
+ -webkit-background-clip: text;
95
+ -webkit-text-fill-color: transparent;
96
+ }
97
+
98
+ .anycoder-link {
99
+ font-size: 0.9rem;
100
+ color: rgba(255, 255, 255, 0.6);
101
+ text-decoration: none;
102
+ border-bottom: 1px solid rgba(255, 255, 255, 0.3);
103
+ transition: 0.3s;
104
+ padding-bottom: 2px;
105
+ }
106
+
107
+ .anycoder-link:hover {
108
+ color: white;
109
+ border-bottom: 1px solid white;
110
+ text-shadow: 0 0 10px white;
111
+ }
112
+
113
+ /* --- Main Container --- */
114
+ .container {
115
+ width: 100%;
116
+ max-width: 500px;
117
+ padding: 20px;
118
+ display: flex;
119
+ flex-direction: column;
120
+ align-items: center;
121
+ z-index: 1;
122
+ }
123
+
124
+ /* --- Glassmorphism Card Base Class --- */
125
+ .glass-card {
126
+ background: var(--glass-bg);
127
+ backdrop-filter: blur(12px);
128
+ -webkit-backdrop-filter: blur(12px);
129
+ border: 1px solid var(--glass-border);
130
+ box-shadow: var(--glass-shadow);
131
+ border-radius: 24px;
132
+ }
133
+
134
+ /* --- Setup Screen --- */
135
+ #setup-screen {
136
+ padding: 40px;
137
+ width: 100%;
138
+ animation: fadeIn 0.8s ease-out;
139
+ text-align: center;
140
+ }
141
+
142
+ .input-group {
143
+ margin-bottom: 25px;
144
+ text-align: left;
145
+ }
146
+
147
+ label {
148
+ display: block;
149
+ font-size: 0.85rem;
150
+ font-weight: 700;
151
+ margin-bottom: 8px;
152
+ color: rgba(255, 255, 255, 0.8);
153
+ letter-spacing: 1px;
154
+ text-transform: uppercase;
155
+ }
156
+
157
+ input {
158
+ width: 100%;
159
+ padding: 15px;
160
+ background: rgba(0, 0, 0, 0.2);
161
+ border: 2px solid transparent;
162
+ border-radius: 12px;
163
+ color: white;
164
+ font-family: 'Outfit', sans-serif;
165
+ font-size: 1.1rem;
166
+ transition: 0.3s;
167
+ outline: none;
168
+ }
169
+
170
+ input::placeholder {
171
+ color: rgba(255, 255, 255, 0.3);
172
+ }
173
+
174
+ input:focus {
175
+ border-color: var(--accent-x);
176
+ background: rgba(0, 0, 0, 0.4);
177
+ box-shadow: 0 0 15px rgba(0, 242, 255, 0.2);
178
+ }
179
+
180
+ /* --- Buttons --- */
181
+ .btn {
182
+ background: linear-gradient(90deg, var(--accent-x), #00a8ff);
183
+ color: #000;
184
+ border: none;
185
+ padding: 15px 30px;
186
+ font-size: 1rem;
187
+ font-weight: 700;
188
+ border-radius: 50px;
189
+ cursor: pointer;
190
+ transition: all 0.3s ease;
191
+ width: 100%;
192
+ margin-top: 15px;
193
+ text-transform: uppercase;
194
+ letter-spacing: 2px;
195
+ box-shadow: 0 0 20px rgba(0, 242, 255, 0.3);
196
+ }
197
+
198
+ .btn:hover {
199
+ transform: translateY(-3px) scale(1.02);
200
+ box-shadow: 0 0 30px rgba(0, 242, 255, 0.6);
201
+ }
202
+
203
+ .btn:active {
204
+ transform: scale(0.98);
205
+ }
206
+
207
+ .btn-secondary {
208
+ background: transparent;
209
+ border: 2px solid rgba(255, 255, 255, 0.2);
210
+ color: rgba(255, 255, 255, 0.8);
211
+ box-shadow: none;
212
+ }
213
+
214
+ .btn-secondary:hover {
215
+ background: rgba(255, 255, 255, 0.1);
216
+ border-color: rgba(255, 255, 255, 0.5);
217
+ color: white;
218
+ box-shadow: 0 0 15px rgba(255, 255, 255, 0.2);
219
+ }
220
+
221
+ /* --- Game Screen --- */
222
+ #game-screen {
223
+ display: none;
224
+ width: 100%;
225
+ flex-direction: column;
226
+ align-items: center;
227
+ animation: slideUp 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);
228
+ }
229
+
230
+ /* Scoreboard */
231
+ .scoreboard {
232
+ display: flex;
233
+ justify-content: space-between;
234
+ width: 100%;
235
+ margin-bottom: 30px;
236
+ padding: 20px;
237
+ }
238
+
239
+ .player-score {
240
+ text-align: center;
241
+ flex: 1;
242
+ padding: 10px;
243
+ border-radius: 15px;
244
+ transition: 0.3s;
245
+ background: rgba(0,0,0,0.2);
246
+ }
247
+
248
+ .player-score h3 {
249
+ font-size: 0.8rem;
250
+ color: rgba(255, 255, 255, 0.6);
251
+ margin-bottom: 5px;
252
+ text-transform: uppercase;
253
+ letter-spacing: 1px;
254
+ }
255
+
256
+ .score-num {
257
+ font-size: 2rem;
258
+ font-weight: 900;
259
+ text-shadow: 0 2px 10px rgba(0,0,0,0.5);
260
+ }
261
+
262
+ .p-x .score-num { color: var(--accent-x); text-shadow: 0 0 10px rgba(0, 242, 255, 0.4); }
263
+ .p-o .score-num { color: var(--accent-o); text-shadow: 0 0 10px rgba(255, 0, 85, 0.4); }
264
+ .p-d .score-num { color: var(--accent-draw); }
265
+
266
+ .active-turn {
267
+ background: rgba(255, 255, 255, 0.15);
268
+ border: 1px solid rgba(255, 255, 255, 0.2);
269
+ transform: scale(1.05);
270
+ }
271
+
272
+ .turn-indicator {
273
+ margin-bottom: 25px;
274
+ font-size: 1.3rem;
275
+ font-weight: 300;
276
+ text-shadow: 0 2px 4px rgba(0,0,0,0.5);
277
+ }
278
 
279
+ .turn-indicator span {
280
+ font-weight: 700;
281
+ letter-spacing: 1px;
282
+ }
283
+
284
+ /* The Grid */
285
+ .board {
286
+ display: grid;
287
+ grid-template-columns: repeat(3, 1fr);
288
+ gap: var(--grid-gap);
289
+ margin-bottom: 30px;
290
+ padding: 20px;
291
+ background: rgba(0, 0, 0, 0.2);
292
+ border-radius: 24px;
293
+ }
294
+
295
+ .cell {
296
+ width: var(--cell-size);
297
+ height: var(--cell-size);
298
+ background: rgba(255, 255, 255, 0.03);
299
+ border: 1px solid rgba(255, 255, 255, 0.05);
300
+ border-radius: 18px;
301
+ display: flex;
302
+ align-items: center;
303
+ justify-content: center;
304
+ font-size: 3.5rem;
305
+ font-weight: 700;
306
+ cursor: pointer;
307
+ transition: all 0.2s ease;
308
+ }
309
+
310
+ .cell:hover:not(.taken) {
311
+ background: rgba(255, 255, 255, 0.1);
312
+ transform: scale(1.05);
313
+ border-color: rgba(255, 255, 255, 0.3);
314
+ }
315
+
316
+ .cell.x {
317
+ color: var(--accent-x);
318
+ text-shadow: 0 0 15px rgba(0, 242, 255, 0.6);
319
+ }
320
+
321
+ .cell.o {
322
+ color: var(--accent-o);
323
+ text-shadow: 0 0 15px rgba(255, 0, 85, 0.6);
324
+ }
325
+
326
+ /* Animations */
327
+ @keyframes pop {
328
+ 0% { transform: scale(0); opacity: 0; }
329
+ 70% { transform: scale(1.2); }
330
+ 100% { transform: scale(1); opacity: 1; }
331
+ }
332
+
333
+ .cell.animate {
334
+ animation: pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
335
+ }
336
+
337
+ @keyframes fadeIn {
338
+ from { opacity: 0; transform: translateY(20px); }
339
+ to { opacity: 1; transform: translateY(0); }
340
+ }
341
+
342
+ @keyframes slideUp {
343
+ from { transform: translateY(100px); opacity: 0; }
344
+ to { transform: translateY(0); opacity: 1; }
345
+ }
346
+
347
+ /* Game Over Modal */
348
+ .modal {
349
+ position: fixed;
350
+ top: 0;
351
+ left: 0;
352
+ width: 100%;
353
+ height: 100%;
354
+ background: rgba(0, 0, 0, 0.6);
355
+ backdrop-filter: blur(5px);
356
+ display: flex;
357
+ justify-content: center;
358
+ align-items: center;
359
+ z-index: 100;
360
+ opacity: 0;
361
+ pointer-events: none;
362
+ transition: opacity 0.3s;
363
+ }
364
+
365
+ .modal.show {
366
+ opacity: 1;
367
+ pointer-events: all;
368
+ }
369
+
370
+ .modal-content {
371
+ background: rgba(20, 20, 20, 0.85);
372
+ backdrop-filter: blur(20px);
373
+ padding: 50px;
374
+ border-radius: 30px;
375
+ text-align: center;
376
+ border: 1px solid rgba(255, 255, 255, 0.1);
377
+ transform: scale(0.8);
378
+ transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
379
+ box-shadow: 0 20px 50px rgba(0,0,0,0.5);
380
+ max-width: 90%;
381
+ }
382
+
383
+ .modal.show .modal-content {
384
+ transform: scale(1);
385
+ }
386
+
387
+ .modal h2 {
388
+ font-size: 3rem;
389
+ margin-bottom: 15px;
390
+ text-transform: uppercase;
391
+ font-weight: 900;
392
+ }
393
+
394
+ .modal p {
395
+ margin-bottom: 40px;
396
+ font-size: 1.2rem;
397
+ color: rgba(255, 255, 255, 0.7);
398
+ }
399
+
400
+ .modal-buttons {
401
+ display: flex;
402
+ gap: 15px;
403
+ flex-direction: column;
404
+ }
405
+
406
+ /* Responsive adjustments */
407
+ @media (max-width: 500px) {
408
+ :root {
409
+ --cell-size: 75px;
410
+ }
411
+ h1 { font-size: 2rem; }
412
+ #setup-screen, .board { padding: 20px; }
413
+ }
414
+ </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  </head>
416
+
417
  <body>
418
 
419
+ <!-- Background Decor -->
420
+ <div class="orb orb-1"></div>
421
+ <div class="orb orb-2"></div>
422
+
423
+ <header>
424
+ <h1>Tic Tac Toe</h1>
425
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">Built with
426
+ anycoder</a>
427
+ </header>
428
+
429
+ <div class="container">
430
+ <!-- SETUP SCREEN -->
431
+ <div id="setup-screen" class="glass-card">
432
+ <h2 style="margin-bottom: 30px; font-weight: 300;">Enter Players</h2>
433
+
434
+ <div class="input-group">
435
+ <label for="p1-name">Player X</label>
436
+ <input type="text" id="p1-name" placeholder="Enter name..." maxlength="12">
437
+ </div>
438
+
439
+ <div class="input-group">
440
+ <label for="p2-name">Player O</label>
441
+ <input type="text" id="p2-name" placeholder="Enter name..." maxlength="12">
442
+ </div>
443
+
444
+ <button class="btn" onclick="startGame()">Start Game</button>
445
+ <button class="btn btn-secondary" onclick="resetHistory()">Reset History</button>
446
+ </div>
447
 
448
+ <!-- GAME SCREEN -->
449
+ <div id="game-screen">
450
+ <!-- Scoreboard -->
451
+ <div class="scoreboard glass-card">
452
+ <div class="player-score p-x" id="score-x-container">
453
+ <h3 id="p1-display">Player X</h3>
454
+ <div class="score-num" id="score-wins-x">0</div>
455
+ <div style="font-size: 0.7rem; opacity: 0.5;">WINS</div>
 
 
 
 
 
 
 
 
 
456
  </div>
457
 
458
+ <div class="player-score p-d">
459
+ <h3>DRAWS</h3>
460
+ <div class="score-num" id="score-draws">0</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
  </div>
 
462
 
463
+ <div class="player-score p-o" id="score-o-container">
464
+ <h3 id="p2-display">Player O</h3>
465
+ <div class="score-num" id="score-wins-o">0</div>
466
+ <div style="font-size: 0.7rem; opacity: 0.5;">WINS</div>
 
 
 
467
  </div>
468
+ </div>
469
 
470
+ <div class="turn-indicator">
471
+ Current Turn: <span id="current-turn-text">Player X</span>
472
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
 
474
+ <div class="board glass-card" id="board">
475
+ <!-- Cells generated by JS -->
476
+ </div>
477
 
478
+ <button class="btn btn-secondary" style="width: auto; min-width: 150px;" onclick="quitGame()">Quit Game</button>
479
+ </div>
480
+ </div>
481
+
482
+ <!-- RESULT MODAL -->
483
+ <div id="result-modal" class="modal">
484
+ <div class="modal-content glass-card">
485
+ <h2 id="modal-title">Winner!</h2>
486
+ <p id="modal-message">Player X Wins!</p>
487
+ <div class="modal-buttons">
488
+ <button class="btn" onclick="nextRound()">Next Round</button>
489
+ <button class="btn btn-secondary" onclick="quitGame()">Main Menu</button>
490
+ </div>
491
+ </div>
492
+ </div>
493
+
494
+ <script>
495
+ // Game State
496
+ let currentPlayer = 'X';
497
+ let gameActive = false;
498
+ let gameState = ["", "", "", "", "", "", "", "", ""];
499
+ let player1Name = "Player X";
500
+ let player2Name = "Player O";
501
+
502
+ // Stats Storage
503
+ let stats = {
504
+ 'p1_wins': 0,
505
+ 'p2_wins': 0,
506
+ 'draws': 0
507
+ };
508
+
509
+ // DOM Elements
510
+ const setupScreen = document.getElementById('setup-screen');
511
+ const gameScreen = document.getElementById('game-screen');
512
+ const boardElement = document.getElementById('board');
513
+ const modal = document.getElementById('result-modal');
514
+ const modalTitle = document.getElementById('modal-title');
515
+ const modalMsg = document.getElementById('modal-message');
516
+
517
+ // Winning Combinations
518
+ const winningConditions = [
519
+ [0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows
520
+ [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns
521
+ [0, 4, 8], [2, 4, 6] // Diagonals
522
+ ];
523
+
524
+ // Initialize
525
+ loadStats();
526
+ createBoard();
527
+
528
+ function createBoard() {
529
+ boardElement.innerHTML = "";
530
+ for (let i = 0; i < 9; i++) {
531
+ const cell = document.createElement('div');
532
+ cell.classList.add('cell');
533
+ cell.setAttribute('data-index', i);
534
+ cell.addEventListener('click', handleCellClick);
535
+ boardElement.appendChild(cell);
536
+ }
537
+ }
538
+
539
+ function startGame() {
540
+ const p1Input = document.getElementById('p1-name').value.trim();
541
+ const p2Input = document.getElementById('p2-name').value.trim();
542
+
543
+ player1Name = p1Input ? p1Input : "Player X";
544
+ player2Name = p2Input ? p2Input : "Player O";
545
+
546
+ setupScreen.style.display = 'none';
547
+ gameScreen.style.display = 'flex';
548
+
549
+ updateScoreboardUI();
550
+ handlePlayerTurnChange();
551
+
552
+ gameActive = true;
553
+ currentPlayer = 'X';
554
+ }
555
 
556
+ function handleCellClick(clickedCellEvent) {
557
+ const clickedCell = clickedCellEvent.target;
558
+ const clickedCellIndex = parseInt(clickedCell.getAttribute('data-index'));
559
 
560
+ if (gameState[clickedCellIndex] !== "" || !gameActive) {
561
+ return;
 
 
 
 
 
 
 
562
  }
563
 
564
+ handleCellPlayed(clickedCell, clickedCellIndex);
565
+ handleResultValidation();
566
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
 
568
+ function handleCellPlayed(clickedCell, clickedCellIndex) {
569
+ gameState[clickedCellIndex] = currentPlayer;
570
+ clickedCell.innerHTML = currentPlayer;
571
+ clickedCell.classList.add('taken');
572
+ clickedCell.classList.add(currentPlayer.toLowerCase());
573
+
574
+ // Add pop animation
575
+ clickedCell.classList.add('animate');
576
+ }
577
+
578
+ function handleResultValidation() {
579
+ let roundWon = false;
580
+ for (let i = 0; i <= 7; i++) {
581
+ const winCondition = winningConditions[i];
582
+ let a = gameState[winCondition[0]];
583
+ let b = gameState[winCondition[1]];
584
+ let c = gameState[winCondition[2]];
585
+
586
+ if (a === '' || b === '' || c === '') {
587
+ continue;
588
  }
589
+ if (a === b && b === c) {
590
+ roundWon = true;
591
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  }
593
  }
594
 
595
+ if (roundWon) {
596
+ endGame(false);
597
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
598
  }
599
 
600
+ let roundDraw = !gameState.includes("");
601
+ if (roundDraw) {
602
+ endGame(true);
603
+ return;
 
 
 
 
 
 
 
 
 
604
  }
605
 
606
+ handlePlayerTurnChange();
607
+ }
 
 
 
 
 
 
 
 
 
 
608
 
609
+ function handlePlayerTurnChange() {
610
+ currentPlayer = currentPlayer === "X" ? "O" : "X";
611
+ const turnText = document.getElementById('current-turn-text');
612
+ const turnContainer = document.querySelector('.turn-indicator');
613
 
614
+ turnText.innerText = currentPlayer === 'X' ? player1Name : player2Name;
615
+
616
+ // Dynamic color for turn text
617
+ turnText.style.color = currentPlayer === 'X' ? 'var(--accent-x)' : 'var(--accent-o)';
618
+ turnText.style.textShadow = currentPlayer === 'X'
619
+ ? '0 0 10px var(--accent-x)'
620
+ : '0 0 10px var(--accent-o)';
621
+
622
+ // Highlight active player in scoreboard
623
+ const pX = document.getElementById('score-x-container');
624
+ const pO = document.getElementById('score-o-container');
625
+
626
+ if(currentPlayer === 'X') {
627
+ pX.classList.add('active-turn');
628
+ pO.classList.remove('active-turn');
629
+ } else {
630
+ pX.classList.remove('active-turn');
631
+ pO.classList.add('active-turn');
 
 
 
 
 
 
632
  }
633
+ }
634
 
635
+ function endGame(isDraw) {
636
+ gameActive = false;
637
+
638
+ if (isDraw) {
639
+ stats['draws']++;
640
+ modalTitle.innerText = "Draw!";
641
+ modalTitle.style.color = "var(--accent-draw)";
642
+ modalTitle.style.textShadow = "0 0 15px var(--accent-draw)";
643
+ modalMsg.innerText = `It's a tie!`;
644
+ } else {
645
+ if (currentPlayer === 'X') {
646
+ stats['p1_wins']++;
647
+ } else {
648
+ stats['p2_wins']++;
649
  }
650
+
651
+ const winnerName = currentPlayer === 'X' ? player1Name : player2Name;
652
+ modalTitle.innerText = "Winner!";
653
+ modalTitle.style.color = currentPlayer === 'X' ? "var(--accent-x)" : "var(--accent-o)";
654
+ modalTitle.style.textShadow = `0 0 20px ${currentPlayer === 'X' ? 'var(--accent-x)' : 'var(--accent-o)'}`;
655
+ modalMsg.innerText = `${winnerName} takes the round!`;
656
  }
657
 
658
+ saveStats();
659
+ updateScoreboardUI();
660
+
661
+ // Show Modal
662
+ setTimeout(() => {
663
+ modal.classList.add('show');
664
+ }, 300);
665
+ }
666
+
667
+ function nextRound() {
668
+ modal.classList.remove('show');
669
+ gameState = ["", "", "", "", "", "", "", "", ""];
670
+ gameActive = true;
671
+ currentPlayer = 'X';
672
+
673
+ // Reset board UI
674
+ document.querySelectorAll('.cell').forEach(cell => {
675
+ cell.innerHTML = "";
676
+ cell.classList.remove('x', 'o', 'taken', 'animate');
677
+ });
678
+
679
+ handlePlayerTurnChange();
680
+ }
681
+
682
+ function quitGame() {
683
+ modal.classList.remove('show');
684
+ gameScreen.style.display = 'none';
685
+ setupScreen.style.display = 'block';
686
+
687
+ // Reset Board
688
+ gameState = ["", "", "", "", "", "", "", "", ""];
689
+ document.querySelectorAll('.cell').forEach(cell => {
690
+ cell.innerHTML = "";
691
+ cell.classList.remove('x', 'o', 'taken');
692
+ });
693
+ }
694
+
695
+ // --- Stats Management ---
696
+
697
+ function updateScoreboardUI() {
698
+ document.getElementById('p1-display').innerText = player1Name;
699
+ document.getElementById('p2-display').innerText = player2Name;
700
+
701
+ document.getElementById('score-wins-x').innerText = stats['p1_wins'];
702
+ document.getElementById('score-wins-o').innerText = stats['p2_wins'];
703
+ document.getElementById('score-draws').innerText = stats['draws'];
704
+ }
705
+
706
+ function saveStats() {
707
+ localStorage.setItem('ttt_stats', JSON.stringify(stats));
708
+ }
709
+
710
+ function loadStats() {
711
+ const saved = localStorage.getItem('ttt_stats');
712
+ if (saved) {
713
+ stats = JSON.parse(saved);
714
+ }
715
+ }
716
+
717
+ function resetHistory() {
718
+ if(confirm("Are you sure you want to clear all game history?")) {
719
+ stats = {
720
+ 'p1_wins': 0,
721
+ 'p2_wins': 0,
722
+ 'draws': 0
723
+ };
724
+ saveStats();
725
+ alert("History reset!");
726
  }
727
+ }
728
+ </script>
729
  </body>
730
  </html>