├── Images
├── Bear.jpg
├── Dear.jpg
├── Hypo.jpg
├── Lion.jpg
├── Pig.jpg
├── Blank.png
├── Giraffe.jpg
├── Monkey.jpg
├── Pinguin.jpg
├── White.jpg
├── Win_State.png
├── Lose_State.png
└── GameSartScreen.png
├── index.html
├── style.css
├── README.md
└── script.js
/Images/Bear.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Bear.jpg
--------------------------------------------------------------------------------
/Images/Dear.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Dear.jpg
--------------------------------------------------------------------------------
/Images/Hypo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Hypo.jpg
--------------------------------------------------------------------------------
/Images/Lion.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Lion.jpg
--------------------------------------------------------------------------------
/Images/Pig.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Pig.jpg
--------------------------------------------------------------------------------
/Images/Blank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Blank.png
--------------------------------------------------------------------------------
/Images/Giraffe.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Giraffe.jpg
--------------------------------------------------------------------------------
/Images/Monkey.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Monkey.jpg
--------------------------------------------------------------------------------
/Images/Pinguin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Pinguin.jpg
--------------------------------------------------------------------------------
/Images/White.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/White.jpg
--------------------------------------------------------------------------------
/Images/Win_State.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Win_State.png
--------------------------------------------------------------------------------
/Images/Lose_State.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/Lose_State.png
--------------------------------------------------------------------------------
/Images/GameSartScreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vanessaxb/Memory-Game/HEAD/Images/GameSartScreen.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
9 |
10 |
11 | Memory Game
12 |
13 |
14 |
15 | Click Count: 0
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | height:100%;
6 | margin: 0;
7 | background-color: grey;
8 | }
9 |
10 | .h1 {
11 | color:#FDE8D4;
12 | text-shadow: 5px 5px 6px rgba(0, 0, 0, 1);
13 | font-size: 52px;
14 | }
15 |
16 |
17 | .frames {
18 | display: flex;
19 | flex-wrap: wrap;
20 | justify-content: center;
21 | height:450px;
22 | width:230px;
23 | border: 3px solid #FDE8D4;
24 | gap: 5px;
25 | }
26 |
27 | .card {
28 | height: 100px;
29 | width: 50px;
30 | border-radius: 8px;
31 | box-shadow: 0 0 5px 0 black(0, 0, 0, 1);
32 | margin-top: 2px;
33 | margin-bottom: 4px;
34 |
35 | /*adding backface visibility and transform property for flipping*/
36 | transform-style: preserve-3d;/*needed to preserve position*/
37 | /* sets whether children of an element are positioned in the 3D space or are flattened in the plane of the element */
38 | /*adding transition effect for flipping card*/
39 | transition: transform 0.5s;
40 | }
41 |
42 | .front {
43 | /*rotates around Y axis without deforming it*/
44 | /*wohtout it, all cars sow their picture to start with*/
45 | transform: rotateY(180deg);
46 | }
47 |
48 | .front,
49 | .back {
50 | /* Add a backside image to cover the card */
51 | position: absolute;
52 | background-image: url('./Images/White.jpg');
53 | height: 100%;
54 | width: 100%;
55 | backface-visibility: hidden;
56 | border: 1px solid rgba(176, 63, 41, 0.677);
57 | border-radius: 8px;
58 |
59 | }
60 |
61 | .flipped {
62 | transform: rotateY(180deg);
63 | background-size: 50px 100px;
64 | }
65 |
66 | #click-count {
67 | position: absolute;
68 | margin-left: 500px;
69 | margin-top: 270px;
70 | font-size: 20px;
71 | font-weight: bold;
72 | color: #FCF3F0;
73 | }
74 |
75 | #refreshButton {
76 | margin-top: 20px;
77 | padding: 10px 20px;
78 | font-size: 16px;
79 |
80 | background-color:rgba(176, 63, 41, 0.677);
81 | color: white;
82 | border: none;
83 | border-radius: 4px;
84 | cursor: pointer;
85 | }
86 |
87 | #refreshButton:hover {
88 | background-color: #45a049;
89 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kid's Memory Game
2 | This is a project to complete the first module of my Software Engineering certification @Per Scholas
3 |
4 | **How is the game played?**
5 | The player selects the first card, the card flipps. When the second card is selected, if they match: cards keep being flipped. If cards don't match, they will both flip back. Player keeps selecting cards, two by two, either until all cards are selected or time runs out.
6 |
7 | ### Live version: (https://vanessaxb.github.io/Memory-Game/)
8 |
9 | ## Features
10 |
11 | **Win state**: all cards are matched within timer.
12 |
13 | **Lose state**: cards are not macthed within timer.
14 |
15 | **Multiple rounds**: cards will be automaticly shuffled and ready to play again when current game round is over.
16 |
17 | **Reset Game**: at any time, player can choose to click on the New Game button to restard the game.
18 |
19 | **Click Count**: added a click count tracker for scoring.
20 |
21 | ## Tech Stack
22 | 1. HTML
23 | 2. CSS with FlexBox
24 | 3. JS
25 |
26 | **The purpose is to demonstrate my knowledge of:**
27 |
28 | * Semantic HTML and application structure
29 | * Styling and appearance using CSS including FlexBox
30 | * Dynamic events and interactions utilizing JavaScript
31 | * Classes and Object Oriented Programming
32 | * DOM manipulation
33 |
34 | ## Challenges
35 | I had two main challenges:
36 | 1. I chose to compare cards using their class id and not names. This was done by this line: card.setAttribute('data-id', picturesCollection[i]);
37 | As you can see on elements, this code line made 'data-id' = card names, therefore, I could compare them.
38 |
39 | 2. My flipping wasn't showing the back of my card. To solve that, on the createFrame function I had to add 2 more div's, each representing a card's face (front/back) so that I could toggle them using the flipping function.
40 |
41 | ## Images
42 | #### Start Screen
43 | 
44 | #### Win State
45 | 
46 | #### Lose State
47 | 
48 |
49 | ## Resources
50 |
51 | #### setTimeOut: (https://developer.mozilla.org/en-US/docs/Web/API/setTimeout)
52 |
53 | #### alert(): (https://developer.mozilla.org/en-US/docs/Web/API/Window/alert)
54 |
55 | #### Adding pictures to my README.md: (https://code.visualstudio.com/docs/languages/markdown#:~:text=Inserting%20images%20and%20links%20to%20files&text=You%20can%20also%20insert%20images,inserted%20when%20you%20drop%20it.)
56 |
57 | #### toggle(): (https://www.w3schools.com/howto/howto_js_toggle_class.asp)
58 |
59 | #### flipping(): (https://css-tricks.com/almanac/properties/b/backface-visibility/)
60 |
61 | #### location.reload(): (https://www.w3schools.com/jsref/met_loc_reload.asp)
62 |
63 | #### transform and rotate: (https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style)
64 | (https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotateY)
65 |
66 | #### setInterval() and clearInterval: (https://developer.mozilla.org/en-US/docs/Web/API/clearInterval)
67 |
68 | #### Array.prototype.includes(): (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)
--------------------------------------------------------------------------------
/script.js:
--------------------------------------------------------------------------------
1 | // will match any HTML element that has a class attribute with the value 'frames'.
2 | const frameContainer = document.querySelector('.frames');
3 |
4 | let cardChosen = [];
5 | let cardChosenId = [];
6 | let cardsMatched = [];
7 | let clickCounter = 0;
8 |
9 |
10 | //Creating my Picture collection
11 | const picturesCollection = ["Dear.jpg", "Bear.jpg", "Giraffe.jpg", "Hypo.jpg",
12 | "Lion.jpg", "Monkey.jpg", "Pig.jpg", "Pinguin.jpg",
13 | "Dear.jpg", "Bear.jpg", "Giraffe.jpg", "Hypo.jpg",
14 | "Lion.jpg", "Monkey.jpg", "Pig.jpg", "Pinguin.jpg"];
15 |
16 |
17 | console.log(picturesCollection);
18 |
19 |
20 | //*Shuffle cards
21 | //generates a random value between -0.5 and 0.5.
22 | picturesCollection.sort(() => 0.5 - Math.random());//random number between 0 and 1
23 |
24 | //*Creating Frames
25 | function createFrame() {
26 | for (let i = 0; i < picturesCollection.length; i++) {
27 | const card = document.createElement("div");
28 | // creating class list to card
29 | card.classList.add('card');
30 | card.setAttribute('data-id', picturesCollection[i]);
31 |
32 | const front = document.createElement("div");
33 | front.classList.add('front')
34 | //formating my picturesCollection size to fit frame
35 | front.style.backgroundImage = `url(./Images/${picturesCollection[i]})`
36 | front.style.backgroundSize = "50px 100px"
37 |
38 | const back = document.createElement("div");
39 | back.classList.add('back');
40 |
41 | //back element becomes a part of the card element's content, and any
42 | //content or styling associated with back will now be visible inside the card.
43 | card.appendChild(back);
44 | card.appendChild(front);
45 | card.addEventListener('click', flipCard);
46 | card.addEventListener('click', updateClickCounter);
47 |
48 | console.log(card);
49 | frameContainer.appendChild(card);
50 | }
51 | }
52 |
53 | //*Flipping Cards
54 | function flipCard() {
55 | //retrieves the value of the data-id attribute from the clicked card
56 | const cardId = this.getAttribute('data-id');
57 | console.log(cardId);
58 | //doesnt allow me to select cards already matched
59 | if (cardChosen.length >= 2 || cardsMatched.includes(cardId)) {
60 | // Already selected two cards or the card with current 'cardId' has already matched
61 | return;
62 | }
63 | //'This' refers to the DOM element that trigered the function.
64 | //in this case, the card being clicked.
65 | this.classList.toggle('flipped');
66 |
67 | //adds the clicked card (the current DOM element) to cardChosen
68 | cardChosen.push(this);
69 | //cardId holds the ID's of currently chosen cards
70 | cardChosenId.push(cardId);
71 |
72 | if (cardChosen.length === 2) {
73 | //the delay of 500 miliseconds allow player to see the second card before
74 | // checking if it's a pair
75 | setTimeout(checkForMatches, 500);
76 | }
77 | }
78 |
79 | //*Checking for Matches
80 | function checkForMatches() {
81 | const optionOneId = cardChosenId[0];
82 | const optionTwoId = cardChosenId[1];
83 |
84 | if (optionOneId === optionTwoId) {
85 | // alert('You found a match!');
86 | cardsMatched.push(optionOneId);
87 | } else {
88 | cardChosen[0].classList.remove("flipped");
89 | cardChosen[1].classList.remove("flipped");
90 | // alert('Try again');
91 | }
92 |
93 | cardChosen.length = 0;
94 | cardChosenId.length = 0;
95 |
96 | if (cardsMatched.length === picturesCollection.length / 2) {
97 | alert(`Congratulations! You've found them all!`);
98 | }
99 | }
100 |
101 | //*Adding a timer
102 | let timer;
103 | let timeRemaining = 480; //adding 480 seconds timer
104 |
105 | function startTimer() {
106 | //built in JavaScript function that repeatedly executes a specified function
107 | // or code block at a defined time interval.
108 | timer = setInterval(updateTimer, 1000); //Update every second
109 | }
110 |
111 | function updateTimer() {
112 | timeRemaining--;
113 | if (timeRemaining <= 0) {
114 | //built-in JavaScript method used to stop the execution of a function that was
115 | // previously scheduled to run repeatedly at a specified interval using setInterval()
116 | clearInterval(timer);
117 | alert('Time is up! Game over.')
118 | location.reload() //if time is up, it will alert and refresh game
119 | }
120 | }
121 |
122 | //*Adding Click Counter
123 | function updateClickCounter() {
124 | clickCounter++
125 | const clicks = document.querySelector('#click-count')
126 | clicks.textContent = `Click Count: ${clickCounter}`;
127 | }
128 |
129 | //* Event listener for the refresh button
130 | const refreshButton = document.getElementById('refreshButton');
131 | refreshButton.addEventListener('click', () => {
132 | // Reload the page to reset the game
133 | location.reload();
134 | });
135 |
136 | createFrame();
137 | startTimer();
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------