Найти в Дзене
html сервисы и приколы

Как написать игру "Сапер" в html

Игра «Сапёр» — классика, которая проверяет логику и внимательность игрока. В этой статье мы шаг за шагом создадим свою версию этой игры, используя HTML, CSS и JavaScript. Вы сможете интегрировать её на свой сайт или использовать как основу для изучения веб-разработки. Кроме того, мы рассмотрим варианты улучшения этой игры в текущем виде. Для начала создадим базовую структуру HTML-документа, включающую панель настроек и игровое поле. <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Сапёр</title>
</head>
<body>
<div class="settings">
<label>Ширина: <input type="number" id="width" value="10" min="5"></label>
<label>Высота: <input type="number" id="height" value="10" min="5"></label>
<label>Бомбы: <input type="number" id="bombs" value="10" min="1"></label>
<button id="new-game">Новая игра</button>
</div>
<div id="game-board" class="game-board"></div>
</body>
</html> Тепе
Оглавление

Подробное руководство

Игра «Сапёр» — классика, которая проверяет логику и внимательность игрока. В этой статье мы шаг за шагом создадим свою версию этой игры, используя HTML, CSS и JavaScript. Вы сможете интегрировать её на свой сайт или использовать как основу для изучения веб-разработки. Кроме того, мы рассмотрим варианты улучшения этой игры в текущем виде.

Шаг 1: Подготовка структуры HTML

Для начала создадим базовую структуру HTML-документа, включающую панель настроек и игровое поле.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Сапёр</title>
</head>
<body>
<div class="settings">
<label>Ширина: <input type="number" id="width" value="10" min="5"></label>
<label>Высота: <input type="number" id="height" value="10" min="5"></label>
<label>Бомбы: <input type="number" id="bombs" value="10" min="1"></label>
<button id="new-game">Новая игра</button>
</div>
<div id="game-board" class="game-board"></div>
</body>
</html>

Что здесь происходит:

  1. Панель настроек: позволяет игроку задавать параметры игры (ширину, высоту, количество бомб).
  2. Игровое поле: будет сгенерировано динамически с помощью JavaScript.

Шаг 2: Добавление стилей CSS

Теперь оформим элементы игры. Нам нужно создать стили для кнопок, клеток игрового поля, а также состояния клеток (открытые, закрытые, с флажками).

<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
}
.settings {
margin-bottom: 10px;
}
.game-board {
display: grid;
gap: 2px;
margin-top: 10px;
}
.cell {
width: 30px;
height: 30px;
background-color: #ddd;
border: 1px solid #aaa;
text-align: center;
line-height: 30px;
font-weight: bold;
cursor: pointer;
user-select: none;
}
.cell.revealed {
background-color: #eee;
}
.cell.bomb {
background-color: red;
}
.cell.flag {
background-color: #ccc;
color: red;
}
.cell.missed {
background-color: lightgreen;
}
</style>

Объяснение:

  • .cell: базовый стиль клетки игрового поля.
  • .revealed: стили для открытых клеток.
  • .bomb: клетки с бомбами окрашиваются в красный при проигрыше.
  • .flag: флажок, обозначающий предполагаемое место бомбы.

Шаг 3: Реализация логики игры с JavaScript

Игра «Сапёр» — это классическая головоломка, где игрок должен открывать клетки на игровом поле и избегать попадания на клетки с бомбами. Цель игры — отметить все клетки с бомбами флажками и открыть остальные клетки. Давайте рассмотрим основные элементы и логику игры.

1. Игровое поле

Игровое поле — это сетка клеток заданного размера, где каждая клетка может содержать:

  • Бомбу — игрок проигрывает, если откроет эту клетку.
  • Число — показывает, сколько бомб находится в соседних клетках.
  • Пустую клетку — если в соседних клетках нет бомб, клетка остаётся пустой. В этом случае открываются соседние клетки автоматически.

Игрок сам выбирает размеры поля и количество бомб, что влияет на сложность игры.

2. Основные действия игрока

Игрок взаимодействует с игровым полем следующими способами:

  • Левый клик: открывает клетку. Если в клетке находится бомба, игра заканчивается проигрышем.
    Если клетка пустая или содержит число, она открывается. При этом, если число равно нулю, автоматически открываются соседние клетки.
  • Правый клик: ставит или убирает флажок на клетке. Флажок используется для отметки предполагаемых мест расположения бомб.
    Флажок можно снять, если игрок передумал.

3. Логика размещения бомб

  • Бомбы размещаются случайным образом на игровом поле при начале новой игры.
  • Каждая клетка, которая не содержит бомбу, получает числовое значение, указывающее количество бомб в соседних клетках.
  • Для подсчёта чисел используются все 8 соседних клеток (если они находятся в пределах поля).

4. Победа и поражение

Игра может закончиться двумя способами:

Проигрыш:

  • Происходит, если игрок открывает клетку с бомбой.
  • После этого все бомбы на поле становятся видимыми, и игра завершена.

Победа:

  • Игрок выигрывает, если:Все бомбы отмечены флажками.
    Все клетки без бомб открыты.
  • Логика победы проверяется каждый раз, когда игрок ставит флажок или открывает клетку. Если условия победы выполнены, игра завершается с поздравлением.

5. Распространение открытия пустых клеток

Если игрок открывает пустую клетку, у которой нет соседних бомб (число «0»), игра автоматически открывает соседние клетки. Этот процесс продолжается до тех пор, пока не будут найдены клетки с числами.

6. Проверка флажков

Флажки помогают игроку запоминать предполагаемое расположение бомб, но они не влияют на результат, пока не проверяются условия победы. Все бомбы должны быть отмечены флажками, чтобы победить.

7. Алгоритмы

Для корректной работы игры используются следующие алгоритмы:

  • Генерация бомб: бомбы размещаются случайно с учётом ограничений.
  • Подсчёт соседних бомб: для каждой клетки определяется количество соседних бомб.
  • Распространение пустых клеток: открываются все соседние клетки, если клетка пустая.
  • Проверка победы: после каждого действия проверяется, выполнены ли условия победы.

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

<script>
const boardElement = document.getElementById('game-board');
const widthInput = document.getElementById('width');
const heightInput = document.getElementById('height');
const bombsInput = document.getElementById('bombs');
const newGameButton = document.getElementById('new-game');

let cells = [];
let flaggedBombs = 0;
let gameOver = false;

function createBoard(width, height, bombs) {
boardElement.innerHTML = '';
boardElement.style.gridTemplateColumns = `repeat(${width}, 30px)`;

cells = Array.from({ length: width * height }, (_, index) => {
return { id: index, bomb: false, revealed: false, flagged: false, count: 0 };
});

let bombPositions = new Set();
while (bombPositions.size < bombs) {
bombPositions.add(Math.floor(Math.random() * cells.length));
}
bombPositions.forEach(pos => cells[pos].bomb = true);

cells.forEach((cell, index) => {
const cellElement = document.createElement('div');
cellElement.classList.add('cell');
cellElement.addEventListener('click', () => revealCell(cell, cellElement));
cellElement.addEventListener('contextmenu', (e) => {
e.preventDefault();
toggleFlag(cell, cellElement);
});
boardElement.appendChild(cellElement);
});
}

function revealCell(cell, element) {
if (cell.revealed || cell.flagged || gameOver) return;

cell.revealed = true;
element.classList.add('revealed');
if (cell.bomb) {
element.classList.add('bomb');
element.textContent = '💣';
endGame(false);
return;
}

checkWin();
}

function toggleFlag(cell, element) {
if (cell.revealed || gameOver) return;

cell.flagged = !cell.flagged;
element.classList.toggle('flag');
element.textContent = cell.flagged ? '🚩' : '';
}

function checkWin() {
const allBombsFlagged = cells.every(cell => !cell.bomb || cell.flagged);
if (allBombsFlagged && flaggedBombs === parseInt(bombsInput.value)) {
endGame(true);
}
}

function endGame(win) {
gameOver = true;
cells.forEach((cell, index) => {
const element = boardElement.children[index];
if (cell.bomb && !cell.flagged) {
element.textContent = '💣';
element.classList.add('bomb');
}
});
alert(win ? 'Вы победили!' : 'Игра окончена!');
}

newGameButton.addEventListener('click', () => {
flaggedBombs = 0;
gameOver = false;
const width = parseInt(widthInput.value);
const height = parseInt(heightInput.value);
const bombs = parseInt(bombsInput.value);

if (bombs >= width * height) {
alert('Слишком много бомб!');
return;
}

createBoard(width, height, bombs);
});

newGameButton.click();
</script>

Объяснение кода:

  1. Создание игрового поля: Генерируется сетка с клетками.
    Бомбы размещаются случайным образом.
  2. Открытие клеток: Если клетка содержит бомбу, игра завершается.
  3. Флажки: Правый клик добавляет или убирает флажок на клетке.
  4. Проверка победы: Победа фиксируется, если все бомбы помечены флажками.

Что здесь можно улучшить?

Игра «Сапёр» в текущем виде уже функциональна и позволяет пользователю играть, но всегда есть возможности для улучшения. Ниже перечислены основные направления, которые помогут сделать код более эффективным, удобным для пользователей и масштабируемым.

1. Оптимизация структуры данных

В текущем коде клетки хранятся в массиве объектов. Хотя это работает, можно улучшить производительность и удобство доступа:

  • Использование двумерного массива: Вместо одномерного массива можно использовать двумерный, что облегчит работу с клетками (особенно при проверке соседей).

let cells = Array.from({ length: height }, () => Array(width).fill(null));

  • Оптимизация поиска соседей: В текущем коде для каждой клетки проверяются все её соседи. Можно предзагрузить массив с относительными координатами соседей и использовать его для доступа к клеткам.

const neighbors = [
[-1, -1], [-1, 0], [-1, 1],
[0, -1], [0, 1],
[1, -1], [1, 0], [1, 1]
];

2. Обработка событий

  • Улучшение обработки кликов: Сейчас каждый элемент клетки создаётся с индивидуальными слушателями событий. Это может привести к снижению производительности на больших полях. Решение — делегировать события:

boardElement.addEventListener('click', handleCellClick);
boardElement.addEventListener('contextmenu', handleCellRightClick);
Внутри этих функций можно определять, какая клетка была нажата, с помощью свойства event.target.

3. Улучшение пользовательского интерфейса (UI)

  • Добавление таймера: Реализуйте простой таймер, чтобы отслеживать, сколько времени заняла игра.

let timer = setInterval(() => {
// Обновление времени на экране
}, 1000);

  • Счётчик оставшихся бомб: Показывайте игроку, сколько ещё бомб не отмечено флажками.
  • Анимация: Добавьте визуальные эффекты при открытии клеток или проигрыше, чтобы сделать игру более привлекательной.

4. Масштабируемость и адаптивность

  • Адаптивный дизайн: Используйте медиазапросы CSS, чтобы игровое поле выглядело корректно на мобильных устройствах.

@media (max-width: 600px) {
.cell {
width: 20px;
height: 20px;
}
}

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

5. Обработка ошибок и проверка ввода

  • Валидация ввода: Убедитесь, что пользователь не может ввести некорректные значения (например, больше бомб, чем клеток).
  • Обработка исключений: Добавьте проверки на случай, если что-то пойдёт не так (например, сбой генерации игрового поля).

6. Модульность кода

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

class Minesweeper {
constructor(width, height, bombs) {
// Инициализация игры
}

createBoard() {
// Создание игрового поля
}

revealCell(x, y) {
// Логика открытия клетки
}

checkWin() {
// Проверка на победу
}
}

7. Тестирование и отладка

  • Добавление тестов: Напишите простые тесты для проверки генерации поля, подсчёта бомб и логики победы/поражения.
  • Режим отладки: Создайте режим отладки, который позволяет разработчику видеть расположение бомб, не влияя на игровой процесс.

8. Сохранение прогресса

Добавьте возможность сохранять и загружать текущее состояние игры:

  • Используйте LocalStorage для хранения состояния.
  • Это позволит игроку продолжить игру после перезагрузки страницы.

Эти улучшения сделают ваш код более оптимальным, а игру — более приятной для пользователя. Кроме того, улучшенная структура и модульность позволят легко добавлять новые функции и поддерживать код в будущем.

Заключение

Теперь вы знаете, как создать игру «Сапёр» с нуля, используя HTML, CSS и JavaScript. Эту игру можно легко интегрировать на сайт WordPress или использовать как учебный проект для углубления знаний в веб-разработке.

Ну а рекомендации по улучшению кода помогут вам довести игру до совершенства.

Сыграть в игру можно здесь: https://sergsergius.ru/%d0%b8%d0%b3%d1%80%d0%b0-%d1%81%d0%b0%d0%bf%d0%b5%d1%80/