Files

587 lines
20 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tic-Tac-Toe Challenge</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.game-container {
text-align: center;
padding: 40px;
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
max-width: 450px;
width: 90%;
}
h1 {
color: #4a4a4a;
margin-bottom: 10px;
font-size: 2.5rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}
.subtitle {
color: #888;
margin-bottom: 30px;
font-size: 1rem;
}
.legend {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 20px;
font-size: 0.9rem;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
}
.legend-icon {
width: 32px;
height: 32px;
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
font-weight: bold;
background: linear-gradient(180deg, #667eea, #5a6fcf);
box-shadow: inset 2px 2px 4px rgba(255, 255, 255, 0.3),
inset -2px -2px 4px rgba(0, 0, 0, 0.2);
}
.legend-label {
color: #888;
}
.coin-flip-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 20px;
}
.coin {
width: 150px;
height: 150px;
border-radius: 50%;
position: relative;
margin: 20px auto;
font-size: 6rem;
font-weight: bold;
color: #5d4037;
box-shadow:
inset 15px 15px 30px rgba(255, 255, 255, 0.5),
inset -15px -15px 30px rgba(139, 69, 19, 0.3),
0 15px 40px rgba(0, 0, 0, 0.3);
cursor: pointer;
transition: transform 0.05s linear;
text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.3);
}
.coin.h {
transform: rotateY(0deg) scale(1);
background: linear-gradient(45deg, #ffd700, #ffb700, #ffd700, #ffeb3b);
z-index: 2;
}
.coin.h::before {
content: 'H';
position: absolute;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(180deg, #ffd700, #ffb700);
z-index: 1;
}
.coin.t {
transform: rotateY(180deg) scale(1);
background: linear-gradient(45deg, #8B4513, #A0522D, #8B4513, #6f4e37);
}
.coin.t::before {
content: 'T';
position: absolute;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(180deg, #8B4513, #6f4e37);
}
.flip-btn {
padding: 12px 35px;
font-size: 1.2rem;
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 50px;
cursor: pointer;
font-weight: bold;
box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
transition: all 0.3s ease;
letter-spacing: 1px;
margin-top: 10px;
}
.flip-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.5);
}
.flip-btn:active {
transform: translateY(2px);
box-shadow: 0 3px 15px rgba(102, 126, 234, 0.3);
}
.game-board {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin: 30px 0;
max-width: 350px;
margin-left: auto;
margin-right: auto;
}
.cell {
aspect-ratio: 1;
background: linear-gradient(145deg, #f5f5f5, #e8e8e8);
border: 3px solid #d0d0d0;
border-radius: 15px;
font-size: 3.5rem;
font-weight: bold;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.2s ease;
user-select: none;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}
.cell:hover:not(.x):not(.o) {
background: linear-gradient(145deg, #ececec, #e0e0e0);
box-shadow: inset 3px 3px 7px rgba(0, 0, 0, 0.1),
inset -3px -3px 7px rgba(255, 255, 255, 0.8);
border-color: #b0b0b0;
}
.cell.x {
color: #667eea;
}
.cell.o {
color: #e91e63;
}
.cell.winning {
background: linear-gradient(145deg, #a8e6cf, #8edcbb);
transform: scale(1.05);
box-shadow: 0 0 25px rgba(136, 198, 178, 0.6);
}
.status {
font-size: 1.4rem;
margin-bottom: 20px;
padding: 15px;
border-radius: 10px;
background: linear-gradient(135deg, #f8f9fa, #e9ecef);
color: #495057;
font-weight: 600;
min-height: 2em;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.05);
}
.restart-btn {
padding: 12px 40px;
font-size: 1.1rem;
background: linear-gradient(45deg, #48bb78, #38a169);
color: white;
border: none;
border-radius: 50px;
cursor: pointer;
font-weight: bold;
box-shadow: 0 5px 20px rgba(72, 187, 120, 0.4);
transition: all 0.3s ease;
letter-spacing: 0.5px;
}
.restart-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(72, 187, 120, 0.5);
background: linear-gradient(45deg, #45a049, #359456);
}
.restart-btn:active {
transform: translateY(2px);
background: linear-gradient(45deg, #45a049, #359456);
}
.turn-indicator {
font-size: 1.2rem;
margin-bottom: 20px;
color: #555;
}
.turn-indicator span {
font-weight: bold;
padding: 10px 20px;
border-radius: 20px;
display: inline-block;
margin: 0 5px;
transition: all 0.3s ease;
}
.turn-indicator .active {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
box-shadow: 0 3px 10px rgba(102, 126, 234, 0.3);
transform: scale(1.05);
}
.turn-indicator .inactive {
background: #e9ecef;
color: #adb5bd;
}
.confetti {
position: fixed;
width: 12px;
height: 12px;
animation: fall linear forwards;
will-change: transform;
}
@keyframes fall {
to {
transform: translateY(100vh) rotate(720deg);
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>🎮 Tic-Tac-Toe</h1>
<p class="subtitle">Human vs Computer Challenge!</p>
<div class="legend">
<div class="legend-item">
<div class="legend-icon" id="legend-icon"></div>
<span class="legend-label" id="legend-x-label">You</span>
</div>
<div class="legend-item">
<div class="legend-icon legend-computer"></div>
<span class="legend-label">Computer</span>
</div>
</div>
<div id="coinSection" class="coin-flip-container">
<div class="coin h">H</div>
<p id="coinMessage" style="color: #666; font-weight: 500; text-align: center;">
Click the coin to flip! <br>
<span style="font-size: 0.9rem; color: #888; display: block; margin-top: 5px;">
🪙 H = Heads (You go first) <br>
🪙 T = Tails (Computer goes first)
</span>
</p>
<button class="flip-btn" id="flipBtn" onclick="flipCoin()">🪙 Flip Coin</button>
</div>
<div id="gameSection" style="display: none;">
<div class="turn-indicator">
Current Turn:
<span id="currentPlayer" class="active">YOU</span>
<span id="computerPlayer" class="inactive">COMPUTER</span>
</div>
<div class="status" id="status"></div>
<div class="game-board" id="board">
<div class="cell" data-index="0" onclick="makeMove(0)"></div>
<div class="cell" data-index="1" onclick="makeMove(1)"></div>
<div class="cell" data-index="2" onclick="makeMove(2)"></div>
<div class="cell" data-index="3" onclick="makeMove(3)"></div>
<div class="cell" data-index="4" onclick="makeMove(4)"></div>
<div class="cell" data-index="5" onclick="makeMove(5)"></div>
<div class="cell" data-index="6" onclick="makeMove(6)"></div>
<div class="cell" data-index="7" onclick="makeMove(7)"></div>
<div class="cell" data-index="8" onclick="makeMove(8)"></div>
</div>
<button class="restart-btn" onclick="restartGame()">🔄 Play Again</button>
</div>
</div>
<script>
let board = [];
let gameActive = false;
let myPlayer = 'X';
let computerPlayer = 'O';
let myTurn = true;
let myGoesFirst = false;
const winPatterns = [
[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6]
];
function flipCoin() {
const coin = document.querySelector('.coin');
const button = document.getElementById('flipBtn');
button.disabled = true;
coin.style.transition = 'transform 1s ease-in-out';
coin.style.transform = 'rotateY(0deg)';
setTimeout(() => {
coin.style.transition = 'none';
const result = Math.random() < 0.5 ? 'H' : 'T';
coin.style.transition = 'transform 0.5s linear';
if (result === 'H') {
coin.className = 'coin h';
myGoesFirst = true;
myPlayer = 'X';
computerPlayer = 'O';
updateLegend();
coin.style.transform = 'rotateY(0deg)';
} else {
coin.className = 'coin t';
myGoesFirst = false;
myPlayer = 'O';
computerPlayer = 'X';
updateLegend();
coin.style.transform = 'rotateY(180deg)';
}
document.getElementById('coinMessage').innerHTML =
`🎲 Result: <strong>${result === 'H' ? 'Heads' : 'Tails'}</strong>!<br>` +
(myGoesFirst
? `👨 <strong>You</strong> will go first! 🎯 You play as <span style="color: #667eea; font-weight: bold">${myPlayer}</span>`
: `🤖 <strong>Computer</strong> will go first! 💻 Computer plays as <span style="color: #667eea; font-weight: bold;">${myPlayer}</span>, You play as <span style="color: #e91e63; font-weight: bold;">${computerPlayer}</span>`
);
setTimeout(startGame, 2000);
}, 1000);
}
function updateLegend() {
document.getElementById('legend-x-label').textContent = myTurn
? `You (${myPlayer}) - Your Turn!`
: `You (${myPlayer}) - Wait for Computer`;
if (myGoesFirst && myPlayer === 'X') {
document.getElementById('legend-icon').textContent = 'X';
} else if (!myGoesFirst && myPlayer === 'X') {
document.getElementById('legend-icon').textContent = 'X';
}
}
function startGame() {
document.getElementById('coinSection').style.display = 'none';
document.getElementById('gameSection').style.display = 'block';
gameActive = true;
if (myGoesFirst) {
// Player X (which could be human or computer) goes first
if (myPlayer === 'X') {
// Human is X, goes first
myTurn = true;
document.getElementById('currentPlayer').classList.remove('inactive');
document.getElementById('currentPlayer').classList.add('active');
document.getElementById('computerPlayer').classList.remove('active');
document.getElementById('computerPlayer').classList.add('inactive');
} else {
// Computer is X, goes first
computerMove();
}
document.getElementById('status').textContent = 'Choose a cell to make your move!';
} else if (!myGoesFirst) {
// Computer goes first
computerMove();
}
}
function computerMove() {
if (!gameActive) return;
const cells = Array.from(document.querySelectorAll('.cell'));
const possibleMoves = [];
cells.forEach((cell) => {
if (!cell.textContent) {
possibleMoves.push(parseInt(cell.dataset.index));
}
});
if (possibleMoves.length === 0) {
return;
}
const randomMove = possibleMoves[Math.floor(Math.random() * possibleMoves.length)];
board[randomMove] = 'O';
cells[randomMove].textContent = 'O';
cells[randomMove].classList.add('o');
if (checkWin('O')) {
endGame('computer');
} else if (checkDraw()) {
endGame('draw');
} else {
myTurn = true;
updateTurnStatus();
document.getElementById('status').textContent = 'Your turn! Click any cell.';
}
}
function makeMove(index) {
if (!gameActive) return;
if (!myTurn) return;
if (board[index]) return;
board[index] = myPlayer;
const cells = Array.from(document.querySelectorAll('.cell'));
cells[index].textContent = myPlayer;
cells[index].classList.add(myPlayer.toLowerCase());
if (checkWin(myPlayer)) {
endGame('human');
return;
}
if (checkDraw()) {
endGame('draw');
return;
}
myTurn = false;
updateTurnStatus();
document.getElementById('status').textContent = "Computer is thinking...";
setTimeout(computerMove, 800);
}
function checkWin(player) {
return winPatterns.some(pattern => {
return pattern.every(index => board[index] === player);
});
}
function checkDraw() {
return board.length > 0 && !board.includes('');
}
function updateTurnStatus() {
const humanSpan = document.getElementById('currentPlayer');
const computerSpan = document.getElementById('computerPlayer');
if (myTurn) {
humanSpan.classList.add('active');
humanSpan.classList.remove('inactive');
computerSpan.classList.remove('active');
computerSpan.classList.add('inactive');
document.getElementById('status').textContent = 'Your turn! Click any cell.';
} else {
humanSpan.classList.remove('active');
humanSpan.classList.add('inactive');
computerSpan.classList.add('active');
computerSpan.classList.remove('inactive');
}
}
function endGame(result) {
gameActive = false;
const statusEl = document.getElementById('status');
if (result === 'human') {
statusEl.textContent = '🎉 YOU WON! Congratulations! Play again!';
statusEl.style.background = 'linear-gradient(135deg, #a8e6cf, #8edcbb)';
createConfetti();
} else if (result === 'computer') {
statusEl.textContent = '😅 COMPUTER WINS! Better luck next time! Play again!';
statusEl.style.background = 'linear-gradient(135deg, #ffecd2, #fcb69f)';
} else {
statusEl.textContent = '🤝 DRAW GAME! Well played! Try again!';
statusEl.style.background = 'linear-gradient(135deg, #d4fc79, #96e6a1)';
}
}
function createConfetti() {
const colors = ['#ff6b6b', '#feca57', '#48dbfb', '#ff9ff3', '#54a0ff', '#1dd1a1'];
for (let i = 0; i < 60; i++) {
const confetti = document.createElement('div');
confetti.classList.add('confetti');
confetti.style.left = Math.random() * 100 + 'vw';
confetti.style.top = -10 + 'px';
confetti.style.background = colors[Math.floor(Math.random() * colors.length)];
confetti.style.borderRadius = Math.random() > 0.5 ? '50%' : '2px 0 2px 2px';
confetti.style.animationDuration = (Math.random() * 3 + 2) + 's';
document.body.appendChild(confetti);
setTimeout(() => confetti.remove(), 5000);
}
}
function restartGame() {
// Reset everything for fresh game
board = [];
gameActive = false;
myTurn = true;
// Reset board display
Array.from(document.querySelectorAll('.cell')).forEach(cell => {
cell.textContent = '';
cell.classList.remove('x', 'o', 'winning');
});
// Reset message to show coin page
if (document.getElementById('coinSection').style.display === 'none') {
document.getElementById('coinSection').style.display = 'flex';
document.getElementById('gameSection').style.display = 'none';
// Reset coin to default
const coin = document.querySelector('.coin');
coin.textContent = 'H';
coin.className = 'coin h';
coin.style.transform = 'rotateY(0deg)';
document.getElementById('coinMessage').innerHTML = 'Click the coin to flip!<br><span style="font-size: 0.9rem; color: #888; display: block; margin-top: 5px;">🪙 H = Heads (You go first)<br>🪙 T = Tails (Computer goes first)</span>';
document.getElementById('flipBtn').disabled = false;
}
document.getElementById('currentPlayer').classList.remove('active');
document.getElementById('currentPlayer').classList.add('inactive');
document.getElementById('computerPlayer').classList.remove('inactive');
document.getElementById('computerPlayer').classList.add('active');
document.getElementById('status').textContent = '';
document.getElementById('legend-x-label').textContent = 'You - Your Turn!';
}
function cleanUp() {
const confettis = document.querySelectorAll('.confetti');
confettis.forEach(c => c.remove());
}
</script>
</body>
</html>