Tic Tac Toe
Render Board
<!DOCTYPE html> <html lang="en"> <head> <title>Chessboard</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <style> body { font-family: 'Helvetica', sans-serif; } .board-cell { border: 1px solid #666; box-sizing: border-box; display: inline-block; font-size: 32px; height: 100px; line-height: 100px; text-align: center; width: 100px; margin-left: -1px; margin-top: -1px; } .board-cell .content { display: inline-block; vertical-align: middle; } </style> </head> <body> <h1>Tic Tac Toe</h1> <p>Current player turn: <span class="js-current-player"></span></p> <div class="js-board"> </div> <button class="js-reset">Reset</button> <script> (() => { function init() { const DOM = { $currentPlayer: document.querySelector('.js-current-player'), $board: document.querySelector('.js-board'), $resetButton: document.querySelector('.js-reset'), } const SIZE = 3; function initialState() { return { boardModel: Array(SIZE).fill(null).map(_ => Array(SIZE).fill(null)), players: ['X', 'O'], currentPlayer: 0, // 0 or 1 gameEnded: false, turn: 0, } } let state = initialState(); function renderBoard() { DOM.$currentPlayer.textContent = state.players[state.currentPlayer]; // Assuming SIZE > 0; DOM.$board.innerHTML = '' for(let i = 0; i < SIZE; i++) { const $row = document.createElement('div'); $row.classList.add('border-row'); for(let j = 0; j < SIZE; j++) { const $cell = document.createElement('div'); $cell.classList.add('board-cell'); $cell.setAttribute('data-i', i); $cell.setAttribute('data-j', j); const $content = document.createElement('span'); $content.classList.add('content'); $content.textContent = state.boardModel[i][j]; $cell.appendChild($content); $row.appendChild($cell) } DOM.$board.appendChild($row); } } renderBoard(); } document.addEventListener('DOMContentLoaded', init) })() </script> </body> </html>
Attach Event Listeners
DOM.$board.addEventListener("click", (event) => {
if (state.gameEnded) {
return;
}
if (!event.target.classList.contains("board-cell")) {
return;
}
// get chosen cell
const $cell = event.target;
const i = parseInt($cell.getAttribute("data-i"), 10);
const j = parseInt($cell.getAttribute("data-j"), 10);
if (state.boardModel[i][j] !== null) {
alert("Cell has already been taken!");
return;
}
// get current player
const player = state.players[state.currentPlayer];
// mark the move
state.boardModel[i][j] = player;
// after mark the move, we start to check if it is a winning move
// const winningMove = checkWinning(state.boardModel, player);
const winningMove = false;
// increase the turn counter
state.turn++;
if (!winningMove) {
state.currentPlayer = state.currentPlayer === 0 ? 1 : 0;
// re-render with new mark
renderBoard();
if (state.turn === SIZE * SIZE) {
alert("It is a draw!");
}
} else {
renderBoard();
state.gameEnded = true;
alert(`Player ${player} wins!`);
}
});
DOM.$resetButton.addEventListener("click", () => {
if (confirm("Start a new game?")) {
state = initialState();
renderBoard();
}
});
<!DOCTYPE html> <html lang="en"> <head> <title>Chessboard</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <style> body { font-family: 'Helvetica', sans-serif; } .board-cell { border: 1px solid #666; box-sizing: border-box; display: inline-block; font-size: 32px; height: 100px; line-height: 100px; text-align: center; width: 100px; margin-left: -1px; margin-top: -1px; } .board-cell .content { display: inline-block; vertical-align: middle; } </style> </head> <body> <h1>Tic Tac Toe</h1> <p>Current player turn: <span class="js-current-player"></span></p> <div class="js-board"> </div> <button class="js-reset">Reset</button> <script> (() => { function init() { const DOM = { $currentPlayer: document.querySelector('.js-current-player'), $board: document.querySelector('.js-board'), $resetButton: document.querySelector('.js-reset'), } const SIZE = 3; function initialState() { return { boardModel: Array(SIZE).fill(null).map(_ => Array(SIZE).fill(null)), players: ['X', 'O'], currentPlayer: 0, // 0 or 1 gameEnded: false, turn: 0, } } let state = initialState(); function renderBoard() { DOM.$currentPlayer.textContent = state.players[state.currentPlayer]; // Assuming SIZE > 0; DOM.$board.innerHTML = '' for(let i = 0; i < SIZE; i++) { const $row = document.createElement('div'); $row.classList.add('border-row'); for(let j = 0; j < SIZE; j++) { const $cell = document.createElement('div'); $cell.classList.add('board-cell'); $cell.setAttribute('data-i', i); $cell.setAttribute('data-j', j); const $content = document.createElement('span'); $content.classList.add('content'); $content.textContent = state.boardModel[i][j]; $cell.appendChild($content); $row.appendChild($cell) } DOM.$board.appendChild($row); } } function attachEventListeners() { DOM.$board.addEventListener('click', (event) => { if (state.gameEnded) { return; } if (!event.target.classList.contains('board-cell')) { return; } const $cell = event.target; const i = parseInt($cell.getAttribute('data-i'), 10); const j = parseInt($cell.getAttribute('data-j'), 10); if (state.boardModel[i][j] !== null) { alert('Cell has already been taken!'); return; } const player = state.players[state.currentPlayer]; state.boardModel[i][j] = player; const winningMove = false; state.turn++; if (!winningMove) { state.currentPlayer = (state.currentPlayer + 1) % 2; renderBoard(); if (state.turn === SIZE * SIZE) { alert('It is a draw!'); } } else { renderBoard(); state.gameEnded = true; alert(`Player \${player} wins!`); } }); DOM.$resetButton.addEventListener('click', () => { if (confirm('Start a new game?')) { state = initialState(); renderBoard(); } }); } renderBoard(); attachEventListeners(); } document.addEventListener('DOMContentLoaded', init) })() </script> </body> </html>
Check Winning
function checkWinning(board, player) {
// check horizontal
for (let i = 0; i < SIZE; i++) {
if (board[i].every((cell) => cell === player)) {
return true;
}
}
// check vertical
for (let j = 0; j < SIZE; i++) {
let verticalAllPlayer = true;
for (let i = 0; i < SIZE; i++) {
if (board[i][j] != player) {
verticalAllPlayer = false;
break;
}
}
if (verticalAllPlayer) {
return verticalAllPlayer;
}
}
// check diagonal south-east
let diagonalAllPlayer = true;
for (let i = 0; i < SIZE; i++) {
if (board[i][i] !== player) {
diagonalAllPlayer = false;
break;
}
}
if (diagonalAllPlayer) {
return diagonalAllPlayer;
}
// check diagonal north-east
let diagonalAllPlayer = true;
// i = 2, j = 0 ; i = 1, j = 1; i = 2; j = 0;
for (let i = SIZE - 1, j = 0; i >= 0; i--, j++) {
if (board[i][i] !== player) {
diagonalAllPlayer = false;
break;
}
}
if (diagonalAllPlayer) {
return diagonalAllPlayer;
}
return false;
}
<!DOCTYPE html> <html lang="en"> <head> <title>Chessboard</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <style> body { font-family: 'Helvetica', sans-serif; } .board-cell { border: 1px solid #666; box-sizing: border-box; display: inline-block; font-size: 32px; height: 100px; line-height: 100px; text-align: center; width: 100px; margin-left: -1px; margin-top: -1px; } .board-cell .content { display: inline-block; vertical-align: middle; } </style> </head> <body> <h1>Tic Tac Toe</h1> <p>Current player turn: <span class="js-current-player"></span></p> <div class="js-board"> </div> <button class="js-reset">Reset</button> <script> (() => { function init() { const DOM = { $currentPlayer: document.querySelector('.js-current-player'), $board: document.querySelector('.js-board'), $resetButton: document.querySelector('.js-reset'), } const SIZE = 3; function initialState() { return { boardModel: Array(SIZE).fill(null).map(_ => Array(SIZE).fill(null)), players: ['X', 'O'], currentPlayer: 0, // 0 or 1 gameEnded: false, turn: 0, } } let state = initialState(); function renderBoard() { DOM.$currentPlayer.textContent = state.players[state.currentPlayer]; // Assuming SIZE > 0; DOM.$board.innerHTML = '' for(let i = 0; i < SIZE; i++) { const $row = document.createElement('div'); $row.classList.add('border-row'); for(let j = 0; j < SIZE; j++) { const $cell = document.createElement('div'); $cell.classList.add('board-cell'); $cell.setAttribute('data-i', i); $cell.setAttribute('data-j', j); const $content = document.createElement('span'); $content.classList.add('content'); $content.textContent = state.boardModel[i][j]; $cell.appendChild($content); $row.appendChild($cell) } DOM.$board.appendChild($row); } } function checkWinning(board, player) { // Check horizontal. for (let i = 0; i < SIZE; i++) { if (board[i].every(cell => cell === player)) { return true; } } // Check vertical. for (let j = 0; j < SIZE; j++) { let verticalAllPlayer = true; for (let i = 0; i < SIZE; i++) { if (board[i][j] !== player) { verticalAllPlayer = false; break; } } if (verticalAllPlayer) { return verticalAllPlayer; } } // Check diagonal South-East. let diagonalAllPlayer = true; for (let i = 0; i < SIZE; i++) { if (board[i][i] !== player) { diagonalAllPlayer = false; break; } } if (diagonalAllPlayer) { return diagonalAllPlayer; } // Check diagonal North-East. diagonalAllPlayer = true; for (let i = SIZE - 1, j = 0; i >= 0; i--, j++) { if (board[i][j] !== player) { diagonalAllPlayer = false; break; } } if (diagonalAllPlayer) { return diagonalAllPlayer; } return false; } function attachEventListeners() { DOM.$board.addEventListener('click', (event) => { if (state.gameEnded) { return; } if (!event.target.classList.contains('board-cell')) { return; } const $cell = event.target; const i = parseInt($cell.getAttribute('data-i'), 10); const j = parseInt($cell.getAttribute('data-j'), 10); if (state.boardModel[i][j] !== null) { alert('Cell has already been taken!'); return; } const player = state.players[state.currentPlayer]; state.boardModel[i][j] = player; const winningMove = checkWinning(state.boardModel, player); state.turn++; if (!winningMove) { state.currentPlayer = (state.currentPlayer + 1) % 2; renderBoard(); if (state.turn === SIZE * SIZE) { alert('It is a draw!'); } } else { renderBoard(); state.gameEnded = true; alert(`Player \${player} wins!`); } }); DOM.$resetButton.addEventListener('click', () => { if (confirm('Start a new game?')) { state = initialState(); renderBoard(); } }); } renderBoard(); attachEventListeners(); } document.addEventListener('DOMContentLoaded', init) })() </script> </body> </html>
Last Update: 12:13 - 22 April 2024