mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2026-05-11 18:46:39 +08:00
Squash commit
This commit is contained in:
178
domain/tic-tac-toe/index.html
Normal file
178
domain/tic-tac-toe/index.html
Normal file
@@ -0,0 +1,178 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<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;
|
||||
}
|
||||
|
||||
.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>
|
||||
// We will spend the next 45 minutes building a single-page web app that implements a Tic-Tac-Toe game. jQuery has been included for you. We'll implement the following features in order:
|
||||
|
||||
// 1. Render a 3x3 board. You can hardcode some X and O values within the cell for starters.
|
||||
// 2. Implement the add symbol functionality that adds a X or O into a cell whenever the player clicks on it.
|
||||
// 3. Rotate between the players whenever a move is made. Update the current player display.
|
||||
// 4. Check for end game conditions after each move and display the winner if any.
|
||||
// horizontally, vertically, diagonally
|
||||
// 5. After a winner has been determined, disable further moves on the board.
|
||||
// 6. Add a button to reset the game state.
|
||||
(() => {
|
||||
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,
|
||||
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('board-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\'s 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>
|
||||
Reference in New Issue
Block a user