Write a simple game that plays tic-tac-toe against a h
Write a simple game that plays tic-tac-toe against a human player
▶Main candidate · GPT-5.6 Solcandidate
Save the following as tic-tac-toe.html, then open it in a web browser:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tic-Tac-Toe</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
background: #f4f4f4;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
gap: 6px;
justify-content: center;
margin: 25px auto;
}
.cell {
width: 100px;
height: 100px;
border: none;
border-radius: 8px;
background: white;
box-shadow: 0 2px 6px #aaa;
font-size: 48px;
font-weight: bold;
cursor: pointer;
}
.cell:hover:empty {
background: #e8f0ff;
}
#status {
font-size: 20px;
min-height: 24px;
}
#restart {
padding: 10px 20px;
border: none;
border-radius: 6px;
background: #2864dc;
color: white;
font-size: 16px;
cursor: pointer;
}
#restart:hover {
background: #174cae;
}
</style>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<p>You are X. The computer is O.</p>
<div id="status">Your turn</div>
<div id="board"></div>
<button id="restart">Restart Game</button>
<script>
const boardElement = document.getElementById("board");
const statusElement = document.getElementById("status");
const restartButton = document.getElementById("restart");
const winningLines = [
[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 board;
let gameOver;
let computerThinking;
function startGame() {
board = Array(9).fill("");
gameOver = false;
computerThinking = false;
statusElement.textContent = "Your turn";
renderBoard();
}
function renderBoard() {
boardElement.innerHTML = "";
board.forEach((value, index) => {
const cell = document.createElement("button");
cell.className = "cell";
cell.textContent = value;
cell.addEventListener("click", () => playerMove(index));
boardElement.appendChild(cell);
});
}
function playerMove(index) {
if (gameOver || computerThinking || board[index] !== "") return;
board[index] = "X";
renderBoard();
if (finishTurn("X")) return;
computerThinking = true;
statusElement.textContent = "Computer is thinking...";
setTimeout(computerMove, 400);
}
function computerMove() {
// Win if possible, otherwise block the player,
// otherwise choose a random available square.
let move = findWinningMove("O");
if (move === null) {
move = findWinningMove("X");
}
if (move === null && board[4] === "") {
move = 4;
}
if (move === null) {
const available = board
.map((value, index) => value === "" ? index : null)
.filter(index => index !== null);
move = available[Math.floor(Math.random() * available.length)];
}
board[move] = "O";
computerThinking = false;
renderBoard();
if (!finishTurn("O")) {
statusElement.textContent = "Your turn";
}
}
function findWinningMove(symbol) {
for (let i = 0; i < board.length; i++) {
if (board[i] !== "") continue;
board[i] = symbol;
const wins = hasWon(symbol);
board[i] = "";
if (wins) return i;
}
return null;
}
function hasWon(symbol) {
return winningLines.some(line =>
line.every(index => board[index] === symbol)
);
}
function finishTurn(symbol) {
if (hasWon(symbol)) {
gameOver = true;
statusElement.textContent =
symbol === "X" ? "You win!" : "Computer wins!";
return true;
}
if (board.every(cell => cell !== "")) {
gameOver = true;
statusElement.textContent = "It's a draw!";
return true;
}
return false;
}
restartButton.addEventListener("click", startGame);
startGame();
</script>
</body>
</html>▶Deterministic validation0 pass · 0 fail · 1 warn
▶Review iteration · 13 reviewers
Meets AC-1: simple, complete human-vs-computer tic-tac-toe with correct rules and usable UI. No material defects.
The implementation is otherwise a valid simple browser game, but its restart control can corrupt turn order through an uncancelled asynchronous move.
Add let computerTimer = null; let gameId = 0;. In startGame(), call clearTimeout(computerTimer); computerTimer = null; gameId++;. When scheduling, use const id = gameId; computerTimer = setTimeout(() => { if (id === gameId && !gameOver) computerMove(); }, 400);. Set computerTimer = null when the callback runs.
Code is correct, self-contained and runnable; win/block/draw logic verified. Only minor issues: a stale-timeout race on restart and a forkable heuristic AI. Accepting.
- Was the restart-mid-AI-turn path tested, and is a stray computer move acceptable to the user?
▶Main assessment & revisionrevised candidate
Fixed the restart race while preserving the simple human-vs-computer design.
Was the restart-mid-AI-turn path tested, and is a stray computer move acceptable to the user?
Main: The original path was not safely handled, and a stray move is not acceptable. The revision cancels the pending timer and guards callbacks with a game-generation ID.
Save the following as tic-tac-toe.html, then open it in a web browser:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tic-Tac-Toe</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
background: #f4f4f4;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
gap: 6px;
justify-content: center;
margin: 25px auto;
}
.cell {
width: 100px;
height: 100px;
border: none;
border-radius: 8px;
background: white;
box-shadow: 0 2px 6px #aaa;
font-size: 48px;
font-weight: bold;
cursor: pointer;
}
.cell:hover:empty {
background: #e8f0ff;
}
#status {
min-height: 24px;
font-size: 20px;
}
#restart {
padding: 10px 20px;
border: none;
border-radius: 6px;
background: #2864dc;
color: white;
font-size: 16px;
cursor: pointer;
}
#restart:hover {
background: #174cae;
}
</style>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<p>You are X. The computer is O.</p>
<div id="status">Your turn</div>
<div id="board"></div>
<button id="restart" type="button">Restart Game</button>
<script>
const boardElement = document.getElementById("board");
const statusElement = document.getElementById("status");
const restartButton = document.getElementById("restart");
const winningLines = [
[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 board;
let gameOver;
let computerThinking;
let computerTimer = null;
let gameId = 0;
function startGame() {
if (computerTimer !== null) {
clearTimeout(computerTimer);
computerTimer = null;
}
gameId++;
board = Array(9).fill("");
gameOver = false;
computerThinking = false;
statusElement.textContent = "Your turn";
renderBoard();
}
function renderBoard() {
boardElement.innerHTML = "";
board.forEach((value, index) => {
const cell = document.createElement("button");
cell.type = "button";
cell.className = "cell";
cell.textContent = value;
cell.setAttribute(
"aria-label",
value ? `Square ${index + 1}: ${value}` : `Square ${index + 1}: empty`
);
cell.addEventListener("click", () => playerMove(index));
boardElement.appendChild(cell);
});
}
function playerMove(index) {
if (gameOver || computerThinking || board[index] !== "") return;
board[index] = "X";
renderBoard();
if (finishTurn("X")) return;
computerThinking = true;
statusElement.textContent = "Computer is thinking...";
const scheduledGameId = gameId;
computerTimer = setTimeout(() => {
computerTimer = null;
if (scheduledGameId !== gameId || gameOver) return;
computerMove();
}, 400);
}
function computerMove() {
// Win if possible, otherwise block the player,
// take the center, or choose a random available square.
let move = findWinningMove("O");
if (move === null) {
move = findWinningMove("X");
}
if (move === null && board[4] === "") {
move = 4;
}
if (move === null) {
const available = board
.map((value, index) => value === "" ? index : null)
.filter(index => index !== null);
move = available[Math.floor(Math.random() * available.length)];
}
board[move] = "O";
computerThinking = false;
renderBoard();
if (!finishTurn("O")) {
statusElement.textContent = "Your turn";
}
}
function findWinningMove(symbol) {
for (let i = 0; i < board.length; i++) {
if (board[i] !== "") continue;
board[i] = symbol;
const wins = hasWon(symbol);
board[i] = "";
if (wins) return i;
}
return null;
}
function hasWon(symbol) {
return winningLines.some(line =>
line.every(index => board[index] === symbol)
);
}
function finishTurn(symbol) {
if (hasWon(symbol)) {
gameOver = true;
statusElement.textContent =
symbol === "X" ? "You win!" : "Computer wins!";
return true;
}
if (board.every(cell => cell !== "")) {
gameOver = true;
statusElement.textContent = "It's a draw!";
return true;
}
return false;
}
restartButton.addEventListener("click", startGame);
startGame();
</script>
</body>
</html>▶Deterministic validation0 pass · 0 fail · 1 warn
▶Review iteration · 23 reviewers
The game satisfies the request. The revised timer cancellation and game-generation guard correctly prevent stale computer moves after restart.
Meets AC-1. Simple, correct human-vs-AI game; prior restart race is fixed. No material defects found.
Code is correct and self-contained; the restart race is genuinely fixed by timer cancellation plus the generation guard. Remaining points are polish (focus retention, AI strength, format choice), not defects against AC-1.
- Do you want the computer to be unbeatable (minimax) or intentionally beatable?
- Is a browser page the preferred format, or would a terminal program suit better?
▶Main assessment & revisionrevised candidate
Accepted the accessibility polish, upgraded the opponent to unbeatable minimax, and noted that a terminal version is available. The existing restart-race protection remains intact.
Do you want the computer to be unbeatable (minimax) or intentionally beatable?
Main: The revised version uses minimax, making the computer unbeatable.
Is a browser page the preferred format, or would a terminal program suit better?
Main: A self-contained browser page is retained for ease of use; a Python terminal version can be supplied on request.
Save the following as tic-tac-toe.html, then open it in a web browser. You play as X, and the computer uses minimax, so it cannot be beaten.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tic-Tac-Toe</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
background: #f4f4f4;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
gap: 6px;
justify-content: center;
margin: 25px auto;
}
.cell {
width: 100px;
height: 100px;
border: none;
border-radius: 8px;
background: white;
box-shadow: 0 2px 6px #aaa;
font-size: 48px;
font-weight: bold;
cursor: pointer;
}
.cell:hover:not(.filled) {
background: #e8f0ff;
}
.cell:focus-visible {
outline: 4px solid #2864dc;
outline-offset: 2px;
}
#status {
min-height: 24px;
font-size: 20px;
}
#restart {
padding: 10px 20px;
border: none;
border-radius: 6px;
background: #2864dc;
color: white;
font-size: 16px;
cursor: pointer;
}
#restart:hover {
background: #174cae;
}
#restart:focus-visible {
outline: 4px solid #111;
outline-offset: 2px;
}
</style>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<p>You are X. The computer is O.</p>
<div id="status" aria-live="polite">Your turn</div>
<div id="board" aria-label="Tic-tac-toe board"></div>
<button id="restart" type="button">Restart Game</button>
<script>
const boardElement = document.getElementById("board");
const statusElement = document.getElementById("status");
const restartButton = document.getElementById("restart");
const winningLines = [
[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6]
];
const cells = [];
let board;
let gameOver;
let computerThinking;
let computerTimer = null;
let gameId = 0;
function createBoard() {
for (let index = 0; index < 9; index++) {
const cell = document.createElement("button");
cell.type = "button";
cell.className = "cell";
cell.addEventListener("click", () => playerMove(index));
cells.push(cell);
boardElement.appendChild(cell);
}
}
function startGame() {
if (computerTimer !== null) {
clearTimeout(computerTimer);
computerTimer = null;
}
gameId++;
board = Array(9).fill("");
gameOver = false;
computerThinking = false;
statusElement.textContent = "Your turn";
renderBoard();
}
function renderBoard() {
board.forEach((value, index) => {
const cell = cells[index];
cell.textContent = value;
cell.classList.toggle("filled", value !== "");
cell.setAttribute(
"aria-label",
value
? `Square ${index + 1}: ${value}`
: `Square ${index + 1}: empty`
);
});
}
function playerMove(index) {
if (gameOver || computerThinking || board[index] !== "") {
return;
}
board[index] = "X";
renderBoard();
if (finishTurn("X")) {
return;
}
computerThinking = true;
statusElement.textContent = "Computer is thinking...";
const scheduledGameId = gameId;
computerTimer = setTimeout(() => {
computerTimer = null;
if (scheduledGameId !== gameId || gameOver) {
return;
}
computerMove();
}, 400);
}
function computerMove() {
const move = findBestComputerMove();
board[move] = "O";
computerThinking = false;
renderBoard();
if (!finishTurn("O")) {
statusElement.textContent = "Your turn";
}
}
function findBestComputerMove() {
let bestScore = -Infinity;
let bestMove = null;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
const score = minimax(false, 0);
board[index] = "";
if (score > bestScore) {
bestScore = score;
bestMove = index;
}
}
return bestMove;
}
function minimax(computerTurn, depth) {
if (hasWon("O")) {
return 10 - depth;
}
if (hasWon("X")) {
return depth - 10;
}
if (board.every(cell => cell !== "")) {
return 0;
}
if (computerTurn) {
let bestScore = -Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
bestScore = Math.max(
bestScore,
minimax(false, depth + 1)
);
board[index] = "";
}
return bestScore;
}
let bestScore = Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "X";
bestScore = Math.min(
bestScore,
minimax(true, depth + 1)
);
board[index] = "";
}
return bestScore;
}
function hasWon(symbol) {
return winningLines.some(line =>
line.every(index => board[index] === symbol)
);
}
function finishTurn(symbol) {
if (hasWon(symbol)) {
gameOver = true;
statusElement.textContent =
symbol === "X" ? "You win!" : "Computer wins!";
return true;
}
if (board.every(cell => cell !== "")) {
gameOver = true;
statusElement.textContent = "It's a draw!";
return true;
}
return false;
}
restartButton.addEventListener("click", startGame);
createBoard();
startGame();
</script>
</body>
</html>A Python terminal version can also be provided if preferred.
▶Deterministic validation0 pass · 0 fail · 1 warn
Save the following as tic-tac-toe.html, then open it in a web browser. You play as X, and the computer uses minimax, so it cannot be beaten.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tic-Tac-Toe</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
background: #f4f4f4;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
gap: 6px;
justify-content: center;
margin: 25px auto;
}
.cell {
width: 100px;
height: 100px;
border: none;
border-radius: 8px;
background: white;
box-shadow: 0 2px 6px #aaa;
font-size: 48px;
font-weight: bold;
cursor: pointer;
}
.cell:hover:not(.filled) {
background: #e8f0ff;
}
.cell:focus-visible {
outline: 4px solid #2864dc;
outline-offset: 2px;
}
#status {
min-height: 24px;
font-size: 20px;
}
#restart {
padding: 10px 20px;
border: none;
border-radius: 6px;
background: #2864dc;
color: white;
font-size: 16px;
cursor: pointer;
}
#restart:hover {
background: #174cae;
}
#restart:focus-visible {
outline: 4px solid #111;
outline-offset: 2px;
}
</style>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<p>You are X. The computer is O.</p>
<div id="status" aria-live="polite">Your turn</div>
<div id="board" aria-label="Tic-tac-toe board"></div>
<button id="restart" type="button">Restart Game</button>
<script>
const boardElement = document.getElementById("board");
const statusElement = document.getElementById("status");
const restartButton = document.getElementById("restart");
const winningLines = [
[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6]
];
const cells = [];
let board;
let gameOver;
let computerThinking;
let computerTimer = null;
let gameId = 0;
function createBoard() {
for (let index = 0; index < 9; index++) {
const cell = document.createElement("button");
cell.type = "button";
cell.className = "cell";
cell.addEventListener("click", () => playerMove(index));
cells.push(cell);
boardElement.appendChild(cell);
}
}
function startGame() {
if (computerTimer !== null) {
clearTimeout(computerTimer);
computerTimer = null;
}
gameId++;
board = Array(9).fill("");
gameOver = false;
computerThinking = false;
statusElement.textContent = "Your turn";
renderBoard();
}
function renderBoard() {
board.forEach((value, index) => {
const cell = cells[index];
cell.textContent = value;
cell.classList.toggle("filled", value !== "");
cell.setAttribute(
"aria-label",
value
? `Square ${index + 1}: ${value}`
: `Square ${index + 1}: empty`
);
});
}
function playerMove(index) {
if (gameOver || computerThinking || board[index] !== "") {
return;
}
board[index] = "X";
renderBoard();
if (finishTurn("X")) {
return;
}
computerThinking = true;
statusElement.textContent = "Computer is thinking...";
const scheduledGameId = gameId;
computerTimer = setTimeout(() => {
computerTimer = null;
if (scheduledGameId !== gameId || gameOver) {
return;
}
computerMove();
}, 400);
}
function computerMove() {
const move = findBestComputerMove();
board[move] = "O";
computerThinking = false;
renderBoard();
if (!finishTurn("O")) {
statusElement.textContent = "Your turn";
}
}
function findBestComputerMove() {
let bestScore = -Infinity;
let bestMove = null;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
const score = minimax(false, 0);
board[index] = "";
if (score > bestScore) {
bestScore = score;
bestMove = index;
}
}
return bestMove;
}
function minimax(computerTurn, depth) {
if (hasWon("O")) {
return 10 - depth;
}
if (hasWon("X")) {
return depth - 10;
}
if (board.every(cell => cell !== "")) {
return 0;
}
if (computerTurn) {
let bestScore = -Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
bestScore = Math.max(
bestScore,
minimax(false, depth + 1)
);
board[index] = "";
}
return bestScore;
}
let bestScore = Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "X";
bestScore = Math.min(
bestScore,
minimax(true, depth + 1)
);
board[index] = "";
}
return bestScore;
}
function hasWon(symbol) {
return winningLines.some(line =>
line.every(index => board[index] === symbol)
);
}
function finishTurn(symbol) {
if (hasWon(symbol)) {
gameOver = true;
statusElement.textContent =
symbol === "X" ? "You win!" : "Computer wins!";
return true;
}
if (board.every(cell => cell !== "")) {
gameOver = true;
statusElement.textContent = "It's a draw!";
return true;
}
return false;
}
restartButton.addEventListener("click", startGame);
createBoard();
startGame();
</script>
</body>
</html>A Python terminal version can also be provided if preferred.
As a downloadable file please
▶Main candidate · GPT-5.6 Solcandidate
MPLUS_FILE: tic-tac-toe.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tic-Tac-Toe</title>
<style>
body {
margin: 0;
padding: 24px;
font-family: Arial, sans-serif;
text-align: center;
background: #f4f4f4;
color: #222;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
gap: 6px;
justify-content: center;
margin: 25px auto;
}
.cell {
width: 100px;
height: 100px;
border: none;
border-radius: 8px;
background: white;
box-shadow: 0 2px 6px #aaa;
font-size: 48px;
font-weight: bold;
cursor: pointer;
}
.cell:hover:not(:disabled) {
background: #e8f0ff;
}
.cell:disabled {
color: #222;
cursor: default;
opacity: 1;
}
.cell:focus-visible {
outline: 4px solid #2864dc;
outline-offset: 2px;
}
#status {
min-height: 24px;
font-size: 20px;
}
#restart {
padding: 10px 20px;
border: none;
border-radius: 6px;
background: #2864dc;
color: white;
font-size: 16px;
cursor: pointer;
}
#restart:hover {
background: #174cae;
}
#restart:focus-visible {
outline: 4px solid #111;
outline-offset: 2px;
}
@media (max-width: 380px) {
#board {
grid-template-columns: repeat(3, 27vw);
}
.cell {
width: 27vw;
height: 27vw;
}
}
</style>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<p>You are X. The computer is O.</p>
<div id="status" aria-live="polite">Your turn</div>
<div id="board" role="grid" aria-label="Tic-tac-toe board"></div>
<button id="restart" type="button">Restart Game</button>
<script>
const boardElement = document.getElementById("board");
const statusElement = document.getElementById("status");
const restartButton = document.getElementById("restart");
const winningLines = [
[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6]
];
const cells = [];
let board = [];
let gameOver = false;
let computerThinking = false;
let computerTimer = null;
let gameId = 0;
function createBoard() {
for (let index = 0; index < 9; index++) {
const cell = document.createElement("button");
cell.type = "button";
cell.className = "cell";
cell.setAttribute("role", "gridcell");
cell.addEventListener("click", () => playerMove(index));
cells.push(cell);
boardElement.appendChild(cell);
}
}
function startGame() {
if (computerTimer !== null) {
clearTimeout(computerTimer);
computerTimer = null;
}
gameId++;
board = Array(9).fill("");
gameOver = false;
computerThinking = false;
statusElement.textContent = "Your turn";
renderBoard();
}
function renderBoard() {
board.forEach((value, index) => {
const cell = cells[index];
const row = Math.floor(index / 3) + 1;
const column = (index % 3) + 1;
cell.textContent = value;
cell.disabled = value !== "" || gameOver || computerThinking;
cell.setAttribute(
"aria-label",
`Row ${row}, column ${column}: ${value || "empty"}`
);
});
}
function playerMove(index) {
if (gameOver || computerThinking || board[index] !== "") {
return;
}
board[index] = "X";
renderBoard();
if (finishTurn("X")) {
renderBoard();
return;
}
computerThinking = true;
statusElement.textContent = "Computer is thinking...";
renderBoard();
const currentGameId = gameId;
computerTimer = setTimeout(() => {
computerTimer = null;
if (currentGameId !== gameId || gameOver) {
return;
}
computerMove();
}, 400);
}
function computerMove() {
const move = findBestComputerMove();
if (move === null) {
return;
}
board[move] = "O";
computerThinking = false;
renderBoard();
if (!finishTurn("O")) {
statusElement.textContent = "Your turn";
}
renderBoard();
}
function findBestComputerMove() {
let bestScore = -Infinity;
let bestMove = null;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
const score = minimax(false, 0);
board[index] = "";
if (score > bestScore) {
bestScore = score;
bestMove = index;
}
}
return bestMove;
}
function minimax(computerTurn, depth) {
if (hasWon("O")) {
return 10 - depth;
}
if (hasWon("X")) {
return depth - 10;
}
if (board.every(cell => cell !== "")) {
return 0;
}
if (computerTurn) {
let bestScore = -Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
bestScore = Math.max(
bestScore,
minimax(false, depth + 1)
);
board[index] = "";
}
return bestScore;
}
let bestScore = Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "X";
bestScore = Math.min(
bestScore,
minimax(true, depth + 1)
);
board[index] = "";
}
return bestScore;
}
function hasWon(symbol) {
return winningLines.some(line =>
line.every(index => board[index] === symbol)
);
}
function finishTurn(symbol) {
if (hasWon(symbol)) {
gameOver = true;
statusElement.textContent =
symbol === "X" ? "You win!" : "Computer wins!";
return true;
}
if (board.every(cell => cell !== "")) {
gameOver = true;
statusElement.textContent = "It's a draw!";
return true;
}
return false;
}
restartButton.addEventListener("click", startGame);
createBoard();
startGame();
</script>
</body>
</html>Download tic-tac-toe.html and open it in a web browser to play.
▶Deterministic validation0 pass · 0 fail · 1 warn
▶Review iteration · 13 reviewers
The requested downloadable file is correctly provided and contains a self-contained, functional browser game.
AC-1 met: proper downloadable HTML with working unbeatable tic-tac-toe. No material defects found.
Deliverable meets the request: a complete standalone tic-tac-toe HTML file with unbeatable minimax and correct restart/race guards. Only minor accessibility polish (disabled vs aria-disabled, grid roles, focus handling) would improve it.
▶Main assessment & revisionrevised candidate
Adopted the valid accessibility improvements while preserving the working minimax game and restart safeguards.
MPLUS_FILE: tic-tac-toe.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tic-Tac-Toe</title>
<style>
body {
margin: 0;
padding: 24px;
font-family: Arial, sans-serif;
text-align: center;
background: #f4f4f4;
color: #222;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
gap: 6px;
justify-content: center;
margin: 25px auto;
}
.cell {
width: 100px;
height: 100px;
border: none;
border-radius: 8px;
background: white;
box-shadow: 0 2px 6px #aaa;
color: #222;
font-size: 48px;
font-weight: bold;
cursor: pointer;
}
.cell:not([aria-disabled="true"]):hover {
background: #e8f0ff;
}
.cell[aria-disabled="true"] {
cursor: default;
}
.cell:focus-visible {
outline: 4px solid #2864dc;
outline-offset: 2px;
}
#status {
min-height: 24px;
font-size: 20px;
}
#restart {
padding: 10px 20px;
border: none;
border-radius: 6px;
background: #2864dc;
color: white;
font-size: 16px;
cursor: pointer;
}
#restart:hover {
background: #174cae;
}
#restart:focus-visible {
outline: 4px solid #111;
outline-offset: 2px;
}
@media (max-width: 380px) {
#board {
grid-template-columns: repeat(3, 27vw);
}
.cell {
width: 27vw;
height: 27vw;
}
}
</style>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<p>You are X. The computer is O.</p>
<div id="status" aria-live="polite">Your turn</div>
<div id="board" aria-label="Tic-tac-toe board"></div>
<button id="restart" type="button">Restart Game</button>
<script>
const boardElement = document.getElementById("board");
const statusElement = document.getElementById("status");
const restartButton = document.getElementById("restart");
const winningLines = [
[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6]
];
const cells = [];
let board = [];
let gameOver = false;
let computerThinking = false;
let computerTimer = null;
let gameId = 0;
function createBoard() {
for (let index = 0; index < 9; index++) {
const cell = document.createElement("button");
cell.type = "button";
cell.className = "cell";
cell.addEventListener("click", () => playerMove(index));
cells.push(cell);
boardElement.appendChild(cell);
}
}
function startGame(moveFocus = false) {
if (computerTimer !== null) {
clearTimeout(computerTimer);
computerTimer = null;
}
gameId++;
board = Array(9).fill("");
gameOver = false;
computerThinking = false;
statusElement.textContent = "Your turn";
renderBoard();
if (moveFocus) {
cells[0].focus();
}
}
function renderBoard() {
board.forEach((value, index) => {
const cell = cells[index];
const row = Math.floor(index / 3) + 1;
const column = (index % 3) + 1;
const unavailable =
value !== "" || gameOver || computerThinking;
cell.textContent = value;
cell.classList.toggle("filled", value !== "");
cell.setAttribute(
"aria-disabled",
unavailable ? "true" : "false"
);
cell.setAttribute(
"aria-label",
`Row ${row}, column ${column}: ${value || "empty"}`
);
});
}
function focusFirstEmptyCell() {
const emptyIndex = board.findIndex(value => value === "");
if (emptyIndex !== -1) {
cells[emptyIndex].focus();
}
}
function playerMove(index) {
if (gameOver || computerThinking || board[index] !== "") {
return;
}
board[index] = "X";
renderBoard();
if (finishTurn("X")) {
renderBoard();
restartButton.focus();
return;
}
computerThinking = true;
statusElement.textContent = "Computer is thinking...";
renderBoard();
const currentGameId = gameId;
computerTimer = setTimeout(() => {
computerTimer = null;
if (currentGameId !== gameId || gameOver) {
return;
}
computerMove();
}, 400);
}
function computerMove() {
const move = findBestComputerMove();
if (move === null) {
return;
}
board[move] = "O";
computerThinking = false;
renderBoard();
if (finishTurn("O")) {
renderBoard();
restartButton.focus();
return;
}
statusElement.textContent = "Your turn";
renderBoard();
focusFirstEmptyCell();
}
function findBestComputerMove() {
let bestScore = -Infinity;
let bestMove = null;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
const score = minimax(false, 0);
board[index] = "";
if (score > bestScore) {
bestScore = score;
bestMove = index;
}
}
return bestMove;
}
function minimax(computerTurn, depth) {
if (hasWon("O")) {
return 10 - depth;
}
if (hasWon("X")) {
return depth - 10;
}
if (board.every(cell => cell !== "")) {
return 0;
}
if (computerTurn) {
let bestScore = -Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
bestScore = Math.max(
bestScore,
minimax(false, depth + 1)
);
board[index] = "";
}
return bestScore;
}
let bestScore = Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "X";
bestScore = Math.min(
bestScore,
minimax(true, depth + 1)
);
board[index] = "";
}
return bestScore;
}
function hasWon(symbol) {
return winningLines.some(line =>
line.every(index => board[index] === symbol)
);
}
function finishTurn(symbol) {
if (hasWon(symbol)) {
gameOver = true;
statusElement.textContent =
symbol === "X" ? "You win!" : "Computer wins!";
return true;
}
if (board.every(cell => cell !== "")) {
gameOver = true;
statusElement.textContent = "It's a draw!";
return true;
}
return false;
}
restartButton.addEventListener("click", () => startGame(true));
createBoard();
startGame();
</script>
</body>
</html>Download tic-tac-toe.html and open it in a web browser to play.
▶Deterministic validation0 pass · 0 fail · 1 warn
▶Review iteration · 23 reviewers
The downloadable HTML file satisfies the request and contains a functional human-versus-computer tic-tac-toe game.
Downloadable HTML file meets AC-1; game logic and restart safeguards are sound. No material defects.
Deliverable meets the request: a single downloadable, self-contained tic-tac-toe.html with a correct unbeatable minimax opponent, restart/timer guards, and no external dependencies. Only cosmetic/a11y polish items remain (focus jump, unnamed board container, dead .filled class).
- Was the file verified end-to-end in a browser (win, loss-impossible, draw, restart mid-'thinking') after the aria-disabled refactor, or only reasoned about?
▶Main assessment & revisionrevised candidate
Accepted the three accessibility and cleanup improvements; core game logic remains unchanged.
Was the file verified end-to-end in a browser after the aria-disabled refactor, or only reasoned about?
Main: It was reviewed by reasoning rather than independently executed in a browser in this environment.
MPLUS_FILE: tic-tac-toe.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tic-Tac-Toe</title>
<style>
body {
margin: 0;
padding: 24px;
font-family: Arial, sans-serif;
text-align: center;
background: #f4f4f4;
color: #222;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
gap: 6px;
justify-content: center;
margin: 25px auto;
}
.cell {
width: 100px;
height: 100px;
border: none;
border-radius: 8px;
background: white;
box-shadow: 0 2px 6px #aaa;
color: #222;
font-size: 48px;
font-weight: bold;
cursor: pointer;
}
.cell:not([aria-disabled="true"]):hover {
background: #e8f0ff;
}
.cell[aria-disabled="true"] {
cursor: default;
}
.cell:focus-visible {
outline: 4px solid #2864dc;
outline-offset: 2px;
}
#status {
min-height: 24px;
font-size: 20px;
}
#restart {
padding: 10px 20px;
border: none;
border-radius: 6px;
background: #2864dc;
color: white;
font-size: 16px;
cursor: pointer;
}
#restart:hover {
background: #174cae;
}
#restart:focus-visible {
outline: 4px solid #111;
outline-offset: 2px;
}
@media (max-width: 380px) {
#board {
grid-template-columns: repeat(3, 27vw);
}
.cell {
width: 27vw;
height: 27vw;
}
}
</style>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<p>You are X. The computer is O.</p>
<div id="status" aria-live="polite">Your turn</div>
<div
id="board"
role="group"
aria-label="Tic-tac-toe board"
></div>
<button id="restart" type="button">Restart Game</button>
<script>
const boardElement = document.getElementById("board");
const statusElement = document.getElementById("status");
const restartButton = document.getElementById("restart");
const winningLines = [
[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6]
];
const cells = [];
let board = [];
let gameOver = false;
let computerThinking = false;
let computerTimer = null;
let gameId = 0;
function createBoard() {
for (let index = 0; index < 9; index++) {
const cell = document.createElement("button");
cell.type = "button";
cell.className = "cell";
cell.addEventListener("click", () => playerMove(index));
cells.push(cell);
boardElement.appendChild(cell);
}
}
function startGame(moveFocus = false) {
if (computerTimer !== null) {
clearTimeout(computerTimer);
computerTimer = null;
}
gameId++;
board = Array(9).fill("");
gameOver = false;
computerThinking = false;
statusElement.textContent = "Your turn";
renderBoard();
if (moveFocus) {
cells[0].focus();
}
}
function renderBoard() {
board.forEach((value, index) => {
const cell = cells[index];
const row = Math.floor(index / 3) + 1;
const column = (index % 3) + 1;
const unavailable =
value !== "" || gameOver || computerThinking;
cell.textContent = value;
cell.setAttribute(
"aria-disabled",
unavailable ? "true" : "false"
);
cell.setAttribute(
"aria-label",
`Row ${row}, column ${column}: ${value || "empty"}`
);
});
}
function playerMove(index) {
if (gameOver || computerThinking || board[index] !== "") {
return;
}
board[index] = "X";
renderBoard();
if (finishTurn("X")) {
renderBoard();
restartButton.focus();
return;
}
computerThinking = true;
statusElement.textContent = "Computer is thinking...";
renderBoard();
const currentGameId = gameId;
computerTimer = setTimeout(() => {
computerTimer = null;
if (currentGameId !== gameId || gameOver) {
return;
}
computerMove();
}, 400);
}
function computerMove() {
const move = findBestComputerMove();
if (move === null) {
return;
}
board[move] = "O";
computerThinking = false;
renderBoard();
if (finishTurn("O")) {
renderBoard();
restartButton.focus();
return;
}
statusElement.textContent = "Your turn";
renderBoard();
}
function findBestComputerMove() {
let bestScore = -Infinity;
let bestMove = null;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
const score = minimax(false, 0);
board[index] = "";
if (score > bestScore) {
bestScore = score;
bestMove = index;
}
}
return bestMove;
}
function minimax(computerTurn, depth) {
if (hasWon("O")) {
return 10 - depth;
}
if (hasWon("X")) {
return depth - 10;
}
if (board.every(cell => cell !== "")) {
return 0;
}
if (computerTurn) {
let bestScore = -Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "O";
bestScore = Math.max(
bestScore,
minimax(false, depth + 1)
);
board[index] = "";
}
return bestScore;
}
let bestScore = Infinity;
for (let index = 0; index < board.length; index++) {
if (board[index] !== "") {
continue;
}
board[index] = "X";
bestScore = Math.min(
bestScore,
minimax(true, depth + 1)
);
board[index] = "";
}
return bestScore;
}
function hasWon(symbol) {
return winningLines.some(line =>
line.every(index => board[index] === symbol)
);
}
function finishTurn(symbol) {
if (hasWon(symbol)) {
gameOver = true;
statusElement.textContent =
symbol === "X" ? "You win!" : "Computer wins!";
return true;
}
if (board.every(cell => cell !== "")) {
gameOver = true;
statusElement.textContent = "It's a draw!";
return true;
}
return false;
}
restartButton.addEventListener("click", () => startGame(true));
createBoard();
startGame();
</script>
</body>
</html>Download tic-tac-toe.html and open it in a web browser to play.
▶Deterministic validation0 pass · 0 fail · 1 warn
Download tic-tac-toe.html and open it in a web browser to play.