<!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</title>
<style>
:root { --green:#4CAF50; --blue:#2196F3; --gray:#ccc; }
body { font-family: sans-serif; text-align: center; background:#f4f4f4; margin:0; padding:40px 16px; }
h1 { margin: 0 0 10px; }
.board {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 0;
margin: 20px auto;
background: #fff;
border: 20px solid var(--gray);
box-shadow: 0 0 10px rgba(0,0,0,.1);
width: min(90vw, 420px);
height: min(90vw, 420px);
max-width: 420px;
max-height: 420px;
user-select: none;
}
.cell {
border: 3px solid var(--gray);
display: flex; align-items: center; justify-content: center;
font-size: clamp(2.2rem, 10vw, 3.5rem);
cursor: pointer; transition: background-color .15s ease;
box-sizing: border-box;
}
.cell:hover { background:#eee; }
.cell.x { background: var(--green); color:#fff; }
.cell.o { background: var(--blue); color:#fff; }
.cell.disabled { pointer-events: none; cursor: not-allowed; opacity:.6; }
.score { margin-top: 10px; font-size: 1.2rem; color:#333; display:flex; gap:16px; justify-content:center; }
.meta { margin-top: 10px; color:#555; min-height: 1.4em; }
.controls { margin-top: 16px; display:flex; gap:10px; justify-content:center; }
.btn {
padding: 10px 18px; background: var(--green); color:#fff; border:none; border-radius:6px; cursor:pointer;
}
.btn:hover { filter: brightness(.95); }
.btn.secondary { background:#666; }
</style>
</head>
<body>
<h1 id="game-title">Tic-Tac-Toe</h1>
<div class="score">
<p id="player-x-score">Player X: 0</p>
<p id="player-o-score">Player O: 0</p>
</div>
<div class="meta" id="status">X to move</div>
<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 class="controls">
<button class="btn" id="reset-round">New Round</button>
<button class="btn secondary" id="reset-scores">Reset Scores</button>
</div>
<script>
const boardEl = document.getElementById('board');
const cells = Array.from(boardEl.querySelectorAll('.cell'));
const statusEl = document.getElementById('status');
const playerXScoreEl = document.getElementById('player-x-score');
const playerOScoreEl = document.getElementById('player-o-score');
const resetRoundBtn = document.getElementById('reset-round');
const resetScoresBtn = document.getElementById('reset-scores');
let boardState = Array(9).fill('');
let currentPlayer = 'X';
let gameActive = true;
let scoreX = 0;
let scoreO = 0;
const winningLines = [
[0,1,2], [3,4,5], [6,7,8], // rows
[0,3,6], [1,4,7], [2,5,8], // cols
[0,4,8], [2,4,6] // diagonals
];
function updateScoreUI() {
playerXScoreEl.textContent = `Player X: ${scoreX}`;
playerOScoreEl.textContent = `Player O: ${scoreO}`;
}
function setStatus(msg) {
statusEl.textContent = msg;
}
function clearBoardUI() {
cells.forEach(c => {
c.textContent = '';
c.classList.remove('x', 'o', 'disabled');
});
}
function newRound() {
boardState = Array(9).fill('');
gameActive = true;
currentPlayer = 'X';
clearBoardUI();
setStatus(`${currentPlayer} to move`);
}
function resetScores() {
scoreX = 0;
scoreO = 0;
updateScoreUI();
newRound();
}
function determineWinner() {
for (const [a,b,c] of winningLines) {
const va = boardState[a], vb = boardState[b], vc = boardState[c];
if (va && va === vb && vb === vc) return va; // 'X' or 'O'
}
return null;
}
function isBoardFull() {
return boardState.every(v => v !== '');
}
function endGame(message) {
gameActive = false;
// disable remaining cells
cells.forEach((cell, idx) => {
if (!boardState[idx]) cell.classList.add('disabled');
});
setStatus(message);
}
// Single event listener (no duplicates on reset)
boardEl.addEventListener('click', (e) => {
if (!gameActive) return;
const cell = e.target.closest('.cell');
if (!cell || !boardEl.contains(cell)) return;
const idx = Number(cell.dataset.index);
if (boardState[idx]) return; // already played
// Commit move
boardState[idx] = currentPlayer;
cell.textContent = currentPlayer;
cell.classList.add(currentPlayer.toLowerCase()); // 'x' or 'o'
// Check outcome
const winner = determineWinner();
if (winner) {
if (winner === 'X') scoreX++; else scoreO++;
updateScoreUI();
endGame(`Player ${winner} wins!`);
return;
}
if (isBoardFull()) {
endGame(`It's a tie!`);
return;
}
// Next turn
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
setStatus(`${currentPlayer} to move`);
});
resetRoundBtn.addEventListener('click', newRound);
resetScoresBtn.addEventListener('click', resetScores);
// Init
updateScoreUI();
newRound();
</script>
</body>
</html>