├── 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 | ![alt text](Images/GameSartScreen.png "Memory Game Start Screen") 44 | #### Win State 45 | ![alt text](Images/Win_State.png "Win State Screen") 46 | #### Lose State 47 | ![alt text](Images/Lose_State.png "Lose State Screen") 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 | --------------------------------------------------------------------------------