anycoder-27457fd7 / index.html
samirerty's picture
Upload folder using huggingface_hub
243eb7c verified
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>بازی دوز طنز | Neon Edition</title>
<!-- Importing Vazirmatn Font -->
<link href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css" rel="stylesheet"
type="text/css" />
<!-- Importing Font Awesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--bg-color: #05050a;
--container-bg: #10101a;
--accent-color: #2a2a40;
--neon-blue: #00f3ff;
--neon-pink: #ff00ff;
--neon-purple: #bc13fe;
--neon-green: #0aff0a;
--neon-yellow: #ffff00;
--text-color: #ffffff;
--shadow-intensity: 0 0 20px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Vazirmatn', sans-serif;
-webkit-tap-highlight-color: transparent;
}
body {
background-color: var(--bg-color);
background-image:
radial-gradient(circle at 20% 30%, rgba(0, 243, 255, 0.15) 0%, transparent 40%),
radial-gradient(circle at 80% 70%, rgba(255, 0, 255, 0.15) 0%, transparent 40%);
color: var(--text-color);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 20px;
overflow-x: hidden;
position: relative;
}
/* Add some floating background particles for humor */
.floating-object {
position: absolute;
font-size: 2rem;
animation: floatAround 10s infinite linear;
opacity: 0.2;
z-index: 0;
}
@keyframes floatAround {
0% {
transform: translate(0, 0) rotate(0deg);
}
25% {
transform: translate(20px, -50px) rotate(90deg);
}
50% {
transform: translate(-20px, -100px) rotate(180deg);
}
75% {
transform: translate(-50px, -20px) rotate(270deg);
}
100% {
transform: translate(0, 0) rotate(360deg);
}
}
/* Canvas for Confetti */
#confetti-canvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 999;
}
/* Header Section */
header {
text-align: center;
margin-bottom: 30px;
width: 100%;
max-width: 500px;
position: relative;
z-index: 10;
}
h1 {
font-size: 3.5rem;
margin-bottom: 10px;
text-transform: uppercase;
letter-spacing: 5px;
background: linear-gradient(90deg, var(--neon-blue), var(--neon-purple), var(--neon-pink));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: gradientShift 3s ease infinite;
text-shadow: 0 0 30px rgba(188, 19, 254, 0.3);
}
@keyframes gradientShift {
0% {
filter: hue-rotate(0deg);
}
50% {
filter: hue-rotate(45deg);
}
100% {
filter: hue-rotate(0deg);
}
}
.subtitle {
color: #a0a0a0;
font-size: 1.2rem;
letter-spacing: 1px;
margin-bottom: 20px;
}
.anycoder-link {
display: inline-block;
margin-top: 15px;
font-size: 0.9rem;
color: var(--neon-blue);
text-decoration: none;
transition: all 0.3s;
border: 1px solid var(--neon-blue);
padding: 8px 20px;
border-radius: 30px;
background: rgba(0, 243, 255, 0.1);
box-shadow: 0 0 10px rgba(0, 243, 255, 0.2);
}
.anycoder-link:hover {
background: var(--neon-blue);
color: #000;
box-shadow: 0 0 20px var(--neon-blue);
transform: translateY(-2px);
}
/* Score Board */
.scoreboard {
display: flex;
justify-content: space-between;
width: 100%;
max-width: 450px;
background-color: var(--container-bg);
padding: 20px;
border-radius: 25px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.1);
margin-bottom: 40px;
position: relative;
overflow: hidden;
}
.scoreboard::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(90deg, var(--neon-blue), var(--neon-pink));
}
.player-score {
text-align: center;
padding: 15px;
border-radius: 15px;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
flex: 1;
position: relative;
cursor: default;
/* Remove pointer */
}
.player-score.active {
background: rgba(255, 255, 255, 0.05);
box-shadow: 0 0 25px rgba(0, 243, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.player-score.active::after {
content: '-turn';
position: absolute;
bottom: -25px;
left: 50%;
transform: translateX(-50%);
font-size: 0.8rem;
color: var(--neon-blue);
font-weight: bold;
letter-spacing: 2px;
animation: bounceText 1s infinite alternate;
}
.player-score.o.active::after {
color: var(--neon-pink);
}
@keyframes bounceText {
from {
transform: translateX(-50%) translateY(0);
}
to {
transform: translateX(-50%) translateY(-5px);
}
}
.player-name {
font-size: 1.6rem;
font-weight: 800;
margin-bottom: 5px;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.player-x {
color: var(--neon-blue);
text-shadow: 0 0 10px rgba(0, 243, 255, 0.5);
}
.player-o {
color: var(--neon-pink);
text-shadow: 0 0 10px rgba(255, 0, 255, 0.5);
}
.score-value {
font-size: 3rem;
font-weight: 900;
line-height: 1;
color: #fff;
}
/* Game Board Container - FIXED GRID */
.game-container {
position: relative;
background-color: var(--container-bg);
padding: 25px;
border-radius: 30px;
box-shadow:
0 20px 50px rgba(0, 0, 0, 0.6),
inset 0 0 0 2px rgba(255, 255, 255, 0.05);
margin-bottom: 30px;
perspective: 1000px;
/* Ensure container doesn't shrink */
width: 100%;
max-width: 400px;
}
.board {
display: flex;
flex-wrap: wrap;
width: 100%;
/* Force 3 items per row using flex-basis */
gap: 15px;
}
.cell {
background-color: var(--bg-color);
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 4.5rem;
cursor: pointer;
transition: all 0.3s ease;
box-shadow:
5px 5px 10px rgba(0, 0, 0, 0.4),
-2px -2px 5px rgba(255, 255, 255, 0.05);
position: relative;
overflow: hidden;
/* CRITICAL FIX: Force cells to be equal squares */
width: 32%; /* Approximately 1/3rd of container */
min-width: 100px; /* Prevent shrinking on small screens */
min-height: 100px;
aspect-ratio: 1 / 1; /* Ensures it stays a perfect square */
flex: 1 1 32%;
}
/* Sneaky Hover Effect - Cell tilts slightly to look at cursor but stays in place */
.cell:hover {
background-color: #151525;
box-shadow:
8px 8px 15px rgba(0, 0, 0, 0.5),
inset 0 0 0 1px rgba(255, 255, 255, 0.1),
0 0 15px rgba(0, 243, 255, 0.2);
/* Glow effect instead of movement */
}
.cell.x {
color: var(--neon-blue);
text-shadow: 0 0 15px var(--neon-blue), 0 0 30px var(--neon-blue);
animation: flyInLeft 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards;
}
.cell.o {
color: var(--neon-pink);
text-shadow: 0 0 15px var(--neon-pink), 0 0 30px var(--neon-pink);
animation: flyInRight 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards;
}
/* Humorous Animations for Marks */
@keyframes flyInLeft {
0% {
transform: translateX(-100px) rotate(-45deg) scale(0);
opacity: 0;
}
50% {
transform: translateX(20px) rotate(20deg) scale(1.2);
}
70% {
transform: translateX(-10px) rotate(-10deg) scale(1);
}
100% {
transform: translateX(0) rotate(0deg) scale(1);
opacity: 1;
}
}
@keyframes flyInRight {
0% {
transform: translateX(100px) rotate(45deg) scale(0);
opacity: 0;
}
50% {
transform: translateX(-20px) rotate(-20deg) scale(1.2);
}
70% {
transform: translateX(10px) rotate(10deg) scale(1);
}
100% {
transform: translateX(0) rotate(0deg) scale(1);
opacity: 1;
}
}
/* Winning Animation - Violent Shake for humor */
.cell.winner {
background-color: rgba(255, 255, 255, 0.1);
animation: shakeWinner 0.5s infinite;
z-index: 5;
color: var(--neon-yellow) !important;
text-shadow: 0 0 20px var(--neon-yellow) !important;
}
@keyframes shakeWinner {
0% {
transform: translate(1px, 1px) rotate(0deg);
}
10% {
transform: translate(-1px, -2px) rotate(-1deg);
}
20% {
transform: translate(-3px, 0px) rotate(1deg);
}
30% {
transform: translate(3px, 2px) rotate(0deg);
}
40% {
transform: translate(1px, -1px) rotate(1deg);
}
50% {
transform: translate(-1px, 2px) rotate(-1deg);
}
60% {
transform: translate(-3px, 1px) rotate(0deg);
}
70% {
transform: translate(3px, 1px) rotate(-1deg);
}
80% {
transform: translate(-1px, -1px) rotate(1deg);
}
90% {
transform: translate(1px, 2px) rotate(0deg);
}
100% {
transform: translate(1px, -2px) rotate(-1deg);
}
}
/* Laser Line Animation */
.laser-line {
position: absolute;
background-color: #fff;
box-shadow: 0 0 10px #fff, 0 0 20px var(--neon-green), 0 0 40px var(--neon-green);
opacity: 0;
z-index: 4;
transition: opacity 0.3s ease;
height: 8px;
border-radius: 4px;
}
/* Status and Controls */
.status-message {
text-align: center;
margin: 25px 0;
font-size: 1.8rem;
height: 50px;
font-weight: bold;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
transition: all 0.3s;
}
.status-message.gag-message {
font-size: 2.5rem;
color: var(--neon-yellow);
animation: jumpText 0.5s ease;
}
@keyframes jumpText {
0% {
transform: scale(1);
}
50% {
transform: scale(1.5) rotate(10deg);
}
100% {
transform: scale(1);
}
}
.btn {
background: linear-gradient(45deg, var(--neon-purple), var(--neon-blue));
color: white;
border: none;
padding: 15px 50px;
font-size: 1.3rem;
border-radius: 50px;
cursor: pointer;
transition: all 0.4s;
display: flex;
align-items: center;
gap: 15px;
margin: 0 auto;
box-shadow: 0 10px 20px rgba(188, 19, 254, 0.3);
position: relative;
overflow: hidden;
}
.btn:hover {
transform: translateY(-5px) scale(1.05);
box-shadow: 0 15px 30px rgba(0, 243, 255, 0.4);
}
.btn:active {
transform: translateY(2px) scale(0.98);
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: 0.5s;
}
.btn:hover::before {
left: 100%;
}
/* Modal for Game Over */
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(5, 5, 10, 0.9);
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
opacity: 0;
pointer-events: none;
transition: opacity 0.4s ease;
backdrop-filter: blur(8px);
}
.modal.show {
opacity: 1;
pointer-events: all;
}
.modal-content {
background: linear-gradient(145deg, #1a1a2e, #16213e);
padding: 50px;
border-radius: 30px;
text-align: center;
border: 2px solid var(--neon-purple);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.7), 0 0 50px rgba(188, 19, 254, 0.2);
animation: modalPop 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
max-width: 90%;
width: 400px;
position: relative;
}
@keyframes modalPop {
from {
transform: scale(0.5) rotate(-15deg);
opacity: 0;
}
to {
transform: scale(1) rotate(0);
opacity: 1;
}
}
.winner-icon {
font-size: 6rem;
margin-bottom: 20px;
display: block;
animation: bounce 2s infinite;
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-20px) rotate(10deg);
}
60% {
transform: translateY(-10px) rotate(-10deg);
}
}
.winner-text {
font-size: 3rem;
margin-bottom: 40px;
color: #fff;
font-weight: 900;
}
.gag-text {
font-size: 1.5rem;
color: var(--neon-yellow);
margin-bottom: 20px;
display: block;
font-weight: normal;
}
/* Responsive Design - Adjustments for Mobile */
@media (max-width: 450px) {
.game-container {
padding: 15px;
width: 95%;
}
.board {
gap: 10px;
}
.cell {
font-size: 3rem;
border-radius: 15px;
min-width: 80px;
min-height: 80px;
}
h1 {
font-size: 2.5rem;
}
.scoreboard {
flex-direction: column;
gap: 15px;
}
.player-score {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.player-name {
margin-bottom: 0;
}
.score-value {
margin-right: 15px;
}
.anycoder-link {
width: 100%;
text-align: center;
box-sizing: border-box;
}
}
</style>
</head>
<body>
<!-- Decorative floating objects -->
<div class="floating-object" style="top: 10%; left: 10%; animation-duration: 15s;"><i class="fas fa-ghost"></i></div>
<div class="floating-object" style="top: 80%; right: 10%; animation-duration: 12s;"><i class="fas fa-robot"></i></div>
<div class="floating-object" style="top: 40%; right: 20%; animation-duration: 18s;"><i class="fas fa-rocket"></i>
</div>
<canvas id="confetti-canvas"></canvas>
<header>
<h1>بازی دوز طنز</h1>
<div class="subtitle">نسخه با انیمیشن‌های خنده‌دار</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
<i class="fas fa-rocket"></i> Built with anycoder
</a>
</header>
<div class="scoreboard">
<div class="player-score active" id="score-x-container">
<div class="player-name player-x"><i class="fas fa-times"></i> بازیکن X</div>
<div class="score-value" id="score-x">0</div>
</div>
<div class="player-score" id="score-o-container">
<div class="player-name player-o"><i class="fas fa-circle"></i> بازیکن O</div>
<div class="score-value" id="score-o">0</div>
</div>
</div>
<div class="status-message" id="status-message">
<span class="player-x">نوبت بازیکن X است</span>
</div>
<div class="game-container">
<div class="board" id="board">
<div class="cell" data-index="0"></div>
<div class="cell" data-index="1"></div>
<div class="cell" data-index="2"></div>
<div class="cell" data-index="3"></div>
<div class="cell" data-index="4"></div>
<div class="cell" data-index="5"></div>
<div class="cell" data-index="6"></div>
<div class="cell" data-index="7"></div>
<div class="cell" data-index="8"></div>
</div>
</div>
<button class="btn" id="restart-btn">
<i class="fas fa-redo"></i> شروع مجدد بازی
</button>
<!-- Game Over Modal -->
<div class="modal" id="game-over-modal">
<div class="modal-content">
<span class="winner-icon" id="winner-icon"></span>
<div class="winner-text" id="winner-text"></div>
<div class="gag-text" id="winner-gag"></div>
<button class="btn" id="modal-restart-btn">
<i class="fas fa-play"></i> بازی بعدی
</button>
</div>
</div>
<script>
// Game State
const state = {
board: Array(9).fill(''),
currentPlayer: 'X',
gameActive: true,
scores: { X: 0, O: 0 }
};
// DOM Elements
const boardElement = document.getElementById('board');
const cells = document.querySelectorAll('.cell');
const statusMessage = document.getElementById('status-message');
const scoreXElement = document.getElementById('score-x');
const scoreOElement = document.getElementById('score-o');
const scoreXContainer = document.getElementById('score-x-container');
const scoreOContainer = document.getElementById('score-o-container');
const restartBtn = document.getElementById('restart-btn');
const modal = document.getElementById('game-over-modal');
const modalRestartBtn = document.getElementById('modal-restart-btn');
const winnerTextElement = document.getElementById('winner-text');
const winnerIconElement = document.getElementById('winner-icon');
const winnerGagElement = document.getElementById('winner-gag');
const canvas = document.getElementById('confetti-canvas');
const ctx = canvas.getContext('2d');
// 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
];
// Humorous Gags for different scenarios
const gagPhrases = [
"دقت کن! داری اشتباه می‌زنی!",
"این خانه خالیه، دیوانه نیستی؟",
"بازی دوز نیست که اینطوری بزنی!",
"یه ذره دقت کن عزیزم!",
"آفرین! دوباره همینو بزن!",
"من دارم تماشا می‌کنم!"
];
// Initialize Canvas for Confetti
let particles = [];
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
class Particle {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
this.size = Math.random() * 7 + 3;
this.speedX = Math.random() * 6 - 3;
this.speedY = Math.random() * -6 - 3;
this.gravity = 0.2;
this.alpha = 1;
this.rotation = Math.random() * 360;
this.rotationSpeed = Math.random() * 10 - 5;
this.emoji = ['😂', '😎', '🥳', '🤡', '👻'][Math.floor(Math.random() * 5)]; // Humorous emojis
this.showEmoji = Math.random() > 0.5;
}
update() {
this.x += this.speedX;
this.y += this.speedY;
this.speedY += this.gravity;
this.alpha -= 0.015;
this.rotation += this.rotationSpeed;
this.size *= 0.96;
}
draw() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation * Math.PI / 180);
ctx.globalAlpha = this.alpha;
if (this.showEmoji) {
ctx.font = `${this.size * 2}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(this.emoji, 0, 0);
} else {
ctx.fillStyle = this.color;
ctx.fillRect(-this.size / 2, -this.size / 2, this.size, this.size);
}
ctx.restore();
}
}
function createConfetti() {
particles = [];
const colors = ['#00f3ff', '#ff00ff', '#bc13fe', '#0aff0a', '#ffffff'];
for (let i = 0; i < 150; i++) {
const x = window.innerWidth / 2;
const y = window.innerHeight / 2;
const color = colors[Math.floor(Math.random() * colors.length)];
particles.push(new Particle(x, y, color));
}
animateConfetti();
}
function animateConfetti() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach((p, index) => {
p.update();
p.draw();
if (p.alpha <= 0) {
particles.splice(index, 1);
}
});
if (particles.length > 0) {
requestAnimationFrame(animateConfetti);
}
}
// Initialize Game
function initGame() {
state.board.fill('');
state.gameActive = true;
state.currentPlayer = 'X';
updateStatusMessage();
updateTurnIndicator();
cells.forEach(cell => {
cell.innerText = '';
cell.classList.remove('x', 'o', 'winner');
});
// Remove laser lines if any exist
const existingLines = document.querySelectorAll('.laser-line');
existingLines.forEach(line => line.remove());
modal.classList.remove('show');
}
// Handle Cell Click
function handleCellClick(e) {
const clickedCell = e.target;
const clickedCellIndex = parseInt(clickedCell.getAttribute('data-index'));
if (state.board[clickedCellIndex] !== '' || !state.gameActive) {
return;
}
updateCell(clickedCell, clickedCellIndex);
checkResult();
}
// Update Cell UI and State
function updateCell(cell, index) {
state.board[index] = state.currentPlayer;
cell.innerText = state.currentPlayer;
cell.classList.add(state.currentPlayer.toLowerCase());
}
// Switch Player
function switchPlayer() {
state.currentPlayer = state.currentPlayer === 'X' ? 'O' : 'X';
updateStatusMessage();
updateTurnIndicator();
}
// Update Status Text
function updateStatusMessage() {
if (state.gameActive) {
const playerClass = state.currentPlayer === 'X' ? 'player-x' : 'player-o';
statusMessage.innerHTML = `<span class="${playerClass}">نوبت بازیکن ${state.currentPlayer} است</span>`;
} else {
const winner = checkWinner();
if (winner) {
const playerClass = winner === 'X' ? 'player-x' : 'player-o';
statusMessage.innerHTML = `<span class="${playerClass}">بازیکن ${winner} برنده شد!</span>`;
} else {
statusMessage.innerHTML = `<span style="color: #fff; font-weight: bold; text-shadow: 0 0 10px #fff;">بازی مساوی شد! چه سختی!</span>`;
}
}
}
// Update Scoreboard Active State
function updateTurnIndicator() {
if (state.currentPlayer === 'X') {
scoreXContainer.classList.add('active');
scoreOContainer.classList.remove('active');
} else {
scoreOContainer.classList.add('active');
scoreXContainer.classList.remove('active');
}
}
// Check Game Result
function checkResult() {
let roundWon = false;
let winningLine = [];
for (let i = 0; i < winningConditions.length; i++) {
const [a, b, c] = winningConditions[i];
const valA = state.board[a];
const valB = state.board[b];
const valC = state.board[c];
if (valA === '' || valB === '' || valC === '') {
continue;
}
if (valA === valB && valB === valC) {
roundWon = true;
winningLine = [a, b, c];
break;
}
}
if (roundWon) {
state.gameActive = false;
highlightWinningCells(winningLine);
updateScore(state.currentPlayer);
showGameOverModal(state.currentPlayer);
createConfetti();
return;
}
const roundDraw = !state.board.includes('');
if (roundDraw) {
state.gameActive = false;
updateStatusMessage();
showGameOverModal('draw');
return;
}
switchPlayer();
}
// Highlight Winning Cells & Draw Laser Line
function highlightWinningCells(indices) {
indices.forEach(index => {
cells[index].classList.add('winner');
});
// Calculate laser line position
const [a, b, c] = indices;
const cellA = cells[a];
const cellC = cells[c];
// Get coordinates relative to the board container
const boardRect = boardElement.getBoundingClientRect();
const rectA = cellA.getBoundingClientRect();
const rectC = cellC.getBoundingClientRect();
const x1 = rectA.left + rectA.width / 2 - boardRect.left;
const y1 = rectA.top + rectA.height / 2 - boardRect.top;
const x2 = rectC.left + rectC.width / 2 - boardRect.left;
const y2 = rectC.top + rectC.height / 2 - boardRect.top;
const distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
const angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
const laserLine = document.createElement('div');
laserLine.classList.add('laser-line');
laserLine.style.width = `${distance}px`;
laserLine.style.height = '6px';
laserLine.style.left = `${x1}px`;
laserLine.style.top = `${y1}px`;
laserLine.style.transform = `rotate(${angle}deg)`;
laserLine.style.transformOrigin = '0 50%';
// Add color based on winner
const winnerColor = state.currentPlayer === 'X' ? 'var(--neon-blue)' : 'var(--neon-pink)';
laserLine.style.background = winnerColor;
laserLine.style.boxShadow = `0 0 10px #fff, 0 0 20px ${winnerColor}, 0 0 40px ${winnerColor}`;
boardElement.appendChild(laserLine);
// Animate laser
requestAnimationFrame(() => {
laserLine.style.opacity = '1';
laserLine.style.transition = 'width 0.4s ease-out, opacity 0.3s ease';
// Force reflow
laserLine.offsetWidth;
laserLine.style.width = `${distance}px`;
});
}
// Update Score
function updateScore(winner) {
state.scores[winner]++;
scoreXElement.innerText = state.scores.X;
scoreOElement.innerText = state.scores.O;
}
// Show Game Over Modal with Humor
function showGameOverModal(result) {
setTimeout(() => {
if (result === 'draw') {
winnerTextElement.innerText = "بازی مساوی شد!";
winnerGagElement.innerText = "هیچکس برنده نشد... خسته شدید؟";
winnerIconElement.innerHTML = '<i class="fas fa-handshake" style="color: #fff;"></i>';
winnerTextElement.style.color = '#fff';
} else {
const color = result === 'X' ? 'var(--neon-blue)' : 'var(--neon-pink)';
winnerTextElement.innerText = `بازیکن ${result} برنده شد!`;
winnerTextElement.style.color = color;
winnerIconElement.innerHTML = `<i class="fas fa-trophy" style="color: ${color};"></i>`;
// Pick a random gag phrase
const randomGag = gagPhrases[Math.floor(Math.random() * gagPhrases.length)];
winnerGagElement.innerText = randomGag;
// Add a little jump animation to the text if it's a gag
if (result === 'O') {
winnerGagElement.style.animation = "jumpText 0.5s ease";
setTimeout(() => winnerGagElement.style.animation = "", 500);
}
}
modal.classList.add('show');
}, 800);
}
// Event Listeners
cells.forEach(cell => cell.addEventListener('click', handleCellClick));
restartBtn.addEventListener('click', initGame);
modalRestartBtn.addEventListener('click', initGame);
// Start the game
initGame();
</script>
</body>
</html>