Как сделать игру «Камень, ножницы, бумага» на JavaScript и HTML с нуля? Мини-игра кажется простой, но в ней есть весь базовый цикл фронтенд-разработки: разметка интерфейса, стили, обработка действий пользователя, обновление состояния и вывод результата. В этом разборе мы соберём ту же финальную версию, которая уже работает в разделе «Поиграть».
Готовая HTML-игра на чистом JavaScript: выбор хода, случайный ответ компьютера, счёт игрока и компьютера, серия побед, история последних раундов и сброс без перезагрузки страницы.
Сначала попробуйте готовую игру
Сыграйте несколько раундов, чтобы зафиксировать целевое поведение. После этого код читается намного быстрее: вы сразу понимаете, зачем нужен каждый блок.
Как сделать игру «Камень, ножницы, бумага»: структура проекта
Финальная версия состоит из трёх файлов. Именно их мы разбираем в статье, и именно они лежат в блоке исходников внизу.
kamen-nozhnitsy-bumaga/
├── source.html
├── style.css
└── game.js
HTML-разметка игры «Камень, ножницы, бумага»
Разметка описывает не только визуальные блоки, но и точки привязки логики. Атрибуты data-rps-* позволяют JavaScript точно находить элементы без жёсткой привязки к структуре класса или тега.
<main class="rps" data-rps-game>
<header class="rps__header">
<h1>Камень, ножницы, бумага</h1>
<p>Выбирайте ход и набирайте серии побед против компьютера.</p>
</header>
<section class="rps__choices" aria-label="Выбор хода">
<button type="button" data-choice="камень">Камень</button>
<button type="button" data-choice="ножницы">Ножницы</button>
<button type="button" data-choice="бумага">Бумага</button>
</section>
<p class="rps__result" data-rps-result aria-live="polite">Сделайте первый ход.</p>
<section class="rps__stats" aria-label="Текущий счёт">
<p data-rps-score>Счёт: 0 : 0</p>
<p data-rps-streak>Серия побед: 0</p>
</section>
<button class="rps__reset" type="button" data-rps-reset>Сбросить счёт</button>
<section class="rps__history-wrap" aria-label="История раундов">
<h2>Последние раунды</h2>
<ul class="rps__history" data-rps-history>
<li>Пока нет раундов.</li>
</ul>
</section>
</main>
CSS-стили для игры: адаптивный интерфейс
Стили разделены по ролям: контейнер, управляющие элементы, статистика и история. На широком экране кнопки стоят в три колонки, на мобильном переходят в одну колонку для удобного нажатия.
.rps {
width: min(720px, 100%);
background: rgba(9, 14, 30, 0.84);
border: 1px solid rgba(133, 157, 255, 0.35);
border-radius: 20px;
padding: 20px;
}
.rps__choices {
margin-top: 18px;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 10px;
}
.rps__choices button,
.rps__reset {
border: 0;
border-radius: 12px;
cursor: pointer;
font-weight: 600;
}
@media (max-width: 560px) {
.rps__choices {
grid-template-columns: 1fr;
}
}
JavaScript-логика: правила «камень, ножницы, бумага»
Вместо длинной цепочки if/else используем таблицу победных связей. Такой подход компактный и проще расширяется, если позже добавить новые варианты.
let options = ["камень", "ножницы", "бумага"];
let winMap = {
камень: "ножницы",
ножницы: "бумага",
бумага: "камень",
};
function roundResult(player, cpu) {
if (player === cpu) return "draw";
if (winMap[player] === cpu) return "win";
return "lose";
}
JavaScript: счёт, серия побед и история раундов
После каждого раунда обновляем четыре вещи: счёт, серию побед, текст результата и историю. Историю ограничиваем шестью последними записями, чтобы интерфейс оставался компактным.
let playerScore = 0;
let cpuScore = 0;
let winStreak = 0;
let history = [];
function playRound(playerChoice) {
let cpuChoice = randomChoice();
let result = roundResult(playerChoice, cpuChoice);
if (result === "win") {
playerScore += 1;
winStreak += 1;
} else if (result === "lose") {
cpuScore += 1;
winStreak = 0;
} else {
winStreak = 0;
}
history.unshift(
"Вы: " + playerChoice + " / Компьютер: " + cpuChoice + " - " + resultLabel(result)
);
if (history.length > 6) {
history = history.slice(0, 6);
}
updateScore();
renderHistory();
}
Обработчики кликов и сброс
Все кнопки выбора используют один общий обработчик по атрибуту data-choice. Кнопка сброса возвращает игру к старту без перезагрузки страницы: очищает счёт, серию, историю и текст результата.
Array.prototype.forEach.call(choiceButtons, function (button) {
button.addEventListener("click", function () {
let choice = button.getAttribute("data-choice");
if (!choice) return;
playRound(choice);
});
});
resetButton.addEventListener("click", function () {
playerScore = 0;
cpuScore = 0;
winStreak = 0;
history = [];
resultEl.textContent = "Сделайте первый ход.";
updateScore();
renderHistory();
});
Быстрая самопроверка
| Проверка | Что должно произойти |
|---|---|
| Нажать любую кнопку выбора | Появляется строка с ходом игрока, ходом компьютера и итогом раунда |
| Выиграть раунд | Увеличиваются счёт игрока и серия побед |
| Проиграть или сыграть вничью | Серия побед сбрасывается в 0 |
| Сыграть больше шести раундов | В истории остаются только последние шесть записей |
| Нажать «Сбросить счёт» | Счёт, серия и история возвращаются в стартовое состояние |
FAQ
Почему в этой версии используется game.js, а не app.js?
Потому что финальные исходники проекта собраны именно так. В статье сохранено то же именование, чтобы текст и реальные файлы совпадали один в один.
Можно ли сделать режим «до 5 побед»?
Да. Добавьте порог побед и после достижения нужного счёта блокируйте кнопки выбора до следующего сброса.
Как улучшить UX без изменения механики?
Добавьте анимацию активной кнопки, цветовое выделение победы/поражения и короткий таймер между раундами. Правила игры при этом останутся прежними.
Зачем ограничивать историю шестью пунктами?
Это держит интерфейс компактным. Игрок видит ближайший контекст партий, но экран не превращается в длинную ленту событий.
Как развивать игру дальше
Следующий шаг — режим матчей с финальным победителем, например «до 5 побед». Затем можно добавить сохранение статистики в localStorage и переключение тем оформления. Главное правило: добавляйте по одной механике за итерацию, чтобы не потерять читаемость кода.
Ниже — актуальные файлы финальной версии. Это тот же код, который работает во встроенной игре в начале статьи и на отдельной странице в разделе «Поиграть».
Книга по JavaScript для начинающих
«JavaScript с нуля: учимся программировать, создавая игры»Пошаговый формат с маленькими практическими задачами: от базового синтаксиса до первых игровых механик без перегруза теорией.
Читать книгу на ЛитРес →