diff --git a/tasks/eldritch-horror-week-edition/README.md b/tasks/eldritch-horror-week-edition/README.md new file mode 100644 index 000000000..4c3b4ec0b --- /dev/null +++ b/tasks/eldritch-horror-week-edition/README.md @@ -0,0 +1,282 @@ +# Eldritch Horror — Week Edition + +## Описание задания + +Сокращённая версия [Eldritch Horror](../eldritch-horror/README.md). Требования и критерии оценки этой версии полностью приведены ниже. + +Создайте небольшое приложение для подготовки колоды карт к настольной игре «Древний Ужас». Пользователь нажимает «Замешать колоду», а затем открывает карты по одной. Приложение показывает открытую карту и количество оставшихся карт. + +Срок выполнения — **одна неделя**. Задание закрепляет основы JavaScript на практике: от обработки исходных данных до управления состоянием приложения. Необходимые правила настольной игры приведены ниже. + +## Ключевые навыки + +- реализация алгоритма случайного отбора без повторений и перемешивания карт; +- преобразование массивов данных с учётом правил формирования колоды; +- декомпозиция логики на функции и разделение вычислений и обновления интерфейса; +- управление состоянием колоды и синхронизация счётчиков с действиями пользователя; +- сохранение исходных данных для повторной сборки колоды. + +## Как работает приложение + +Приложение отвечает за подготовку и последовательное открытие колоды мифов. Реализовывать настольную игру целиком, действия игроков или эффекты, написанные на картах, не нужно. В рамках задания карта — это изображение с уникальным идентификатором и цветом. + +Пользователь нажимает «Замешать колоду». Приложение случайно отбирает карты из полного набора и формирует три этапа по схеме Азатота. Схема задаёт количество карт каждого цвета на каждом этапе, а конкретные карты и их порядок определяются при сборке. + +Затем пользователь нажимает «Следующая карта» и видит очередную карту. Приложение уменьшает соответствующий счётчик. После четырёх карт первого этапа начинается второй, после шести карт второго — третий. Когда открыты все 16 карт, колода заканчивается. Победу или поражение приложение не определяет; пользователь может собрать новую колоду и начать заново. + +## Правила колоды + +В задании используется один Древний — **Азатот (`azathoth`)** — и один уровень игры — **средний**. На этом уровне можно использовать все предоставленные карты независимо от их сложности. Поле `difficulty` не влияет на отбор. + +Карты бывают трёх цветов: зелёные, синие и коричневые. Примеры карт: + +![Синяя карта](https://github.com/Luffi2539/eldritch-codejam/blob/main/assets/MythicCards/blue/blue2.png?raw=true) + +![Коричневая карта](https://github.com/Luffi2539/eldritch-codejam/blob/main/assets/MythicCards/brown/brown1.png?raw=true) + +![Зеленая карта](https://github.com/Luffi2539/eldritch-codejam/blob/main/assets/MythicCards/green/green1.png?raw=true) + +Пример карты Древнего со схемой этапов: + +![Древний](https://user-images.githubusercontent.com/43149261/172723651-a9c7e003-96b7-44e4-944a-54ad12755fbd.png) + +Колода состоит из трёх этапов: + +| Этап | Зелёные | Синие | Коричневые | Всего | +| -------------- | ------- | ----- | ---------- | ------ | +| 1 | 1 | 1 | 2 | 4 | +| 2 | 2 | 1 | 3 | 6 | +| 3 | 2 | 0 | 4 | 6 | +| **Вся колода** | **5** | **2** | **9** | **16** | + +**Исходный набор и колода одной игры — разные вещи.** Исходный набор содержит 51 уникальную карту: 18 зелёных, 12 синих и 21 коричневую. Подготовьте весь набор — предоставленный или собственный по требованиям ниже. + +При каждом нажатии «Замешать колоду» приложение случайно выбирает **5 из 18 зелёных, 2 из 12 синих и 9 из 21 коричневой карты**. Эти 16 карт составляют колоду одной игры. Остальные 35 карт в этой игре не используются, но снова участвуют в отборе при следующем замешивании. + +Нельзя заранее выбрать постоянные 16 карт и только перемешивать их: случайным должен быть и состав колоды, и порядок карт внутри этапов. Одна и та же карта не должна повторяться внутри одной колоды, в том числе на разных этапах. Между разными играми повторения допустимы. + +Распределите выбранные карты по этапам согласно таблице и перемешайте карты **внутри каждого этапа**. Сначала пользователь открывает все 4 карты первого этапа, затем 6 карт второго и 6 карт третьего. Перемешивать карты между этапами нельзя. + +Иллюстрация сборки колоды из правил настольной игры: + +![image](https://user-images.githubusercontent.com/43149261/172725219-0d0c9f22-0594-4b4b-9a2b-ce4427c682ab.png) + +## Файлы для работы + +Полный набор изображений карт, из которого нужно выполнять случайный отбор для колоды, находится в папке [assets/MythicCards](../eldritch-horror/assets/MythicCards/) исходного задания: + +- [зелёные карты](../eldritch-horror/assets/MythicCards/green/); +- [синие карты](../eldritch-horror/assets/MythicCards/blue/); +- [коричневые карты](../eldritch-horror/assets/MythicCards/brown/). + +Картинки выше приведены только для примера. Для сборки колоды используйте полный набор из `assets` или собственный набор по требованиям ниже. + +Готовые массивы с описаниями карт находятся в папке [data](../eldritch-horror/data/): + +- [зелёные карты](../eldritch-horror/data/mythicCards/green/index.js); +- [синие карты](../eldritch-horror/data/mythicCards/blue/index.js); +- [коричневые карты](../eldritch-horror/data/mythicCards/brown/index.js). + +У каждой карты есть уникальный `id`, изображение `cardFace`, цвет `color` и сложность `difficulty`. Схема Азатота из [data/ancients.js](../eldritch-horror/data/ancients.js) уже приведена в таблице выше, её можно записать в своём коде. + +Скопируйте изображения в свой проект. Формат данных можно адаптировать: использовать массивы объектов или массивы путей к изображениям. При использовании предоставленных материалов сохраните полный набор карт, их уникальность и принадлежность к цвету. Уникальный путь к изображению может заменять `id`; поле `difficulty` сохранять необязательно, поскольку оно не используется в этом задании. + +Структуру файлов и способ подключения данных выберите самостоятельно: можно использовать массивы в коде, импортировать данные или загружать их через `fetch`[^loading]. Копировать массивы в код приложения не обязательно. Для использования `fetch` разрешается адаптировать предоставленные файлы, например преобразовать JS-модули в JSON и скорректировать пути к изображениям. Способ подключения данных не влияет на оценку. + +[^loading]: При асинхронной загрузке предусмотрите состояние загрузки и сообщение об ошибке. Требования о доступности кнопки «Замешать колоду» относятся к состоянию после успешной загрузки данных. До этого кнопка отключена. После ошибки достаточно сообщения; повторная попытка загрузки без перезагрузки страницы не обязательна. + +### Собственные карточки + +Вместо предоставленных изображений можно нарисовать или сгенерировать свои карточки, в том числе с помощью ИИ. Тематика и визуальный стиль свободные. + +Для собственного набора сохраните то же количество уникальных карт: **18 зелёных, 12 синих и 21 коричневая**. У каждой карты должен быть уникальный идентификатор или путь к изображению. Карточки должны быть визуально различимы, а их цвет — понятен по изображению, рамке или подписи в интерфейсе. Художественное качество и способ создания изображений не оцениваются. + +Собственные карточки заменяют только визуальные материалы. Схема Азатота, состав колоды из 16 карт, этапы, правила отбора и перемешивания, поведение приложения и **все критерии оценки остаются такими же**. В случайном отборе участвует полный собственный набор соответствующего цвета. Подготовьте изображения заранее: генерация карточек во время работы приложения не требуется. + +## Интерфейс + +Разместите на странице: + +- название приложения и подпись с именем Древнего и уровнем сложности, например «Азатот · Средняя сложность»; +- кнопку «Замешать колоду»; +- кнопку «Следующая карта»; +- место для изображения открытой карты; +- таблицу со счётчиками оставшихся карт каждого цвета на каждом этапе; +- текстовое сообщение о состоянии игры. + +Дизайн свободный. Интерфейс должен быть читаемым, а элементы управления — доступными для взаимодействия. Допускается статическая HTML-разметка. Адаптивная вёрстка, анимации и соответствие конкретному макету не оцениваются. Тексты кнопок, подписей и сообщений можно менять, в том числе переводить на другой язык: главное — сохранить их смысл и понятность действий и состояния приложения. Приведённые ниже тексты служат примерами. + +## Поведение приложения + +### До замешивания + +- Кнопка «Замешать колоду» доступна. +- Кнопка «Следующая карта» отключена. +- Изображение карты скрыто, все счётчики равны нулю. +- Отображается сообщение «Нажмите “Замешать колоду”, чтобы начать». + +### После замешивания + +- Собрана новая случайная колода из 16 карт по правилам выше. +- Счётчики соответствуют таблице состава колоды. +- Кнопка «Следующая карта» доступна, изображение пока скрыто. +- Отображается сообщение «Этап 1». + +### При открытии карты + +- Одно нажатие на «Следующая карта» открывает ровно одну карту. +- Карта больше не доступна для повторного взятия из этой колоды. +- Уменьшается на единицу только счётчик её цвета и этапа. +- Открытая карта остаётся на экране до следующего нажатия или нового замешивания. +- После последней карты этапа приложение автоматически переходит к следующему: сообщение показывает этап, из которого будет взята следующая карта. Счётчики завершённого этапа равны нулю. + +Например, если первой открылась коричневая карта, счётчики первого этапа станут: 1 зелёная, 1 синяя, 1 коричневая. Остальные этапы не изменятся. + +### После окончания колоды + +- После 16-го нажатия все счётчики равны нулю. +- Отображается сообщение «Колода закончилась». +- Кнопка «Следующая карта» отключена, последняя карта остаётся на экране. +- Счётчики не могут стать отрицательными. + +### Повторное замешивание + +Кнопка «Замешать колоду» доступна в любой момент. Она собирает колоду заново из полного исходного набора карт, сбрасывает счётчики к значениям таблицы, скрывает открытую карту и возвращает приложение к первому этапу. Перезагружать страницу для этого не нужно. + +Карты из предыдущей игры снова участвуют в отборе. Совпадение отдельных карт или случайное совпадение порядка при двух сборках не является ошибкой. + +## Требования к случайности + +- При каждой сборке отбор выполняется заново из полного набора карт соответствующего цвета. Каждая ещё не выбранная карта этого цвета должна иметь одинаковую вероятность выбора. +- Для случайного отбора и перемешивания карт используйте алгоритм рандомизации, обеспечивающий равную вероятность выбора карт и их расположения внутри этапа. Допускаются разные алгоритмы и их сочетания: для отбора карт и перемешивания этапов можно использовать разные подходы. Выбор алгоритмов и их реализация остаются за участником; оценивается соответствие требованиям к случайности, а не применение конкретного алгоритма. +- Совпадения между разными сборками допустимы. Статистические тесты и доказательство равномерности от участника не требуются. + +## Технические требования + +Используйте JavaScript без библиотек и фреймворков для реализации логики и интерфейса приложения. Любые инструменты разработки разрешены: сборщики, форматтеры, линтеры, Husky, lint-staged и инструменты тестирования. Их наличие и выбор не оцениваются. + +Выбор других Древних и уровней сложности, сохранение в `localStorage`, звук и таймеры в задание не входят и дополнительных баллов не дают. + +### Рекомендации по организации кода + +- Выделите отбор карт, формирование этапов и выдачу следующей карты в отдельные функции. Отделите работу с данными от обновления DOM. +- Работайте с копиями исходных массивов, сохраняя исходные данные неизменными. +- Структуру состояния выберите самостоятельно. + +Это рекомендации: организация кода не оценивается. При любом подходе повторная сборка должна работать с полным набором карт — это проверяется по функциональным критериям. + +## Критерии оценки + +**Максимальная оценка — 100 баллов.** По критериям можно набрать 105 баллов, включая 5 дополнительных баллов за README. Штрафы вычитаются из всей набранной суммы, включая дополнительные баллы за README, и только после этого итог ограничивается 100 баллами. Дополнительные 5 баллов могут компенсировать часть штрафа. + +### Интерфейс и начальное состояние — 10 баллов + +- **5 баллов:** присутствуют название, подпись с именем Древнего и уровнем сложности, обе кнопки и таблица счётчиков трёх этапов. +- **5 баллов:** до замешивания счётчики равны нулю, изображение скрыто, взятие карты отключено и показана подсказка о начале игры. + +### Сборка колоды — 40 баллов + +- **10 баллов:** колода содержит 16 карт: 5 зелёных, 2 синие и 9 коричневых. +- **10 баллов:** ни одна карта не повторяется внутри колоды. +- **10 баллов:** состав каждого этапа соответствует таблице. +- **10 баллов:** для отбора и перемешивания карт реализован алгоритм рандомизации, соответствующий требованиям к случайности. Состав колоды и порядок карт формируются при каждой сборке, а не выбираются из заранее заданных вариантов. Пункт проверяется **по коду в PR**. При снятии баллов проверяющий указывает конкретный участок кода и нарушенное требование. Совпадения между отдельными сборками не являются основанием для снятия баллов; статистические проверки не проводятся. + +### Открытие карт и счётчики — 30 баллов + +- **10 баллов:** одно нажатие открывает одну карту и показывает её изображение; до следующего нажатия изображение сохраняется. +- **10 баллов:** после замешивания счётчики соответствуют таблице, каждое взятие уменьшает только нужный счётчик на единицу. +- **10 баллов:** карты выдаются в порядке этапов 1 → 2 → 3, сообщение о текущем этапе обновляется по описанным правилам. + +### Окончание игры и повторная сборка — 20 баллов + +- **10 баллов:** после 16 карт отображается сообщение об окончании, все счётчики равны нулю, дальнейшее взятие отключено и последняя карта остаётся видимой. +- **10 баллов:** повторное замешивание в середине и в конце игры создаёт новую колоду из полного набора, восстанавливает счётчики и доступность кнопки, скрывает старую карту и возвращает первый этап без перезагрузки страницы. + +### README — 5 дополнительных баллов + +- **5 баллов:** в корне репозитория есть `README.md` с кратким описанием приложения, ссылкой на PR и инструкцией локального запуска. Инструкция содержит необходимые условия, команды установки зависимостей (если они используются) и запуска приложения. По ней можно запустить проект из ветки с решением без дополнительных уточнений у автора. + +**Все спорные моменты при проверке, включая трактовку требований, начисление баллов и применение штрафов, решаются в пользу студента.** + +Пункты оцениваются независимо. За каждый пункт начисляется указанное количество баллов, если он выполнен полностью, иначе — 0. Недостатки оформления, не мешающие пользоваться приложением, не снижают оценку. + +## Требования к репозиторию и сдаче + +1. Создайте личный репозиторий `codejam-eldritch`. Ветка `main` может содержать `README.md` и служебные файлы; работу над приложением выполняйте в ветке `eldritch-horror`. +2. Делайте коммиты по мере выполнения задания. История должна отражать процесс работы. Сообщения коммитов должны соответствовать [конвенции RS School](https://rs.school/ru/docs/git-convention). +3. Деплой разрешён на любом сервисе. Постарайтесь убедиться, что выбранный сервис и приложение доступны всем проверяющим в течение всего cross-check, без авторизации, запроса доступа или обязательного VPN. Проверьте ссылку в режиме инкогнито; учитывайте региональные ограничения сервиса. +4. Откройте PR по требованиям ниже. Добавьте в приложение ссылку на PR. Репозиторий должен быть публичным и PR открытым к началу cross-check. +5. До дедлайна в расписании откройте **RS App → Cross-Check: Submit**, выберите это задание и отправьте **ссылку на Pull Request** в поле **Solution URL**. Ссылка на деплой должна находиться в описании PR. + +Если репозиторий был создан приватным, сделайте его публичным к началу cross-check. + +## Требования к Pull Request + +Оформите PR по [требованиям RS School](https://rs.school/docs/short-track/pull-request-requirements) и уточнениям ниже. + +Создайте PR из `eldritch-horror` в `main` своего репозитория. Все изменения приложения должны быть видны в этом PR. Название PR — **Eldritch Horror**. Не мержите и не закрывайте PR до окончания проверки. + +В описании обязательно укажите: + +1. Ссылку на это задание. +2. Скриншот приложения с собранной колодой и трекером. +3. Ссылку на работающий деплой, доступный без авторизации. +4. Дату сдачи и дату дедлайна. +5. Самооценку по каждому пункту критериев: начисленные баллы и невыполненные или частично выполненные требования. + +Пример структуры описания: + +```markdown +1. Задание: <ссылка на описание> +2. Скриншот: <вставьте изображение> +3. Деплой: <ссылка на приложение> +4. Дата сдачи: ДД.ММ.ГГГГ / Дедлайн: ДД.ММ.ГГГГ +5. Самооценка: XX / 100 + <перечислите пункты критериев, баллы и известные недочёты> +``` + +## Штрафы + +### Отсутствующий или неверно оформленный PR — 30 баллов + +Штраф применяется, если есть хотя бы одно нарушение: + +- неверное название или направление веток; +- отсутствие изменений приложения в PR; +- отсутствие обязательного пункта описания, кроме ссылки на деплой, которая оценивается отдельно; +- неработающая ссылка на задание или отсутствующий скриншот; +- отсутствие ссылки на PR в `README.md` репозитория; +- PR отсутствует, недоступен, закрыт или смержен. + +### Отсутствующий или недоступный деплой — 30 баллов + +Штраф применяется, если в описании PR нет ссылки на деплой, ссылка не ведёт к приложению либо приложение недоступно проверяющим из-за ограничений доступа, хостинга или отсутствия публикации. Отсутствие или неработоспособность ссылки на деплой не является дополнительным основанием для штрафа за оформление PR. + +Если деплой отсутствует или недоступен, проверяющий должен запустить приложение локально из ветки с решением, указанной в PR, и оценить функциональность по общим критериям. Штраф 30 баллов за деплой при этом сохраняется. Отсутствие деплоя само по себе не обнуляет баллы за функциональность. + +Автор должен указать в `README.md` необходимые условия и команды для локального запуска, включая установку зависимостей, если они используются. Если локальный запуск не удался, проверяющий описывает ошибку в отзыве; баллы за функциональность, которую не удалось проверить, не начисляются. + +Ошибки функциональности в доступном приложении оцениваются по соответствующим критериям и сами по себе не считаются отсутствием деплоя. + +### Коммиты не по конвенции — 10 баллов + +Штраф применяется, если сообщения одного или нескольких коммитов с решением задания не соответствуют [конвенции RS School](https://rs.school/ru/docs/git-convention). Проверяются коммиты в PR; начальный коммит создания репозитория и автоматически созданные merge-коммиты не учитываются. В отзыве укажите конкретные коммиты и нарушенные требования конвенции. + +### Расчёт итоговой оценки + +Каждый из трёх штрафов применяется **один раз за задание**, независимо от числа нарушений внутри категории. Сначала из суммы баллов по всем критериям, включая 5 дополнительных баллов за README, вычитается сумма штрафов. Затем результат ограничивается диапазоном от 0 до 100 баллов. + +`итоговая оценка = max(0, min(100, сумма баллов по критериям − сумма штрафов))` + +Например, при 105 баллах за критерии оценка без штрафов составляет 100, а со штрафом только за PR — 75 (105 − 30); со штрафами за PR и коммиты — 65 (105 − 30 − 10); со всеми тремя штрафами — 35 (105 − 30 − 30 − 10). + +Проверяющий перечисляет конкретные основания для каждого штрафа в комментарии к оценке. Не начисляйте баллы за функциональность, которую невозможно проверить, и не предполагайте нарушения без подтверждения. + +До начала cross-check оформление можно исправить без штрафа. PR должен оставаться открытым, а репозиторий и деплой — доступными до окончания проверки. + +## Материалы по алгоритмам + +Материалы для самостоятельного изучения. Использовать конкретный алгоритм из списка не обязательно. + +- [Перемешивание Фишера — Йейтса и последовательный случайный выбор с удалением](https://bost.ocks.org/mike/shuffle/) — разбор нескольких вариантов с визуализациями. +- [Сравнение алгоритмов перемешивания](https://bost.ocks.org/mike/shuffle/compare.html) — интерактивная визуализация распределения элементов по позициям. diff --git a/tasks/memory-game-week-edition/README.md b/tasks/memory-game-week-edition/README.md new file mode 100644 index 000000000..d2dcabad8 --- /dev/null +++ b/tasks/memory-game-week-edition/README.md @@ -0,0 +1,313 @@ +# Memory Game — Week Edition + +**Срок выполнения: одна неделя.** Даты сдачи и cross-check указаны в расписании курса. + +Создайте игру на поиск пар: игрок открывает карточки и запоминает их расположение, чтобы найти все совпадения за наименьшее число ходов. + +## Чему вы научитесь + +- генерировать HTML-разметку с помощью JavaScript; +- разбивать игровую логику на функции с понятной ответственностью; +- работать с коллекцией карточек и случайным порядком элементов; +- согласовывать состояние игры, обработку событий и отображение интерфейса; +- учитывать повторные действия пользователя и отложенные изменения состояния. +- создавать переиспользуемые компоненты приложения. + +## Пример интерфейса + +![Пример интерфейса Memory Game](../js30%23/images/js30-8.jpg) + +Изображение взято из исходного задания и иллюстрирует принцип игры. В этой версии на поле **16 карточек — 8 пар**. Повторять оформление примера не требуется. + +## Правила игры + +1. В начале игры все 16 карточек лежат рубашкой вверх. Счётчик ходов равен 0, найденных пар — 0 из 8. +2. Игрок открывает одну карточку, затем другую. **Один ход — открытие двух разных доступных карточек**, независимо от того, совпали они или нет. +3. Если изображения совпали, обе карточки остаются открытыми до конца игры. Счётчик найденных пар увеличивается на 1. +4. Если изображения различаются, обе карточки остаются видимыми примерно секунду, затем закрываются. Пока игрок рассматривает несовпавшую пару, открыть другие карточки нельзя. +5. Когда найдены все 8 пар, игра завершена. Автоматически откройте модальное окно с сообщением о победе, итоговым количеством ходов и кнопками «Новая игра» и «Закрыть». +6. В хедере расположены кнопки «Новая игра» и «Таблица лидеров». «Новая игра» начинает игру заново: карточки перемешиваются и закрываются, счётчики обнуляются. «Таблица лидеров» открывает сохранённые результаты в модальном окне. + +Тексты интерфейса можно изменять и переводить, сохраняя их смысл. + +## Требования к реализации + +### Хедер + +В хедере находятся две кнопки. + +#### «Новая игра» + +По нажатию начинается новая игра без перезагрузки страницы: все карточки перемешиваются и закрываются, число ходов и найденных пар обнуляется. + +Кнопка работает и во время игры, и после победы. Если несовпавшая пара ещё открыта, её таймер закрытия отменяется. Все карточки сразу закрываются и перемешиваются, оба счётчика обнуляются. Новая игра начинается сразу, без ожидания окончания старого таймера. Незавершённая игра не сохраняется в рейтинге, а результаты прошлых игр остаются. + +#### «Таблица лидеров» + +Открывает окно с сохранёнными результатами. Кнопка доступна до первой игры, во время игры и после победы. + +Просмотр таблицы не сбрасывает игру. Если в этот момент открыта несовпавшая пара, она закрывается по истечении своей задержки. После закрытия таблицы игрок продолжает с того же поля. + +### Игровое поле + +#### Карточки + +- На поле 16 карточек: 8 разных изображений, каждое встречается дважды. Во всех играх можно использовать один набор изображений. +- При запуске все карточки лежат рубашкой вверх. Рубашки одинаковые и не раскрывают содержимое карточек. +- Разные пары должны легко отличаться друг от друга, а изображения внутри пары — совпадать. Можно использовать готовые изображения, собственные рисунки, фотографии или изображения, созданные с помощью ИИ. Художественное качество не оценивается; источники и лицензии укажите при необходимости. +- При запуске и каждой новой игре карточки перемешиваются. Алгоритмы рандомизации могут быть разными. Выбор из заранее подготовленных раскладок не считается перемешиванием. Случайное повторение раскладки допустимо. + +#### Выбор пары + +Игрок нажимает на закрытую карточку, затем на другую. Первая остаётся открытой до выбора второй. + +- Если изображения совпали, обе карточки остаются открытыми до конца игры. Можно выбирать следующую пару. +- Если изображения различаются, обе карточки закрываются через **700–1500 мс** после открытия второй. До этого момента выбрать другие карточки нельзя, но кнопки хедера доступны. +- Нажатия на уже открытую карточку или найденную пару игнорируются, в том числе при быстром двойном клике. + +Когда найдены все 8 пар, игра завершается и открывается окно победы. Дальнейшие нажатия на карточки ничего не меняют. + +#### Счётчики + +На странице отображаются число ходов и число найденных пар. В начале игры это **0 ходов** и **0 из 8 пар**. + +Один ход засчитывается при открытии второй карточки, независимо от совпадения. Счётчик пар увеличивается только при нахождении новой пары. Нажатия, которые не открывают новую карточку, не меняют счётчики. + +### Окно победы + +Открывается автоматически после нахождения последней пары. В окне показаны сообщение о победе, число ходов за завершённую игру и две кнопки. Результат отображается независимо от попадания в таблицу лидеров. + +#### «Новая игра» + +Закрывает окно и запускает новую игру так же, как кнопка в хедере. + +#### «Закрыть» + +Закрывает окно. Найденные пары и итоговые счётчики остаются на странице. Игрок может начать новую игру или открыть таблицу лидеров через хедер. + +### Окно таблицы лидеров + +Открывается из хедера. В нём показаны до **10 лучших результатов** и кнопка «Закрыть». Если результатов ещё нет, вместо таблицы выводится сообщение, например «Пока нет результатов». + +#### Содержимое таблицы + +Для каждой игры указываются место, число ходов и дата в формате **ДД.ММ.ГГГГ**, без времени. Результаты идут от меньшего числа ходов к большему. При равенстве выше находится более ранняя игра. Места нумеруются от 1. + +#### Сохранение результатов + +После каждой победы результат один раз добавляется в рейтинг. В таблице остаются 10 лучших результатов; если завершённых игр меньше 10, показываются все. + +Результаты хранятся в `localStorage` и доступны после перезагрузки страницы или повторного открытия браузера. Открытие и закрытие окон не создаёт повторных записей. Новая игра не удаляет прошлые результаты, незавершённые игры не сохраняются. + +#### «Закрыть» + +Закрывает таблицу. Поле, счётчики и сохранённые результаты остаются без изменений. + +### Общие правила модальных окон + +- За открытым окном виден затемнённый фон. Карточки и кнопки хедера под ним недоступны, прокрутка страницы заблокирована. +- Окно закрывается любым из трёх способов: кнопкой «Закрыть», кликом по затемнённому фону или клавишей Escape. После закрытия прокрутка восстанавливается. +- Нажатие на текст или другое содержимое окна не закрывает его. Кнопка «Новая игра» в окне победы выполняет перезапуск. +- Закрытие окна не сбрасывает игру и не меняет результаты. + +Можно использовать `` или собственную реализацию. Окна победы и таблицы лидеров могут использовать общий код, но должны показывать разное содержимое. + +### Интерфейс и инструменты + +- В хедере находятся кнопки «Новая игра» и «Таблица лидеров». На странице видны игровое поле, число ходов и число найденных пар. Карточки и кнопки доступны для нажатия, изображения различимы. +- Дизайн свободный. Анимации, звук, таймер прохождения, уровни сложности не обязательны и дополнительных баллов не дают. +- `` в файле `index.html` должен быть пустым: допускается только тег `