Deploy - https://artem-webdeveloper.github.io/pair-em-up/
Это интерактивная игра-головоломка, где цель - очистить поле от чисел, находя пары (одинаковые цифры или дающие в сумме 10). Приложение поддерживает три режима с разной логикой генерации, пять ассист-инструментов, сохранение прогресса, система undo, таймер, таблица рекордов, фоновая музыка и звуки.
Написано на чистом Vanilla JS - без сборщиков, фреймворков, TypeScript и сторонних библиотек. Вся архитектура, DOM-рендер и управление состоянием - вручную, без абстракций фреймворка.
Проект выполнен в рамках курса RS School. Главное техническое ограничение: <body> в HTML пустой - весь интерфейс строится через JavaScript. | Техническое Задание
- Classic - числа 1–19 (без нуля) в строгом порядке, 9 в строку
- Random - тот же набор, позиции перемешаны
- Chaotic - 27 случайных цифр от 1 до 9, дубли разрешены
При нажатии «Добавить числа» каждый режим ведёт себя по-своему: Classic продолжает последовательность, Random добавляет случайные из того же набора, Chaotic добавляет столько новых, сколько осталось на поле.
| Пара | Очки |
|---|---|
| Одинаковые числа (7 + 7) | +1 |
| Сумма = 10 (3 + 7) | +2 |
| Двойная пятёрка (5 + 5) | +3 |
Пара валидна, если между ячейками нет заполненных клеток - по горизонтали, вертикали или через «перелом» строки (последняя ячейка строки N → первая ячейка строки N+1).
| Инструмент | Что делает | Лимит |
|---|---|---|
| 💡 Hints | Показывает кол-во доступных ходов (макс. "5+") | без лимита |
| ↩ Revert | Отмена последнего хода | 1 раз за ход |
| ➕ Add Numbers | Добавляет числа по правилам режима | 10 раз |
| 🔀 Shuffle | Перемешивает оставшиеся числа | 5 раз |
| 🧹 Eraser | Убирает одну выбранную ячейку | 5 раз |
- Победа: набрано 100+ очков
- Поражение: нет ходов + все ассисты исчерпаны - ИЛИ поле достигло 50 строк
gameState- автосохранение при каждом действии (защита от случайного закрытия)savedGame- ручное сохранение кнопкой «Save», восстанавливается кнопкой «Continue»
src/
├── js/
│ ├── app.js # Точка входа, инициализация игры
│ ├── config.js # Стейт, константы
│ ├── helpers.js # Утилиты
│ ├── settings.js # Управление настройками и темой
│ ├── game/ # Core логика игры
│ │ ├── gameStatus.js # Проверка условий победы и поражения
│ │ ├── logic.js # Алгоритмы валидации пар
│ │ ├── sound.js # Audio API менеджер
│ │ └── timer.js # Игровой таймер
│ └── view/ # UI компоненты и рендер DOM
│
└── styles/
└── scss/ # Стили
Задача: две ячейки можно соединить только если между ними нет заполненных клеток - по горизонтали, вертикали или через «перелом» строки (последняя ячейка строки N и первая строки N+1 считаются соседними)
Решение: два отдельных чека - checkIsEmptyCells для линейного пути и checkIsEmptyColumns для вертикального. Перелом строки — третий явный случай со своей индексной логикой
Задача: сетка полностью динамическая - ячейки генерируются и удаляются на каждом ходу. Вешать слушатель на каждую ячейку значит постоянно добавлять и чистить обработчики было бы слишком дорого
Решение: один click на контейнере, цель определяется через e.target.closest. Один обработчик на весь жизненный цикл игры, сколько бы раз сетка не перерисовалась
Задача: автосохранение и ручной сейв должны жить независимо и не перетирать друг друга
Решение: два отдельных ключа в localStorage - gameState обновляется после каждого действия, savedGame пишется только по кнопке. Кнопка «Continue» появляется только когда ключ реально существует
Задача: undo требует полной глубокой копии стейта перед каждым ходом, но не все нужно захватывать
Решение: structuredClone() для инициализации стейта и настроек. Для снапшота истории - JSON.parse(JSON.stringify(...)) с явной формой объекта, чтобы в снимок попадало только нужное
Задача: синхронный вызов renderGameEndScreen() после успешной пары прерывал анимацию на середине
Решение: завернул в queueMicrotask() - рендер откладывается до завершения текущей задачи, анимация отрабатывает полностью
# Клонировать репозиторий
git clone https://github.com/ArtemWebDeveloper/pair-em-up.git
cd pair-em-up
# Установить зависимости
npm install
# Запустить в режиме разработки
npm run dev
MIT © 2026 Artem