tic-tac-tango-toe / index.html
fimix's picture
Create a Tic Tac Toe game, with a game board, a history section, and a score section.
7e97bda verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tic Tac Tango Toe</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3B82F6',
secondary: '#10B981',
}
}
}
}
</script>
<style>
.game-cell {
transition: all 0.3s ease;
}
.game-cell:hover {
transform: scale(1.05);
}
.history-item:hover {
background-color: rgba(59, 130, 246, 0.1);
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div id="app" class="container mx-auto px-4 py-8">
<header class="text-center mb-10">
<h1 class="text-4xl md:text-5xl font-bold text-primary mb-2">Tic Tac Tango Toe</h1>
<p class="text-gray-600">The game where X and O dance! 🕺</p>
</header>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Game Board -->
<div class="lg:col-span-2">
<div class="bg-white rounded-xl shadow-lg p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-semibold text-gray-800">Game Board</h2>
<div class="flex items-center space-x-2">
<span class="px-3 py-1 bg-primary text-white rounded-full text-sm">Player X</span>
<span class="px-3 py-1 bg-secondary text-white rounded-full text-sm">Player O</span>
</div>
</div>
<div class="grid grid-cols-3 gap-3 mb-6">
<div v-for="(cell, index) in board" :key="index"
@click="makeMove(index)"
class="game-cell aspect-square flex items-center justify-center text-5xl font-bold rounded-lg bg-gray-100 hover:bg-gray-200 cursor-pointer transition-colors"
:class="{
'text-primary': cell === 'X',
'text-secondary': cell === 'O'
}">
{{ cell }}
</div>
</div>
<div class="flex justify-center">
<button @click="resetGame"
class="px-6 py-2 bg-gray-800 text-white rounded-lg hover:bg-gray-700 transition-colors flex items-center space-x-2">
<i data-feather="refresh-cw" class="w-4 h-4"></i>
<span>Reset Game</span>
</button>
</div>
</div>
</div>
<!-- Game Info -->
<div class="space-y-6">
<!-- Score Board -->
<div class="bg-white rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Score Board</h2>
<div class="grid grid-cols-2 gap-4">
<div class="text-center p-4 bg-primary bg-opacity-10 rounded-lg">
<p class="text-sm text-primary font-medium">Player X</p>
<p class="text-3xl font-bold text-primary">{{ scores.X }}</p>
</div>
<div class="text-center p-4 bg-secondary bg-opacity-10 rounded-lg">
<p class="text-sm text-secondary font-medium">Player O</p>
<p class="text-3xl font-bold text-secondary">{{ scores.O }}</p>
</div>
<div class="col-span-2 text-center p-4 bg-gray-100 rounded-lg">
<p class="text-sm text-gray-600 font-medium">Ties</p>
<p class="text-3xl font-bold text-gray-800">{{ scores.ties }}</p>
</div>
</div>
</div>
<!-- Game History -->
<div class="bg-white rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Game History</h2>
<div class="space-y-2 max-h-64 overflow-y-auto">
<div v-for="(record, index) in history" :key="index"
class="history-item p-3 rounded-lg cursor-pointer border border-gray-100 hover:border-primary transition-colors"
@click="replayGame(index)">
<div class="flex justify-between items-center">
<span class="font-medium text-gray-700">Game {{ index + 1 }}</span>
<span class="text-sm" :class="{
'text-primary': record.winner === 'X',
'text-secondary': record.winner === 'O',
'text-gray-500': record.winner === 'tie'
}">
{{ record.winner === 'tie' ? 'Tie' : `Winner: ${record.winner}` }}
</span>
</div>
</div>
<p v-if="history.length === 0" class="text-gray-500 text-center py-4">No games played yet</p>
</div>
</div>
</div>
</div>
<!-- Current Player -->
<div class="mt-8 text-center">
<p class="text-lg">
Current player:
<span class="font-bold" :class="{
'text-primary': currentPlayer === 'X',
'text-secondary': currentPlayer === 'O'
}">
{{ currentPlayer }}
</span>
</p>
<p v-if="gameStatus !== 'ongoing'" class="text-xl font-bold mt-2" :class="{
'text-primary': gameStatus === 'X',
'text-secondary': gameStatus === 'O',
'text-gray-600': gameStatus === 'tie'
}">
{{ gameStatus === 'tie' ? "It's a tie!" : `Player ${gameStatus} wins!` }}
</p>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.min.js"></script>
<script>
feather.replace();
const { createApp, ref, computed } = Vue;
createApp({
setup() {
const board = ref(Array(9).fill(null));
const currentPlayer = ref('X');
const gameStatus = ref('ongoing');
const history = ref([]);
const scores = ref({
X: 0,
O: 0,
ties: 0
});
const winningCombinations = [
[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
];
const checkWinner = () => {
for (const combo of winningCombinations) {
const [a, b, c] = combo;
if (board.value[a] && board.value[a] === board.value[b] && board.value[a] === board.value[c]) {
return board.value[a];
}
}
return board.value.includes(null) ? null : 'tie';
};
const makeMove = (index) => {
if (board.value[index] || gameStatus.value !== 'ongoing') return;
board.value[index] = currentPlayer.value;
const winner = checkWinner();
if (winner) {
gameStatus.value = winner;
if (winner !== 'tie') {
scores.value[winner]++;
} else {
scores.value.ties++;
}
history.value.push({
board: [...board.value],
winner: winner
});
} else {
currentPlayer.value = currentPlayer.value === 'X' ? 'O' : 'X';
}
};
const resetGame = () => {
board.value = Array(9).fill(null);
currentPlayer.value = 'X';
gameStatus.value = 'ongoing';
};
const replayGame = (index) => {
const game = history.value[index];
board.value = [...game.board];
gameStatus.value = game.winner;
currentPlayer.value = game.winner === 'tie' ? 'X' : game.winner === 'X' ? 'O' : 'X';
};
return {
board,
currentPlayer,
gameStatus,
history,
scores,
makeMove,
resetGame,
replayGame
};
}
}).mount('#app');
</script>
<script>feather.replace();</script>
</body>
</html>