🎯 Цели урока
- Понять принципы создания функций
- Написать функцию перемешивания массива
- Создать функцию генерации карточек
- Добавить обработку кликов по карточкам
- Интегрировать все функции в игру
🔨 Что мы создаем
Интерактивные карточки, которые можно переворачивать кликом мыши,
алгоритм перемешивания и функции для динамического создания 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;
}
Как работает алгоритм:
- Начинаем с последнего элемента массива
- Генерируем случайный индекс от 0 до текущей позиции
- Меняем местами текущий элемент со случайным
- Переходим к предыдущему элементу
- Повторяем до начала массива
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:
- Получаем данные о кликнутой карточке
- Проверяем, можно ли её перевернуть
- Добавляем визуальный класс "flipped"
- Обновляем состояние в данных
- Добавляем карточку в массив перевернутых
- Если перевернуто 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. Тестирование функций
🔧 Как проверить работу:
- Откройте игру в браузере
- Должны появиться 16 карточек в случайном порядке
- При клике на карточку она должна переворачиваться
- Можно перевернуть максимум 2 карточки подряд
- Счетчик попыток должен увеличиваться
Важно: Пока функция checkForMatch
не создана, карточки будут оставаться перевернутыми. Это нормально -
мы добавим эту функцию в следующем уроке!