← Вернуться в меню

🔧 Урок 4: JavaScript функции

Создаем функции для карточек, перемешивания и обработки кликов

🎯 Цели урока

  • Понять принципы создания функций
  • Написать функцию перемешивания массива
  • Создать функцию генерации карточек
  • Добавить обработку кликов по карточкам
  • Интегрировать все функции в игру

🔨 Что мы создаем

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

1. Функция перемешивания массива

💡 Алгоритм Фишера-Йетса

Это классический алгоритм для случайного перемешивания элементов массива. Гарантирует равномерное распределение вероятностей.

Шаг 1

Функция shuffleArray

// Функция перемешивания массива function shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; }

Как работает алгоритм:

  1. Начинаем с последнего элемента массива
  2. Генерируем случайный индекс от 0 до текущей позиции
  3. Меняем местами текущий элемент со случайным
  4. Переходим к предыдущему элементу
  5. Повторяем до начала массива

Math.random() - возвращает случайное число от 0 до 1

Math.floor() - округляет число вниз до целого

[a, b] = [b, a] - destructuring assignment для обмена значений

2. Создание карточек

Шаг 2

Дополнение функции initGame

// Инициализация игры (дополненная версия) function initGame() { // Очищаем доску gameBoard.innerHTML = ''; cards = []; flippedCards = []; matchedPairs = 0; attempts = 0; canFlip = true; // Обновляем счетчики scoreElement.textContent = matchedPairs; attemptsElement.textContent = attempts; // Создаем пары карточек const gameCards = [...cardImages, ...cardImages]; totalPairsElement.textContent = cardImages.length; // Перемешиваем карточки shuffleArray(gameCards); // Создаем карточки на доске for (let i = 0; i < gameCards.length; i++) { createCard(gameCards[i], i); } }

Теперь функция initGame также:

  • Перемешивает карточки перед размещением
  • Создает карточки в цикле через отдельную функцию
Шаг 3

Функция создания одной карточки

// Функция создания одной карточки function createCard(imageSrc, index) { // Создаем элемент карточки const card = document.createElement('div'); card.classList.add('card'); card.dataset.index = index; // Лицевая сторона (картинка) const front = document.createElement('div'); front.classList.add('card-front'); const img = document.createElement('img'); img.src = imageSrc; img.alt = 'Картинка'; front.appendChild(img); // Обратная сторона (рубашка) const back = document.createElement('div'); back.classList.add('card-back'); back.textContent = '?'; // Добавляем стороны в карточку card.appendChild(front); card.appendChild(back); // Добавляем обработчик клика card.addEventListener('click', flipCard); // Добавляем карточку на доску и в массив gameBoard.appendChild(card); cards.push({ element: card, imgSrc: imageSrc, isFlipped: false, isMatched: false }); }

Эта функция создает полную структуру карточки:

  • Основной div с классом card
  • Лицевую сторону с изображением
  • Обратную сторону с символом "?"
  • Добавляет обработчик клика
  • Сохраняет информацию о карточке в массив

document.createElement() - создает новый HTML элемент

appendChild() - добавляет элемент как дочерний

dataset.index - создает data-атрибут для хранения индекса

3. Обработка кликов

Шаг 4

Функция переворота карточки

// Функция переворота карточки function flipCard() { const clickedCard = this; // this = элемент, по которому кликнули const cardIndex = clickedCard.dataset.index; const cardData = cards[cardIndex]; // Проверяем, можно ли перевернуть эту карточку if (!canFlip || cardData.isFlipped || cardData.isMatched) { return; // Выходим из функции, если нельзя } // Переворачиваем карточку clickedCard.classList.add('flipped'); cardData.isFlipped = true; flippedCards.push(cardData); // Если перевернули 2 карточки, проверяем на совпадение if (flippedCards.length === 2) { canFlip = false; // Блокируем дальнейшие клики attempts++; attemptsElement.textContent = attempts; // Вызываем проверку через небольшую задержку setTimeout(checkForMatch, 500); } }

Логика функции flipCard:

  1. Получаем данные о кликнутой карточке
  2. Проверяем, можно ли её перевернуть
  3. Добавляем визуальный класс "flipped"
  4. Обновляем состояние в данных
  5. Добавляем карточку в массив перевернутых
  6. Если перевернуто 2 карточки - запускаем проверку

this - ключевое слово, ссылающееся на элемент, по которому кликнули

return - досрочно завершает выполнение функции

setTimeout() - выполняет функцию через заданное время

4. Улучшенная инициализация

Шаг 5

Полная функция initGame с созданием карточек

// Инициализация игры (полная версия) function initGame() { // Очищаем доску gameBoard.innerHTML = ''; cards = []; flippedCards = []; matchedPairs = 0; attempts = 0; canFlip = true; // Обновляем счетчики scoreElement.textContent = matchedPairs; attemptsElement.textContent = attempts; // Создаем пары карточек const gameCards = [...cardImages, ...cardImages]; totalPairsElement.textContent = cardImages.length; // Перемешиваем карточки shuffleArray(gameCards); // Создаем карточки на доске for (let i = 0; i < gameCards.length; i++) { createCard(gameCards[i], i); } console.log('Игра инициализирована с', gameCards.length, 'карточками'); }

5. Полный код функций

Шаг 6

Итоговый код script.js (часть 2)

// Функция перемешивания массива function shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } // Функция создания одной карточки function createCard(imageSrc, index) { // Создаем элемент карточки const card = document.createElement('div'); card.classList.add('card'); card.dataset.index = index; // Лицевая сторона (картинка) const front = document.createElement('div'); front.classList.add('card-front'); const img = document.createElement('img'); img.src = imageSrc; img.alt = 'Картинка'; front.appendChild(img); // Обратная сторона (рубашка) const back = document.createElement('div'); back.classList.add('card-back'); back.textContent = '?'; // Добавляем стороны в карточку card.appendChild(front); card.appendChild(back); // Добавляем обработчик клика card.addEventListener('click', flipCard); // Добавляем карточку на доску и в массив gameBoard.appendChild(card); cards.push({ element: card, imgSrc: imageSrc, isFlipped: false, isMatched: false }); } // Функция переворота карточки function flipCard() { const clickedCard = this; const cardIndex = clickedCard.dataset.index; const cardData = cards[cardIndex]; // Проверяем, можно ли перевернуть эту карточку if (!canFlip || cardData.isFlipped || cardData.isMatched) { return; } // Переворачиваем карточку clickedCard.classList.add('flipped'); cardData.isFlipped = true; flippedCards.push(cardData); // Если перевернули 2 карточки, проверяем на совпадение if (flippedCards.length === 2) { canFlip = false; attempts++; attemptsElement.textContent = attempts; setTimeout(checkForMatch, 500); } } // Инициализация игры (обновленная) function initGame() { // Очищаем доску gameBoard.innerHTML = ''; cards = []; flippedCards = []; matchedPairs = 0; attempts = 0; canFlip = true; // Обновляем счетчики scoreElement.textContent = matchedPairs; attemptsElement.textContent = attempts; // Создаем пары карточек const gameCards = [...cardImages, ...cardImages]; totalPairsElement.textContent = cardImages.length; // Перемешиваем карточки shuffleArray(gameCards); // Создаем карточки на доске for (let i = 0; i < gameCards.length; i++) { createCard(gameCards[i], i); } console.log('Игра готова! Кликайте по карточкам.'); }

6. Ключевые концепции программирования

Функции как строительные блоки

Каждая функция решает одну конкретную задачу:

  • shuffleArray - перемешивает массив
  • createCard - создает одну карточку
  • flipCard - обрабатывает клик
  • initGame - координирует весь процесс

Разделение ответственности

Каждая функция отвечает за свою область:

  • Данные - массивы и переменные состояния
  • DOM - создание и изменение HTML элементов
  • События - реакция на действия пользователя
  • Логика - правила игры и проверки

Управление состоянием

Переменная canFlip предотвращает одновременное переворачивание множества карточек.

7. Тестирование функций

🔧 Как проверить работу:

  1. Откройте игру в браузере
  2. Должны появиться 16 карточек в случайном порядке
  3. При клике на карточку она должна переворачиваться
  4. Можно перевернуть максимум 2 карточки подряд
  5. Счетчик попыток должен увеличиваться

Важно: Пока функция checkForMatch не создана, карточки будут оставаться перевернутыми. Это нормально - мы добавим эту функцию в следующем уроке!