diff --git a/src/main.tsx b/src/main.tsx index 071d1ba..f0bf150 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -11,6 +11,7 @@ import SQL from "./components/SQL"; import Landingpage from "./pages/michael/Landingpage"; import CsharpQuiz1 from "./pages/michael/mini-game/Quiz1"; import AuthenticationPage from "./pages/authentication/Loginpage"; +import MatchingCardGame from "./pages/matching-card-game/Card"; const router = createBrowserRouter([ { @@ -52,6 +53,10 @@ const router = createBrowserRouter([ path: "/games/CsharpQuiz1", element: , }, + { + path: "/games/matchingGame", + element: , + }, ]); ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( diff --git a/src/pages/matching-card-game/Card.css b/src/pages/matching-card-game/Card.css new file mode 100644 index 0000000..2085e3c --- /dev/null +++ b/src/pages/matching-card-game/Card.css @@ -0,0 +1,66 @@ +@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital@1&display=swap'); + + +.matching-card-body { + box-sizing: border-box; + display: flex; + flex-direction: column; + margin: 0; + font-family: Montserrat, sans-serif; + min-height: 100vh; + border: 10px solid white; + background-color: white; +} + + +#main { + display: flex; + flex: 1; +} + +#main > .matching-card-cards { + flex: 1; + background: rgb(106, 64, 117); + padding: 0em; /* reduce padding */ +} + +#main > .matching-card-input { + flex: 0 0 20%; + background: #d0c1a6; + order: 2; + padding: 1.5em; /* reduce padding */ +} + +.matching-card-header{ + background: #ffffff; + height: 4vh; + text-align: center; + padding: 0.1em; +} + +.matching-card-cards, .matching-card-input{ + padding: 1em; +} + + +#main .matching-card-cards .card-grid { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-gap: 20px; +} + +.NewGame { + border: 2px solid #d682e1; + transition-duration: 0.4s; +} + +.NewGame:hover { + background-color: white; + color: black; +} + + + + + + \ No newline at end of file diff --git a/src/pages/matching-card-game/Card.tsx b/src/pages/matching-card-game/Card.tsx new file mode 100644 index 0000000..934ade9 --- /dev/null +++ b/src/pages/matching-card-game/Card.tsx @@ -0,0 +1,194 @@ +import React, { useEffect, useState } from "react"; +import "./Card.css"; +import SingleCard from "./component/SingleCard"; + +import cSharp from "./img/cSharp.png"; +import Java1 from "./img/Java-1.png"; +import Java2 from "./img/Java-2.png"; +import JS1 from "./img/JS-1.png"; +import JS2 from "./img/JS-2.png"; +import Python1 from "./img/Python-1.png"; +import Python2 from "./img/Python-2.png"; +import Php1 from "./img/Php-1.png"; +import SQL1 from "./img/SQL-1.png"; +import SQL2 from "./img/SQL-2.png"; + +const cardClassName = "card-images"; + +const cardImages = [ + { id: 1, src: cSharp, matched: false, className: cardClassName }, + { id: 2, src: Java1, matched: false, className: cardClassName }, + { id: 3, src: JS1, matched: false, className: cardClassName }, + { id: 4, src: Python1, matched: false, className: cardClassName }, + { id: 5, src: Php1, matched: false, className: cardClassName }, + { id: 6, src: SQL1, matched: false, className: cardClassName }, +]; + +const cardImages2 = [ + { id: 111, src: cSharp, matched: false, className: cardClassName }, + { id: 222, src: Java2, matched: false, className: cardClassName }, + { id: 333, src: JS2, matched: false, className: cardClassName }, + { id: 444, src: Python2, matched: false, className: cardClassName }, + { id: 555, src: Php1, matched: false, className: cardClassName }, + { id: 666, src: SQL2, matched: false, className: cardClassName }, +]; + +function App() { + const [cards, setCards] = useState([]); + const [turns, setTurns] = useState(0); + const [choiceOne, setChoiceOne] = useState(null); + const [choiceTwo, setChoiceTwo] = useState(null); + const [disabled, setDisabled] = useState(false); + const [time, setTime] = useState(0); + const [score, setScore] = useState(0); + + //shuffle cards + const shuffleCards = () => { + const shuffledCards = [...cardImages, ...cardImages2] + .sort(() => Math.random() - 0.5) + .map((card) => ({ ...card })); + + setChoiceOne(null); + setChoiceTwo(null); + setCards(shuffledCards); + setTurns(0); + setTime(0); + }; + + type Card = { + id: number; + src: string; + matched: boolean; + }; + + // handle a choice + const handleChoice = (card: Card) => { + if (!choiceOne) { + setChoiceOne(card); + } else if (!choiceTwo && choiceOne.id !== card.id) { + setChoiceTwo(card); + } + }; + + useEffect(() => { + const matchingPairs: { [key: number]: number } = { + 1: 111, + 2: 222, + 3: 333, + 4: 444, + 5: 555, + 6: 666, + // Add more matching pairs as needed + }; + + //handles card matching + const handleCardMatching = () => { + if (choiceOne && choiceTwo) { + setDisabled(true); + if ( + choiceOne.id === choiceTwo.id || + matchingPairs[choiceOne.id] === choiceTwo.id || + matchingPairs[choiceTwo.id] === choiceOne.id + ) { + setCards((prevCards) => + prevCards.map((card) => { + if (card.id === choiceOne.id || card.id === choiceTwo.id) { + return { ...card, matched: true }; + } else { + return card; + } + }) + ); + resetTurn(); + } else { + setTimeout(() => { + resetTurn(); + setChoiceOne(null); + setChoiceTwo(null); + }, 1000); + } + } + }; + + handleCardMatching(); + const calculatedScore = totalScore(time, turns); + setScore(calculatedScore); + }, [choiceOne, choiceTwo, time, turns]); + + // add timer + useEffect(() => { + const timerId = setInterval(() => { + setTime((prevTime) => prevTime + 1); + }, 1000); + if (cards.every((card) => card.matched)) { + clearInterval(timerId); + } + return () => clearInterval(timerId); + }, [cards]); + + // reset choices and increase turn + const resetTurn = () => { + setChoiceOne(null); + setChoiceTwo(null); + setTurns((prevTurns) => prevTurns + 1); + setDisabled(false); + }; + + //game start + useEffect(() => { + shuffleCards(); + }, []); + + //calculating scores + + const totalScore = (time: number, turns: number): number => { + const baseScore = 1000; + const timePenalty = 2; + const turnPenalty = 3; + + const timePenaltyTotal = time * timePenalty; + const turnPenaltyTotal = turns * turnPenalty; + + const score = Math.max(baseScore - timePenaltyTotal - turnPenaltyTotal, 0); + + return score; + }; + + return ( + + + + MATCHING CARDS + + + + {/* adding the shuffled cards */} + {cards.map((card) => ( + + ))} + + + + + New Game + + Turns: {turns} + Time: {time} + Score: {score} + + + + + + ); +} + +export default App; diff --git a/src/pages/matching-card-game/component/Cover.png b/src/pages/matching-card-game/component/Cover.png new file mode 100644 index 0000000..cc4aa58 Binary files /dev/null and b/src/pages/matching-card-game/component/Cover.png differ diff --git a/src/pages/matching-card-game/component/SingleCard.css b/src/pages/matching-card-game/component/SingleCard.css new file mode 100644 index 0000000..fca472d --- /dev/null +++ b/src/pages/matching-card-game/component/SingleCard.css @@ -0,0 +1,30 @@ +.matching-card{ + position: relative; +} + +.matching-card img{ + width: 140px !important; + display: block; + border: 2px solid #000000; + border-radius: 6px; + height: 200px;; +} + +.matching-card .matching-card-front { + transform: rotateY(90deg); + transition: all ease-in 0.1s; + position: absolute; +} +.flipped .matching-card-front { + transform: rotateY(0deg); + transition-delay: 0.2s; +} + +.matching-card .matching-card-back { + transition: all ease-in 0.2s; + transition-delay: 0.2s; +} +.flipped .matching-card-back { + transform: rotateY(90deg); + transition-delay: 0s; +} diff --git a/src/pages/matching-card-game/component/SingleCard.tsx b/src/pages/matching-card-game/component/SingleCard.tsx new file mode 100644 index 0000000..5a8f385 --- /dev/null +++ b/src/pages/matching-card-game/component/SingleCard.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import "./SingleCard.css"; +import Cover from "./Cover.png"; + +interface Props { + card: { + id: number; + src: string; + matched: boolean; + }; + handleChoice: (card: { id: number; src: string; matched: boolean }) => void; + flipped: boolean; + disabled: boolean; +} + +const SingleCard: React.FC = ({ + card, + handleChoice, + flipped, + disabled, +}) => { + const handleClick = () => { + if (!disabled) { + handleChoice(card); + } + }; + + return ( + + + + + + + ); +}; + +export default SingleCard; diff --git a/src/pages/matching-card-game/img/JS-1.png b/src/pages/matching-card-game/img/JS-1.png new file mode 100644 index 0000000..5c4e4c7 Binary files /dev/null and b/src/pages/matching-card-game/img/JS-1.png differ diff --git a/src/pages/matching-card-game/img/JS-2.png b/src/pages/matching-card-game/img/JS-2.png new file mode 100644 index 0000000..63ae4fb Binary files /dev/null and b/src/pages/matching-card-game/img/JS-2.png differ diff --git a/src/pages/matching-card-game/img/Java-1.png b/src/pages/matching-card-game/img/Java-1.png new file mode 100644 index 0000000..7a51908 Binary files /dev/null and b/src/pages/matching-card-game/img/Java-1.png differ diff --git a/src/pages/matching-card-game/img/Java-2.png b/src/pages/matching-card-game/img/Java-2.png new file mode 100644 index 0000000..82bd98e Binary files /dev/null and b/src/pages/matching-card-game/img/Java-2.png differ diff --git a/src/pages/matching-card-game/img/Php-1.png b/src/pages/matching-card-game/img/Php-1.png new file mode 100644 index 0000000..09c312a Binary files /dev/null and b/src/pages/matching-card-game/img/Php-1.png differ diff --git a/src/pages/matching-card-game/img/Python-1.png b/src/pages/matching-card-game/img/Python-1.png new file mode 100644 index 0000000..767b803 Binary files /dev/null and b/src/pages/matching-card-game/img/Python-1.png differ diff --git a/src/pages/matching-card-game/img/Python-2.png b/src/pages/matching-card-game/img/Python-2.png new file mode 100644 index 0000000..17d8ae5 Binary files /dev/null and b/src/pages/matching-card-game/img/Python-2.png differ diff --git a/src/pages/matching-card-game/img/SQL-1.png b/src/pages/matching-card-game/img/SQL-1.png new file mode 100644 index 0000000..bade885 Binary files /dev/null and b/src/pages/matching-card-game/img/SQL-1.png differ diff --git a/src/pages/matching-card-game/img/SQL-2.png b/src/pages/matching-card-game/img/SQL-2.png new file mode 100644 index 0000000..775cfbb Binary files /dev/null and b/src/pages/matching-card-game/img/SQL-2.png differ diff --git a/src/pages/matching-card-game/img/cSharp.png b/src/pages/matching-card-game/img/cSharp.png new file mode 100644 index 0000000..9f89044 Binary files /dev/null and b/src/pages/matching-card-game/img/cSharp.png differ diff --git a/src/pages/matching-card-game/index.tsx b/src/pages/matching-card-game/index.tsx new file mode 100644 index 0000000..9c48d7a --- /dev/null +++ b/src/pages/matching-card-game/index.tsx @@ -0,0 +1,5 @@ +import ReactDOM from "react-dom"; + +import Card from "./Card"; + +ReactDOM.render(, document.getElementById("root"));
Turns: {turns}
Time: {time}
Score: {score}