Как создать игру в пятнашки на HTML и JavaScript
Размер текста: A+ A-

Как создать игру в пятнашки на HTML и JavaScript

Нажмите, чтобы оценить наш труд:
[Всего: 1 Средняя: 5]

Игра в пятнашки — классическая головоломка, которая не теряет популярности уже много лет.

Ее можно легко реализовать на веб-странице с использованием базовых технологий, таких как HTML, CSS и JavaScript. В этой статье мы расскажем, как создать простую версию игры, которая будет не только интерактивной, но и привлекательной для пользователей. С помощью этих технологий можно легко создать игровое поле, разместить фишки и добавить функционал для их перемещения.

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

Игра “пятнашки” на HTML / JS

Сначала хотелось бы сразу показать рабочий пример, который мы разместили на нашем сайте (работает и на тачскринах на мобильных устройствах): https://poznayu.com/js/fifteen/

В коде могут быть недочеты в плане логики движений фишек, это просто демонстрация возможностей веб-программирования, а не готовый продукт.

А вот полный код, что мы написали для этой игры. Понятно, что оформить через CSS можно как угодно:

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Пятнашки онлайн</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
flex-direction: column;
}
h1 {
margin-bottom: 20px;
color: #333;
}
.game-container {
display: flex;
flex-direction: column;
align-items: center;
}
#puzzle {
display: grid;
grid-template-columns: repeat(4, 100px);
grid-template-rows: repeat(4, 100px);
gap: 5px;
margin-bottom: 20px;
}
.piece {
width: 100px;
height: 100px;
background-color: #4CAF50;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: bold;
color: white;
border-radius: 5px;
cursor: pointer;
transition: transform 0.3s ease-in-out;
}
.piece.empty {
background-color: #f0f0f0;
cursor: default;
}
button {
padding: 10px 20px;
background-color: #008CBA;
color: white;
border: none;
font-size: 18px;
cursor: pointer;
border-radius: 5px;
}
button:hover {
background-color: #006f8a;
}
</style>
</head>

<body>
<h1>Игра в пятнашки</h1>
<div class="game-container">
<div id="puzzle">
<!-- Игровое поле будет заполнено здесь -->
</div>
<button id="startBtn">Начать игру</button>
</div>

<script>
document.addEventListener("DOMContentLoaded", () => {
const puzzleElement = document.getElementById("puzzle");
const startBtn = document.getElementById("startBtn");
let puzzle = [];
const SIZE = 4; // Размер игрового поля (4x4)
const TOTAL_PIECES = SIZE * SIZE - 1; // Всего фишек (15, пустое место не считается)
// Функция для создания игрового поля в отсортированном виде (по умолчанию)
function createSortedPuzzle() {
puzzle = [];
puzzleElement.innerHTML = ""; // Очищаем поле перед созданием
// Заполняем поле числами от 1 до 15
let numbers = Array.from({ length: TOTAL_PIECES }, (_, i) => i + 1);
// Добавляем пустое место в конец
numbers.push(null);
// Создаём элементы для каждой фишки
for (let i = 0; i < SIZE * SIZE; i++) {
const pieceElement = document.createElement("div");
pieceElement.classList.add("piece");
if (numbers[i] !== null) {
pieceElement.textContent = numbers[i];
pieceElement.dataset.value = numbers[i];
pieceElement.addEventListener("click", () => movePiece(i));
} else {
pieceElement.classList.add("empty");
}
puzzle.push(pieceElement);
puzzleElement.appendChild(pieceElement);
}
}
// Функция перемешивания массива (Фишек)
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
// Функция для перемещения фишек
function movePiece(index) {
const emptyIndex = puzzle.findIndex(piece => piece.classList.contains("empty"));
const validMoves = getValidMoves(emptyIndex);
if (validMoves.includes(index)) {
swapPieces(emptyIndex, index);
}
}
// Получение допустимых движений (по клеткам рядом с пустым местом)
function getValidMoves(emptyIndex) {
const validMoves = [];
const row = Math.floor(emptyIndex / SIZE);
const col = emptyIndex % SIZE;
// Проверка движений вверх, вниз, влево, вправо
if (row > 0) validMoves.push(emptyIndex - SIZE); // вверх
if (row < SIZE - 1) validMoves.push(emptyIndex + SIZE); // вниз
if (col > 0) validMoves.push(emptyIndex - 1); // влево
if (col < SIZE - 1) validMoves.push(emptyIndex + 1); // вправо
console.log(`Valid moves for ${emptyIndex}: ${validMoves}`); // Лог для отладки
return validMoves;
}
// Обмен фишек местами
function swapPieces(emptyIndex, newIndex) {
const temp = puzzle[emptyIndex].textContent;
puzzle[emptyIndex].textContent = puzzle[newIndex].textContent;
puzzle[newIndex].textContent = temp;
puzzle[emptyIndex].classList.remove("empty");
puzzle[newIndex].classList.add("empty");
checkWin();
}
// Проверка на победу
function checkWin() {
const numbers = puzzle.map(piece => piece.textContent);
const winCondition = Array.from({ length: TOTAL_PIECES }, (_, i) => (i + 1).toString());
winCondition.push("");
if (numbers.toString() === winCondition.toString()) {
alert("Вы выиграли!");
}
}
// Инициализация игры (начальное поле отсортировано)
createSortedPuzzle();
// Слушатель на кнопку "Начать игру"
startBtn.addEventListener("click", () => {
let numbers = Array.from({ length: TOTAL_PIECES }, (_, i) => i + 1);
numbers.push(null);
// Перемешиваем фишки случайным образом
shuffle(numbers);
// Очищаем поле и создаем его заново
puzzleElement.innerHTML = "";
puzzle = [];
// Создаём элементы для каждой фишки
for (let i = 0; i < SIZE * SIZE; i++) {
const pieceElement = document.createElement("div");
pieceElement.classList.add("piece");
if (numbers[i] !== null) {
pieceElement.textContent = numbers[i];
pieceElement.dataset.value = numbers[i];
pieceElement.addEventListener("click", () => movePiece(i));
} else {
pieceElement.classList.add("empty");
}
puzzle.push(pieceElement);
puzzleElement.appendChild(pieceElement);
}
});
});
</script>

</body>
</html>

Разбирать все не будем, поясним только лишь за отдельные логические части JS кода.

Подключение к событиям браузера:

document.addEventListener("DOMContentLoaded", () => {

Это слушатель событий, который активируется, когда весь HTML-документ загружен и разобран (но CSS и изображения могут еще загружаться). С помощью DOMContentLoaded мы гарантируем, что весь код будет выполняться только после того, как структура HTML-страницы будет готова.

Инициализация переменных:

const puzzleElement = document.getElementById("puzzle");
const startBtn = document.getElementById("startBtn");
let puzzle = [];
const SIZE = 4;
const TOTAL_PIECES = SIZE * SIZE - 1;
  • puzzleElement: ссылается на HTML-элемент с id “puzzle”, в котором будет отображаться игровое поле.
  • startBtn: ссылается на кнопку с id “startBtn”, которая будет запускать игру.
  • puzzle: это массив, который будет хранить все элементы фишек на поле.
  • SIZE: размер игрового поля. В данном случае это 4 (то есть поле будет 4×4).
  • TOTAL_PIECES: общее количество фишек. На поле 4×4 (16 клеток), но одна из них — пустая, поэтому фишек 15.

Функция перемешивания фишек:

function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}

Эта функция выполняет перемешивание элементов массива. Алгоритм “Фишера-Йейтса” используется для случайного перемешивания элементов.

А вот как реализована функция для перемещения фишек:

function movePiece(index) {
const emptyIndex = puzzle.findIndex(piece => piece.classList.contains("empty"));
const validMoves = getValidMoves(emptyIndex);
if (validMoves.includes(index)) {
swapPieces(emptyIndex, index);
}
}
  • Когда игрок кликает на фишку, эта функция проверяет, может ли фишка переместиться в пустую клетку.
  • Сначала находим индекс пустой клетки, затем получаем все допустимые клетки для перемещения с помощью getValidMoves.
  • Если фишка может быть перемещена, вызываем функцию swapPieces для обмена фишками местами.

Чтобы соблюдать правила игры, нужна функция для определения допустимых движений:

function getValidMoves(emptyIndex) {
const validMoves = [];
const row = Math.floor(emptyIndex / SIZE);
const col = emptyIndex % SIZE;

Эта функция определяет, в какие соседние клетки можно переместить фишку. Мы проверяем движение влево, вправо, вверх и вниз в зависимости от положения пустой клетки.

 if (row > 0) validMoves.push(emptyIndex - SIZE); // вверх
if (row < SIZE - 1) validMoves.push(emptyIndex + SIZE); // вниз
if (col > 0) validMoves.push(emptyIndex - 1); // влево
if (col < SIZE - 1) validMoves.push(emptyIndex + 1); // вправо
return validMoves;
}

Здесь мы добавляем индексы соседних клеток, в которые можно перемещаться, если они не выходят за границы поля.

Собственно, сама механика игры – функция для обмена фишек местами:

function swapPieces(emptyIndex, newIndex) {
const temp = puzzle[emptyIndex].textContent;
puzzle[emptyIndex].textContent = puzzle[newIndex].textContent;
puzzle[newIndex].textContent = temp;
puzzle[emptyIndex].classList.remove("empty");
puzzle[newIndex].classList.add("empty");
checkWin();
}
  • В этой функции происходит фактический обмен фишками местами.
  • Мы также обновляем классы фишек, чтобы правильно отображать пустую клетку.

Функция проверки победы:

function checkWin() {
const numbers = puzzle.map(piece => piece.textContent);
const winCondition = Array.from({ length: TOTAL_PIECES }, (_, i) => (i + 1).toString());
winCondition.push("");
if (numbers.toString() === winCondition.toString()) {
alert("Вы выиграли!");
}
}

Эта функция проверяет, является ли текущее состояние поля выигрышным. Мы сравниваем текущие числа на поле с требуемым порядком чисел (1, 2, 3, …, 15, пустое место).

Но чтобы начать игру, надо как-то смешать поле. Делать поле изначально смешанным мы не хотели. Инициализация игры и обработчик кнопки “Начать”:

startBtn.addEventListener("click", () => {
let numbers = Array.from({ length: TOTAL_PIECES }, (_, i) => i + 1);
numbers.push(null);
shuffle(numbers);
puzzleElement.innerHTML = "";
puzzle = [];
for (let i = 0; i < SIZE * SIZE; i++) {
const pieceElement = document.createElement("div");
pieceElement.classList.add("piece");
if (numbers[i] !== null) {
pieceElement.textContent = numbers[i];
pieceElement.dataset.value = numbers[i];
pieceElement.addEventListener("click", () => movePiece(i));
} else {
pieceElement.classList.add("empty");
}
puzzle.push(pieceElement);
puzzleElement.appendChild(pieceElement);
}
});

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

Нажмите, чтобы оценить наш труд:
[Всего: 1 Средняя: 5]
Ethan Carter

Я, Итан Картер – американский разработчик и технический автор с более чем 20-летним опытом в системном и прикладном программировании. Мой основной профиль — низкоуровневая разработка на Assembler: 22 года практики, включая глубокую работу с оптимизацией кода, архитектурой процессоров и производительностью критичных по скорости решений. Я защитил PhD dissertation по Assembler, а также более 18 лет работаю с ASP.NET, создавая корпоративные веб-системы, API и масштабируемые backend-решения.

Дополнительно я имею 9 лет опыта в C++ и C#, а также 7 лет практики программирования микроконтроллеров на Assembler. Благодаря моему сочетанию академической подготовки и прикладного инженерного опыта я могу писать статьи на стыке архитектуры ПО, низкоуровневой оптимизации и современной разработки, делая сложные технические темы понятными для профессиональной аудитории.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *


Срок проверки reCAPTCHA истек. Перезагрузите страницу.

О нас | Контакты


Прокрутить вверх