- Спроектировать и реализовать популярную однопользовательскую игру Mineswepper. Пример одной из онлайн реализации можно найти по адресу http://minesweeperonline.com/#
- Задача состоит из базовых требований – обязательных для успешного выполнения задачи, и бонусных – требующих продвинутых знаний, но дающих дополнительные баллы при успешном решении
- Цель игры – открыть все ячейки поля, не содержащие мины, одновременно избегая ячеек, которые их содержат. Когда все ячейки поля, не содержащие мины, будут открыты, игрок побеждает.
- Каждая ячейка может содержать число, которое показывает количество мин, окружающих ячейку, с максимально возможным значением 8.
- HTML, Sass
- TypeScript
- HTML5 Canvas
- Vite
- Перед игрой Игроку необходимо указать размерность поля в виде рядов и колонок и количества мин (RхCxM), либо выбрать один из 3х вариантов, с заранее заданным количеством: Начинающий (9x9x10), Продвинутый (16x16x40), Эксперт (16x30x99).
- Минимальное и максимальное количство мин на поле должно удовлетворять условию 1 < mines < R*C
- Когда закончится генерирование игрового поля, Игрок может выполнять следующие действия:
- Левый клик по ячейке поля:
- Если ячейка поля содержит мину, все остальные ячейки поля с минами становятся видимыми и Игрок проигрывает.
- Если ячейка поля не содержит мину, ячейка отобразит число близлежащих мин. Если вокруг ячейки нет мин (ячейка пуста), то игра продолжит открывать прилегающие ячейки, пока не встретит ячейку с числом или не дойдет до края поля.
- Правый клик по ячейке поля
- Правый клик по ячейке поля установит на эту ячейку флаг. Флаг просто помечает ячейку для игрока как потенциально опасную, и игровая логика игнорирует данную ячейку исполняя логику игры.
- Левый клик по смайлу
- Сброс текущей игровой сессии и старт новой.
- Левый клик по ячейке поля:
- Дополнительно:
- Для приятного игрового процесса, повторяющего логику исходной игры, первый клик по ячейке никогда не должен приводить к проигрышу. Это значит, что Игрок никогда не должен попасть на мину при первом открытии ячейки
- Реализовать поддержку больших игровых полей – размерностью до 10000х10000 строк и колонок.
- Реализовать поддержку двух видов рендера с возможность переключения во время игры.
- Реализовать поддержку тем - темная, светлая и анимации.
- Реализовать режим сохранения игры, чтобы игрок мог вернуться к последнему игровому состоянию после закрытия вкладки браузера.
- Реализовать поддержку пользовательского ввода как с помощью мышки, так и с помощью тачпада (Windows, Mac)
- Для реализации графической части проекта можно использовать HTML5 Canvas или WebGL / WebGPU. Если примите решение использовать WebGL, разрешается использовать минимальную стороннюю обертку, чтобы сократить написание инициализационного кода. Логику, которую мы просим вас написать самому – это логика отрисовки поля, чтобы применяемый подход был способен отрисовать очень большие поля (поле 1000 x 1000 ячеек может занимать до 40k x 40k пикселей).
- При использовании WebAssembly мы ждем от вас написанного кода на WAT спецификации. Кросс компиляция из других языков, как С или Rust не допускается.
- Главная цель задания – увидеть, как вы спроектировали архитектуру приложения, которое может отображать большое количество данных на экране и способного быстро их перемещать в обоих направлениях. Оценить подход к эффективному хранению данных поля и реализации ключевой логики игры (клик по ячейкам для отображения ее состояния и состояния соседних ячеек) – игрок не должен ощущать длинных задержек по времени при клике по ячейке на больших полях.
- Не забывайте про призводительность. Старайтесь написать настолько производительный код, на сколько возможно. Если вы понимаете, что какаято часть может быть улучшена, но не готовы ее реализовать, оставьте комментарий с описанием, как бы вы хотели это сделать.
Игровое поле реализовано с помощью технологии HTML5 Canvas
Локальное состояние игры хранится в следующих переменных (game.ts):
- GameInfo
- difficulty - выбранная сложность
- state - состояние игры (Playing, Won, Lost)
- tileW - ширина одной ячейки (в пикселях)
- tileH - высота однной ячейки (в пикселях)
- firstTry - был совершен первый ход, или еще нет (true/false)
- optimizedRender - включен оптимизированный рендер или нет (true/false)
- grid - хранит в себе ячейки игрового поля
- diffs - хранит в себе список изменний ячеек игрового поля, которые нужно отрендерить (используется при оптимизированном рендере)
Каждая ячейка хранит в себе информацию (tile.ts):
- x - абсциссы ячейки на игровом поле
- y - ординаты ячейки на игровом поле
- hasMine - содержит ли ячейка мину (true/false)
- danger - количество ячеек с минами, расположенные в области 3x3 вокруг ячейки
- currentState - текущее состояние ячейки (Visible, Hidden, Flagged)
Есть два вида рендера:
- Обычный рендер
- Включен по умолчанию
- Перерендриваются все ячейки после каждого хода игрока
- Оптимизированный рендер
- Включается в настройках
- Перерендриваются только те ячейки, которые были изменены после каждого хода игрока
Есть четыре вида сложности:
- Кастомный
- Количество рядов выбирает сам игрок (от 2 до 1000)
- Количество колонок выбирает сам игрок (от 2 до 1000)
- Количество мин выбирает сам игрок (от 1 до рядов * колонок - 1)
- Начинающий
- 9 рядов
- 9 колонок
- 10 мин
- Продвинутый
- 16 рядов
- 16 колонок
- 40 мин
- Эксперт
- 16 рядов
- 30 колонок
- 99 мин
- Поддержка больших полей (до 1000 x 1000)
- Поддержку двух видов рендера
- Тёмная тема
- Поддержка пользотельского ввода (лкм и пкм)
- Все настройки, а также состояние игры сохраняются в localStorage