587 lines
20 KiB
HTML
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> |