433 lines
13 KiB
HTML
433 lines
13 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 vs Computer</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
|
|
min-height: 100vh;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 20px;
|
|
}
|
|
|
|
.game-container {
|
|
background: white;
|
|
border-radius: 25px;
|
|
padding: 40px;
|
|
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
|
text-align: center;
|
|
max-width: 450px;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 2rem;
|
|
margin-bottom: 20px;
|
|
background: linear-gradient(90deg, #ff6b6b, #ff9500);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.coin-container {
|
|
display: none;
|
|
margin: 20px auto;
|
|
}
|
|
|
|
.coin-container.active {
|
|
display: block;
|
|
}
|
|
|
|
.coin-message {
|
|
font-size: 1.2rem;
|
|
color: #555;
|
|
margin-bottom: 10px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.coin {
|
|
width: 120px;
|
|
height: 120px;
|
|
border-radius: 50%;
|
|
margin: 0 auto;
|
|
position: relative;
|
|
transition: transform 1.5s ease-in-out;
|
|
}
|
|
|
|
.coin.heads {
|
|
background: linear-gradient(135deg, #ffd700, #ffa500);
|
|
}
|
|
|
|
.coin.tails {
|
|
background: linear-gradient(135deg, #3498db, #2980b9);
|
|
}
|
|
|
|
.coin-header {
|
|
position: absolute;
|
|
top: 40px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
font-size: 2rem;
|
|
font-weight: bold;
|
|
color: white;
|
|
text-shadow: 1px 1px 3px rgba(0,0,0,0.3);
|
|
}
|
|
|
|
.coin-tails .coin-header {
|
|
top: 40px;
|
|
}
|
|
|
|
.result-message {
|
|
font-size: 1.5rem;
|
|
font-weight: bold;
|
|
min-height: 40px;
|
|
margin: 15px 0;
|
|
color: #333;
|
|
}
|
|
|
|
.heads-result {
|
|
background: linear-gradient(90deg, #ffd700, #ffa500);
|
|
padding: 15px 25px;
|
|
border-radius: 15px;
|
|
color: white;
|
|
font-size: 1.3rem;
|
|
box-shadow: 0 4px 15px rgba(255,165,0,0.4);
|
|
}
|
|
|
|
.tails-result {
|
|
background: linear-gradient(90deg, #3498db, #2980b9);
|
|
padding: 15px 25px;
|
|
border-radius: 15px;
|
|
color: white;
|
|
font-size: 1.3rem;
|
|
box-shadow: 0 4px 15px rgba(52,152,219,0.4);
|
|
}
|
|
|
|
.board {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 85px);
|
|
grid-template-rows: repeat(3, 85px);
|
|
gap: 8px;
|
|
margin: 30px auto 0;
|
|
justify-content: center;
|
|
}
|
|
|
|
.cell {
|
|
width: 85px;
|
|
height: 85px;
|
|
background: linear-gradient(135deg, #87CEEB, #B0E0E6);
|
|
border: none;
|
|
border-radius: 12px;
|
|
cursor: pointer;
|
|
font-size: 2.5rem;
|
|
font-weight: bold;
|
|
transition: transform 0.15s ease, background 0.3s ease;
|
|
box-shadow: 0 3px 0 rgba(0,0,0,0.15);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.cell:hover:not(:disabled) {
|
|
transform: scale(1.05);
|
|
background: linear-gradient(135deg, #98DCE8, #C4E2F0);
|
|
}
|
|
|
|
.cell:active:not(:disabled) {
|
|
transform: scale(0.98);
|
|
box-shadow: none;
|
|
}
|
|
|
|
.cell.x {
|
|
color: #3498db;
|
|
text-shadow: 0 2px 10px rgba(52,152,219,0.4);
|
|
}
|
|
|
|
.cell.o {
|
|
color: #ff9500;
|
|
text-shadow: 0 2px 10px rgba(255,149,0,0.4);
|
|
}
|
|
|
|
.cell.winning {
|
|
background: linear-gradient(135deg, #2ecc71, #27ae60);
|
|
transform: scale(1.03);
|
|
box-shadow: 0 5px 20px rgba(46,204,113,0.5);
|
|
}
|
|
|
|
.cell.disabled {
|
|
cursor: not-allowed;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.game-message {
|
|
min-height: 70px;
|
|
margin: 20px auto;
|
|
font-size: 1.3rem;
|
|
font-weight: 600;
|
|
padding: 15px 25px;
|
|
border-radius: 15px;
|
|
max-width: 95%;
|
|
word-wrap: break-word;
|
|
}
|
|
|
|
.message-player-wins {
|
|
background: linear-gradient(90deg, #2ecc71, #27ae60);
|
|
color: white;
|
|
animation: bounceIn 0.6s ease;
|
|
}
|
|
|
|
.message-computer-wins {
|
|
background: linear-gradient(90deg, #ff6b6b, #ff9500);
|
|
color: white;
|
|
animation: bounceIn 0.6s ease;
|
|
}
|
|
|
|
.message-draw {
|
|
background: linear-gradient(90deg, #a29bfe, #6c5ce7);
|
|
color: white;
|
|
animation: fadeIn 0.6s ease;
|
|
}
|
|
|
|
.message-start {
|
|
background: linear-gradient(90deg, #fdcb6e, #ffd700);
|
|
color: #333;
|
|
animation: scaleIn 0.6s ease;
|
|
}
|
|
|
|
@keyframes bounceIn {
|
|
0% { opacity: 0; transform: scale(0.3); }
|
|
50% { opacity: 1; transform: scale(1.1); }
|
|
70% { transform: scale(0.9); }
|
|
100% { transform: scale(1); }
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
0% { opacity: 0; }
|
|
100% { opacity: 1; }
|
|
}
|
|
|
|
@keyframes scaleIn {
|
|
0% { opacity: 0; transform: scale(0.8); }
|
|
100% { opacity: 1; transform: scale(1); }
|
|
}
|
|
|
|
@keyframes wave {
|
|
0% { transform: scale(1); }
|
|
50% { transform: scale(1.2); }
|
|
100% { transform: scale(1); }
|
|
}
|
|
|
|
.cell-animating {
|
|
animation: wave 0.3s ease;
|
|
}
|
|
|
|
.status-indicator {
|
|
font-size: 1rem;
|
|
color: #666;
|
|
margin: 0 0 10px 0;
|
|
font-style: italic;
|
|
}
|
|
|
|
.thinking {
|
|
color: #ff9500;
|
|
font-weight: 600;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="game-container">
|
|
<h1>✏️ Tic Tac Toe vs Computer 🤖</h1>
|
|
|
|
<div class="coin-container" id="coinContainer">
|
|
<div class="coin-message" id="coinMessage">Flipping the coin...</div>
|
|
<div class="coin" id="coin">
|
|
<div class="coin-header H">H</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="result-message" id="resultMessage"></div>
|
|
|
|
<div class="status-indicator" id="statusIndicator"></div>
|
|
|
|
<div class="board" id="board">
|
|
<button class="cell" data-index="0"></button>
|
|
<button class="cell" data-index="1"></button>
|
|
<button class="cell" data-index="2"></button>
|
|
<button class="cell" data-index="3"></button>
|
|
<button class="cell" data-index="4"></button>
|
|
<button class="cell" data-index="5"></button>
|
|
<button class="cell" data-index="6"></button>
|
|
<button class="cell" data-index="7"></button>
|
|
<button class="cell" data-index="8"></button>
|
|
</div>
|
|
|
|
<div class="game-message" id="gameMessage"></div>
|
|
</div>
|
|
|
|
<script>
|
|
const board = [null, null, null, null, null, null, null, null, null];
|
|
let player = 'X';
|
|
let computer = 'O';
|
|
let playerNext = true;
|
|
let gameActive = false;
|
|
|
|
const coinContainer = document.getElementById('coinContainer');
|
|
const coin = document.getElementById('coin');
|
|
const coinMessage = document.getElementById('coinMessage');
|
|
const resultMessage = document.getElementById('resultMessage');
|
|
const gameMessage = document.getElementById('gameMessage');
|
|
const statusIndicator = document.getElementById('statusIndicator');
|
|
const cells = document.querySelectorAll('.cell');
|
|
|
|
function randomMove() {
|
|
let available = [];
|
|
board.forEach((cell, index) => {
|
|
if (cell === null) available.push(index);
|
|
});
|
|
return available[Math.floor(Math.random() * available.length)];
|
|
}
|
|
|
|
function startCoinFlip() {
|
|
setTimeout(() => {
|
|
if (!gameActive) {
|
|
gameActive = true;
|
|
coinContainer.classList.add('active');
|
|
coinMessage.textContent = 'Flipping...';
|
|
coin.classList.add('active');
|
|
|
|
setTimeout(() => {
|
|
const isHeads = Math.random() < 0.5;
|
|
coin.className = 'coin ' + (isHeads ? 'heads' : 'tails');
|
|
coinMessage.textContent = isHeads ? 'Heads!' : 'Tails!';
|
|
resultMessage.innerHTML = isHeads
|
|
? '<div class="heads-result"><span>Heads, <strong>you\'re X!</strong></span></div>'
|
|
: '<div class="tails-result"><span>Tails, <strong>computer is <span class="player">\'X\'</span></strong>!</span></div>';
|
|
|
|
setTimeout(startGame, 500);
|
|
}, 1500);
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
function startGame() {
|
|
coinMessage.textContent = 'Ready!';
|
|
cells.forEach(cell => {
|
|
cell.textContent = '';
|
|
cell.className = 'cell';
|
|
cell.disabled = false;
|
|
});
|
|
statusIndicator.textContent = '';
|
|
gameMessage.innerHTML = '<div class="message-start">Your Turn!</div>';
|
|
gameActive = true;
|
|
|
|
setTimeout(() => {
|
|
gameActive = false;
|
|
computerMove();
|
|
}, 500);
|
|
}
|
|
|
|
function computerMove() {
|
|
if (!gameActive) return;
|
|
statusIndicator.textContent = '🤖 Computer is thinking...';
|
|
|
|
setTimeout(() => {
|
|
const move = randomMove();
|
|
if (move !== undefined) {
|
|
makeMove(move, computer, true);
|
|
playerNext = true;
|
|
gameActive = false;
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
function makeMove(index, mark, isComputer = false) {
|
|
const cell = cells[index];
|
|
board[index] = mark;
|
|
cell.textContent = mark;
|
|
cell.classList.add(mark.toLowerCase());
|
|
cell.classList.add('cell-animating');
|
|
|
|
setTimeout(() => cell.classList.remove('cell-animating'), 300);
|
|
|
|
if (isComputer) {
|
|
statusIndicator.textContent = '';
|
|
checkResult();
|
|
} else {
|
|
gameActive = false;
|
|
if (board.includes(null)) {
|
|
statusIndicator.textContent = 'Your Turn!';
|
|
playerNext = true;
|
|
} else {
|
|
gameMessage.textContent = '🤝';
|
|
}
|
|
checkResult();
|
|
}
|
|
}
|
|
|
|
function checkResult() {
|
|
const wins = [
|
|
[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]
|
|
];
|
|
|
|
let winner = null;
|
|
for (let i = 0; i < 8; i++) {
|
|
if (board[wins[i][0]] === board[wins[i][1]] &&
|
|
board[wins[i][1]] === board[wins[i][2]] &&
|
|
board[wins[i][0]] !== null) {
|
|
winner = board[wins[i][0]];
|
|
}
|
|
}
|
|
|
|
if (winner) {
|
|
cells.forEach(cell => {
|
|
if (board[parseInt(cell.dataset.index)] === winner) {
|
|
cell.classList.add('winning');
|
|
}
|
|
});
|
|
|
|
setTimeout(() => {
|
|
gameMessage.innerHTML = winner === computer
|
|
? '<div class="message-computer-wins">😄 Computer wins! Better luck next time! 🎮</div>'
|
|
: '<div class="message-player-wins">🎉 You win! Great job! 🎮</div>';
|
|
}, 500);
|
|
} else if (board.every(cell => cell !== null)) {
|
|
setTimeout(() => {
|
|
gameMessage.textContent = '🤝 It is a draw! 🎮';
|
|
}, 500);
|
|
}
|
|
}
|
|
|
|
function restart() {
|
|
cells.forEach(cell => {
|
|
cell.textContent = '';
|
|
cell.className = 'cell';
|
|
});
|
|
|
|
setTimeout(() => {
|
|
gameMessage.innerHTML = '<div class="message-start">Play Again!</div>';
|
|
startCoinFlip();
|
|
}, 300);
|
|
}
|
|
|
|
cells.forEach(cell => {
|
|
cell.addEventListener('click', () => {
|
|
if (playerNext) {
|
|
makeMove(parseInt(cell.dataset.index), player);
|
|
}
|
|
});
|
|
});
|
|
|
|
startCoinFlip();
|
|
</script>
|
|
</body>
|
|
</html> |