Создание игры "Крестики-нолики"

Тренажер по работе с HTML DOM на JavaScript для пользователей с начальным и средним уровнем подготовки.

Тренажер JavaScript: Покоряем HTML DOM

В этом модуле вы шаг за шагом создадите работающую игру «Крестики-нолики», используя манипуляции с DOM. Задания построены логически: от генерации игрового поля и обработки кликов до реализации игровой логики (смена игрока, проверка победы) и функции перезапуска игры. Вам предстоит работать с методами поиска элементов, созданием узлов, событиями и свойствами содержимого элементов. Итоговый результат будет полностью функциональной мини-игрой.

Список тем

Генерация игрового поля

id: 37088_ttt_01

Для начала нам нужно создать сетку игры 3x3. У нас есть пустой контейнер. Ваша задача — с помощью цикла создать 9 элементов `div`, добавить каждому класс `cell` и поместить их внутрь игрового поля.

CSS
.board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; width: 150px; margin: 0 auto; } .cell { width: 50px; height: 50px; background: #eee; display: flex; align-items: center; justify-content: center; font-size: 24px; cursor: pointer; border: 1px solid #ccc; }
HTML
Восстановить HTML
<div id="game-board" class="board"></div>
JavaScript
const board = document.getElementById("game-board");

for (let i = 0; i < 9; i++) {
    const cell = document.input__1("div");
    cell.input__2 = "cell";
    board.input__3(cell);
}
Используйте метод `createElement` для создания элемента, свойство `className` для назначения класса и `appendChild` для вставки элемента в родительский контейнер.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Обработка клика по ячейке

id: 37088_ttt_02

Поле создано. Теперь нужно научить ячейки реагировать на нажатия. Найдите все элементы с классом `.cell` и добавьте каждому обработчик события клика, который будет выводить в консоль текст 'Click'.

CSS
.board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; width: 150px; margin: 0 auto; } .cell { width: 50px; height: 50px; background: #eee; border: 1px solid #ccc; cursor: pointer; }
HTML
Восстановить HTML
<div class="board"><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div></div>
JavaScript
const cells = document.input__1(".cell");

cells.forEach(cell => {
    cell.input__2("input__3", function() {
        console.log("Click");
    });
});
Используйте `querySelectorAll` для поиска всех ячеек и `addEventListener` для подписки на событие. В цикле `forEach` переберите найденные элементы.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Отображение хода (Крестик)

id: 37088_ttt_03

При клике мы должны узнать, на какой именно элемент нажали, и записать в него символ 'X'. Используйте объект события для доступа к целевому элементу.

CSS
.board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; width: 150px; margin: 0 auto; } .cell { width: 50px; height: 50px; background: #eee; display: flex; align-items: center; justify-content: center; font-size: 24px; border: 1px solid #ccc; cursor: pointer; }
HTML
Восстановить HTML
<div class="board"><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div></div>
JavaScript
const cells = document.querySelectorAll(".cell");

cells.forEach(cell => {
    cell.addEventListener("click", function(event) {
        const targetCell = event.input__1;
        targetCell.input__2 = "X";
    });
});
Объект события `event` передается в функцию. Свойство `target` указывает на элемент, по которому кликнули. Измените его текстовое содержимое.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Смена игрока

id: 37088_ttt_04

Игра не может состоять только из крестиков. Реализуйте логику смены игрока: если текущий игрок 'X', то следующим должен стать 'O', и наоборот. Заполните пропуски в тернарном операторе.

CSS
.status { margin-bottom: 10px; font-weight: bold; }
HTML
Восстановить HTML
<div id="status" class="status">Ходит: X</div>
JavaScript
let currentPlayer = "X";
const statusDisplay = document.getElementById("status");

function changePlayer() {
    currentPlayer = currentPlayer === "X" ? "input__1" : "input__2";
    statusDisplay.textContent = "Ходит: " + currentPlayer;
}

// Эмуляция вызова для проверки
changePlayer();
Тернарный оператор работает как if/else. Условие ? значение_если_истина : значение_если_ложь.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Проверка занятости ячейки

id: 37088_ttt_05

Сейчас можно нажать на уже заполненную ячейку и перезаписать значение. Это неправильно. Добавьте условие: если в ячейке уже есть текст (не пустая строка), то мы выходим из функции и ничего не делаем.

CSS
.cell { width: 50px; height: 50px; background: #eee; border: 1px solid #ccc; display: flex; align-items: center; justify-content: center; }
HTML
Восстановить HTML
<div class="cell">X</div>
JavaScript
const cell = document.querySelector(".cell");

function handleCellClick(clickedCell) {
    // Проверяем, занята ли ячейка
    if (clickedCell.input__1 !== "") {
        return;
    }
    
    console.log("Ход выполнен");
}

handleCellClick(cell);
Проверьте свойство `textContent` ячейки. Если оно не равно пустой строке `""`, используйте `return` для выхода.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Логика победы: Проверка комбинации

id: 37088_ttt_06

Самая сложная часть — определить победителя. У нас есть массив выигрышных комбинаций (индексы ячеек). Вам нужно внутри цикла проверки сравнить значения трех ячеек, входящих в комбинацию. Если они равны и не пусты — это победа.

CSS
.board { display: none; }
HTML
Восстановить HTML
<div class="board"></div>
JavaScript
const cells = [/*...массив 9 элементов...*/]; 
// Представим, что cells уже заполнен элементами DOM

const winningConditions = [
    [0, 1, 2], [3, 4, 5], [6, 7, 8] // и другие...
];

function checkResult() {
    let roundWon = false;
    for (let i = 0; i < winningConditions.length; i++) {
        const winCondition = winningConditions[i];
        let a = cells[winCondition[0]].textContent;
        let b = cells[winCondition[1]].textContent;
        let c = cells[winCondition[2]].textContent;

        if (a === "" || b === "" || c === "") {
            continue;
        }
        
        if (a === input__1 && b === input__2) {
            roundWon = true;
            break;
        }
    }
    return roundWon;
}
Вам даны индексы a, b и c. Нужно получить элементы из массива `cells` по этим индексам и сравнить их содержимое (`textContent`). A должно быть равно B, и B должно быть равно C.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Визуализация победы

id: 37088_ttt_07

Если игрок победил, давайте выделим выигрышную комбинацию цветом. Вам нужно добавить класс `winner` элементам, которые составили линию победы.

CSS
.board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; width: 150px; margin: 0 auto; } .cell { width: 50px; height: 50px; background: #eee; display: flex; align-items: center; justify-content: center; border: 1px solid #ccc; } .winner { background-color: #90ee90; }
HTML
Восстановить HTML
<div class="board"><div class="cell">X</div><div class="cell">X</div><div class="cell">X</div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div></div>
JavaScript
const cells = document.querySelectorAll(".cell");
const winCondition = [0, 1, 2]; // Индексы победившей строки

// Добавляем класс winner победным ячейкам
cells[winCondition[0]].input__1.add("winner");
cells[winCondition[1]].input__1.add("winner");
cells[winCondition[2]].input__1.add("input__2");
Используйте `classList.add` для добавления класса элементам массива `cells` по индексам из `winCondition`.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Кнопка перезапуска игры

id: 37088_ttt_08

Игра закончилась, нужно начать заново. Напишите функцию очистки поля. Она должна пройтись по всем ячейкам и очистить их текстовое содержимое.

CSS
.cell { width: 50px; height: 50px; background: #eee; border: 1px solid #ccc; margin: 2px; display: inline-block;} button { margin-top: 10px; }
HTML
Восстановить HTML
<div><div class="cell">X</div><div class="cell">O</div><div class="cell">X</div></div><button id="restart">Заново</button>
JavaScript
const cells = document.querySelectorAll(".cell");
const restartBtn = document.getElementById("restart");

restartBtn.addEventListener("click", function() {
    cells.forEach(cell => {
        cell.input__1 = "";
        cell.classList.input__2("winner"); // на всякий случай убираем класс победы
    });
});
Внутри цикла по ячейкам установите `textContent` в пустую строку `""`.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку
НайтиКурс.Ру