diff --git a/.eslintrc.json b/.eslintrc.json index e37e1e072..df89451f1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -7,4 +7,4 @@ "eqeqeq": ["error", "always"], "no-unused-vars": ["error"] } -} +} \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js index 65e18f5ff..99cd00a0a 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -7,4 +7,4 @@ module.exports = { bracketSpacing: true, arrowParens: "avoid", htmlWhitespaceSensitivity: "ignore", -}; +}; \ No newline at end of file diff --git a/docs/mvp-spec.md b/docs/mvp-spec.md index fab47685e..8b695eb9c 100644 --- a/docs/mvp-spec.md +++ b/docs/mvp-spec.md @@ -4,7 +4,7 @@ [Ссылка на макет (страница «Инструменты разработки»).](https://www.figma.com/file/Xk8ocvZA9NlMmA0szZeI5h/%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D1%8B%D0%B9-JS?node-id=4325%3A2) -## Описание игры +## Описание игры 1 Вам предстоит реализовать следующий функционал: выбор сложности, основную логику игры, вывод результата. Ниже вы найдёте подробное описание каждого пункта. @@ -14,9 +14,10 @@ Количество карточек для каждого уровня сложности можете назначать и свои или выбрать готовый пресет. Предлагаем следующее пресеты: - - Легкий уровень - 6 карточек (3 пары) - - Средний уровень - 12 карточек (6 пар) - - Сложный уровень - 18 карточек (9 пар) + +- Легкий уровень - 6 карточек (3 пары) +- Средний уровень - 12 карточек (6 пар) +- Сложный уровень - 18 карточек (9 пар) Как только уровень сложности выбран, игроку показывается на игровой поле. diff --git a/lefthook.yml b/lefthook.yml index 87752f862..bf049dd55 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -17,4 +17,4 @@ pre-commit: commands: eslint: glob: "*.{js,jsx}" - run: npm run lint + run: npm run lint \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index edaf5083f..dd3e2dd10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5961,9 +5961,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001522", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz", - "integrity": "sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==", + "version": "1.0.30001660", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", + "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", "funding": [ { "type": "opencollective", @@ -22559,9 +22559,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001522", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz", - "integrity": "sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==" + "version": "1.0.30001660", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", + "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==" }, "case-sensitive-paths-webpack-plugin": { "version": "2.4.0", diff --git a/public/Vector.svg b/public/Vector.svg new file mode 100644 index 000000000..dc94e72f4 --- /dev/null +++ b/public/Vector.svg @@ -0,0 +1,3 @@ + diff --git a/public/manifest.json b/public/manifest.json index 3bd1fa1b8..3a670d468 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -22,4 +22,4 @@ "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" -} +} \ No newline at end of file diff --git a/public/robots.txt b/public/robots.txt index e9e57dc4d..5537f0739 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,3 +1,3 @@ # https://www.robotstxt.org/robotstxt.html User-agent: * -Disallow: +Disallow: \ No newline at end of file diff --git a/src/components/Button/Button.module.css b/src/components/Button/Button.module.css index 5d3f1f80e..132022b6f 100644 --- a/src/components/Button/Button.module.css +++ b/src/components/Button/Button.module.css @@ -23,4 +23,4 @@ .button:hover { background: #7ac100cc; -} +} \ No newline at end of file diff --git a/src/components/Card/Card.module.css b/src/components/Card/Card.module.css index 86c3fbb5b..9705b2737 100644 --- a/src/components/Card/Card.module.css +++ b/src/components/Card/Card.module.css @@ -114,4 +114,4 @@ .back { z-index: 2; transform: rotateY(180deg); -} +} \ No newline at end of file diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index 7526a56c8..e856fcabf 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -1,14 +1,18 @@ import { shuffle } from "lodash"; -import { useEffect, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { generateDeck } from "../../utils/cards"; import styles from "./Cards.module.css"; import { EndGameModal } from "../../components/EndGameModal/EndGameModal"; import { Button } from "../../components/Button/Button"; import { Card } from "../../components/Card/Card"; +import { EasyContext } from "../../contexte/contexte"; +import { useNavigate } from "react-router-dom"; // Игра закончилась const STATUS_LOST = "STATUS_LOST"; const STATUS_WON = "STATUS_WON"; +// Пауза игры при допускании ошибки выбора карточки +const STATUS_PAUSED = "STATUS_PAUSED"; // Идет игра: карты закрыты, игрок может их открыть const STATUS_IN_PROGRESS = "STATUS_IN_PROGRESS"; // Начало игры: игрок видит все карты в течении нескольких секунд @@ -41,8 +45,18 @@ function getTimerValue(startDate, endDate) { * previewSeconds - сколько секунд пользователь будет видеть все карты открытыми до начала игры */ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { + // Когда игра окончена, переход на главную страницу + const navigate = useNavigate(); + function goTo() { + navigate("/"); + } + + // Обработка количества попыток + const { tries, setTries, isEasyMode } = useContext(EasyContext); + // В cards лежит игровое поле - массив карт и их состояние открыта\закрыта const [cards, setCards] = useState([]); + // Текущий статус игры const [status, setStatus] = useState(STATUS_PREVIEW); @@ -57,16 +71,32 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { minutes: 0, }); - function finishGame(status = STATUS_LOST) { + // Если количество попыток равно 0 устанавливается стату проиграл и игра заканчивается + useEffect(() => { + if (tries === 0) { + finishGame(STATUS_LOST); + } + }, [tries]); + + function finishGame(status) { setGameEndDate(new Date()); setStatus(status); } + + function pausedGame(status = STATUS_PAUSED) { + setStatus(status); + } + function startGame() { const startDate = new Date(); setGameEndDate(null); setGameStartDate(startDate); setTimer(getTimerValue(startDate, null)); setStatus(STATUS_IN_PROGRESS); + // Добавлена проверка на включенный режим 3-х попыток + if (!isEasyMode) { + setTries(1); + } } function resetGame() { setGameStartDate(null); @@ -75,6 +105,24 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { setStatus(STATUS_PREVIEW); } + function сontinueGame(status = STATUS_IN_PROGRESS) { + setStatus(status); + } + + // Функция запускает разные сценарии для кнопки в модальном окне + function whatsNext() { + if (status === STATUS_PAUSED) { + сontinueGame(STATUS_IN_PROGRESS); + } + if (status === STATUS_LOST) { + goTo(); + setTries(3); + } + if (status === STATUS_WON) { + resetGame(); + } + } + /** * Обработка основного действия в игре - открытие карты. * После открытия карты игра может пепереходит в следующие состояния @@ -123,18 +171,23 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { return false; }); - const playerLost = openCardsWithoutPair.length >= 2; + const havMistake = openCardsWithoutPair.length >= 2; - // "Игрок проиграл", т.к на поле есть две открытые карты без пары - if (playerLost) { - finishGame(STATUS_LOST); - return; + // Если на поле есть две открытые карты без пары, то игра паузится и уменьшается количество попыток + function minusTries() { + setTries(prev => prev - 1); + } + + // "Игрок допустил ошибку", т.к на поле есть две открытые карты без пары + if (havMistake) { + minusTries(); + pausedGame(STATUS_PAUSED); } // ... игра продолжается }; - const isGameEnded = status === STATUS_LOST || status === STATUS_WON; + const isGameEnded = status === STATUS_LOST || status === STATUS_WON || status === STATUS_PAUSED; // Игровой цикл useEffect(() => { @@ -195,7 +248,12 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { > )} - {status === STATUS_IN_PROGRESS ? : null} +
Затраченное время:
-Оставшеся количество попыток:
} + {isWon === "Вы победили!" &&Затраченное время:
} + {isWon === "Вы проиграли!" &&Затраченное время:
} + + {isWon === "Вы допустили ошибку" && ( +{tries}
+