This a memory game is created with HTML, CSS and Javascript.
How To Play
The game board consists of randomly placed 8 different pairs of face down cards.
- Click on a card to reveal the card.
- Click on another card to reveal it as well.
- If two cards match,they will remain revealed otherwise they will be face down again.
- Once all the cards are matched, game ends and pop up window appears with information of how many moves you took to complete the game and your rating aka your bragging rights.
HTML
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Matching Game</title> <meta name="description" content=""> <link rel="stylesheet prefetch" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css"> <link rel="stylesheet prefetch" href="https://fonts.googleapis.com/css?family=Coda"> <link href="https://afeld.github.io/emoji-css/emoji.css" rel="stylesheet"> <link rel="stylesheet" href="css/app.css"> </head> <body> <div class="container"> <header> <h1>Matching Game</h1> </header> <section class="score-panel"> <ul class="stars"> </ul> <span class="moves"></span> Moves <span class="timer">time</span> <div class="restart"> <i class="fa fa-repeat"></i> </div> </section> <ul class="deck"> <li class="card"> <i class="fa fa-diamond"></i> </li> <li class="card"> <i class="fa fa-paper-plane-o"></i> </li> <li class="card"> <i class="fa fa-anchor"></i> </li> <li class="card"> <i class="fa fa-bolt"></i> </li> <li class="card"> <i class="fa fa-cube"></i> </li> <li class="card"> <i class="fa fa-anchor"></i> </li> <li class="card"> <i class="fa fa-leaf"></i> </li> <li class="card"> <i class="fa fa-bicycle"></i> </li> <li class="card"> <i class="fa fa-diamond"></i> </li> <li class="card"> <i class="fa fa-bomb"></i> </li> <li class="card"> <i class="fa fa-leaf"></i> </li> <li class="card"> <i class="fa fa-bomb"></i> </li> <li class="card"> <i class="fa fa-bolt"></i> </li> <li class="card"> <i class="fa fa-bicycle"></i> </li> <li class="card"> <i class="fa fa-paper-plane-o"></i> </li> <li class="card"> <i class="fa fa-cube"></i> </li> </ul> </div> <!-- Complete Modal --> <div id="completeModal" class="modal"> <!-- Modal content --> <div class="modal-content"> <div class="modal-text"> <span>You did it!!!</span> <i class="em em-trophy"></i> <i class="em em-clap"></i> <i class="em em-clap"></i> <i class="em em-clap"></i> <p>You completed the game in <span id="totalMove"></span> move(s) in <span id="totalTime"></span> </p> <p><span class="star_rating"></span> </p> <p><span class="start_again">Start Again</span></p> </div> </div> </div> <script src="js/app.js"></script> </body> </html>
CSS
@import url('https://fonts.googleapis.com/css?family=Indie+Flower'); html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; } html, body { width: 100%; height: 100%; margin: 0; padding: 0; } body { background: #ffffff url('../img/geometry2.png'); /* Background pattern from Subtle Patterns */ font-family: 'Coda', cursive; } .container { display: flex; justify-content: center; align-items: center; flex-direction: column; } h1 { font-family: 'Open Sans', sans-serif; font-weight: 300; } /* * Styles for the deck of cards */ .deck { width: 660px; min-height: 680px; background: linear-gradient(160deg, #02ccba 0%, #aa7ecd 100%); padding: 32px; border-radius: 10px; box-shadow: 12px 15px 20px 0 rgba(46, 61, 73, 0.5); display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; margin: 0 0 3em; } .deck .card { height: 125px; width: 125px; background: #2e3d49; font-size: 0; color: #ffffff; border-radius: 8px; cursor: pointer; display: flex; justify-content: center; align-items: center; box-shadow: 5px 2px 20px 0 rgba(46, 61, 73, 0.5); } .deck .card.open { transform: rotateY(0); background: #02b3e4; cursor: default; } .deck .card.show { font-size: 33px; } .deck .card.match { animation: pop 0.5s; cursor: default; background: #02ccba; font-size: 33px; } .deck .card.disabled { pointer-events: none; } .deck .card.unmatched { animation: shake 0.65s; background: rgb(226,4,59); } /* * Styles for the Score Panel */ .score-panel { text-align: left; width: 345px; margin-bottom: 10px; } .score-panel .stars { margin: 0; padding: 0; display: inline-block; margin: 0 5px 0 0; } .score-panel .stars li { list-style: none; display: inline-block; } .score-panel .restart { float: right; cursor: pointer; } /** End of Score Panel **/ /* * Styles for Modal */ /** Modal from https://www.w3schools.com/howto/howto_css_modals.asp **/ .modal { display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ padding-top: 100px; /* Location of the box */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0,0,0); /* Fallback color */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ } .modal-content { background-color: #fefefe; margin: auto; padding: 20px; border: 1px solid #888; width: 60%; } .modal-text { width: 80%; margin-left: 100px; font-size: 2em; font-family: 'Indie Flower', cursive,sans-serif; } .start_again { cursor: pointer; border: 1px solid rgb(187, 186, 186); text-align: center; padding: 10px; box-shadow: 2px 3px 0 #000; margin-left: 35%; border-radius: 5px; font-size: 0.8em; } .fa-star, .star_style { color: #feda68; } .fa-star{ font-size: 22px; } /** End of Modal **/ /* animation for shake unmatched card */ @keyframes shake { 0% { transform: translate(0px, 0px);} 15% { transform: translate(9px, 0px);} 30% { transform: translate(-9px, 0px);} 45% { transform: translate(9px, 0px);} 60% { transform: translate(-9px, 0px);} 75% { transform: translate(9px, 0px);} 90% { transform: translate(-9px, 0px);} 100% { transform: translate(0px, 0px);} } @keyframes pop { 0% { transform: scale(0.5); } 100% { transform: scale(1); } }
Javascript
//convert node list to array let card_array = [].slice.call(document.querySelectorAll(".card")); let deck = document.querySelector('.deck'); //For modal let modal = document.querySelector('#completeModal'); let start_again = document.querySelector('.start_again'); let star_rating_modal = document.querySelector('.star_rating'); let stars = ''; //For counting moves let move = document.querySelector(".moves"); let move_counter = 0; //For display time let timer = document.querySelector('.timer'); let time_interval; //For restarting the game let restart = document.querySelector(".restart"); let list_open_cards = []; let match_counter = 0; let star_rating_board = document.querySelector('.stars'); // Shuffle function from http://stackoverflow.com/a/2450976 function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex; while (currentIndex !== 0) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } window.onload = init(); //function for starting game function init() { var shuffle_cards = shuffle(card_array); for (var i = 0; i < shuffle_cards.length; i++) { var li = shuffle_cards[i] var icon = shuffle_cards[i].querySelector('i'); li.id = icon.classList[1]; deck.appendChild(li); shuffle_cards[i].classList.remove("show", "open", "match", "disabled"); } star_rating_board.innerHTML = ''; for(var j = 0; j < 3; j++){ var li = document.createElement("li"); var i = document.createElement("i"); i.setAttribute("class", "fa fa-star"); li.appendChild(i); star_rating_board.appendChild(li); } list_open_cards = []; move_counter = 0; match_counter = 0; move.innerHTML = move_counter; sec = 0; timer.innerHTML = 'time'; clearInterval(time_interval); } //function for checking if card matches or not function openCard() { if(list_open_cards.length < 2 ){ displayCard(this); moveCounter(); if(list_open_cards.length === 0){ list_open_cards.push(this); }else if(list_open_cards.length === 1){ list_open_cards.push(this); if(list_open_cards[0].id === list_open_cards[1].id){ match_counter+=2; matched(); if(match_counter === card_array.length){ clearInterval(time_interval); complete(); } }else{ unmatched(); } } } } //function for displaying clicked card function displayCard(card){ card.classList.toggle('show'); card.classList.toggle('open'); card.classList.add('disabled'); } //function for adding classes to matched card function matched(){ list_open_cards[0].classList.add("match", "disabled"); list_open_cards[1].classList.add("match", "disabled"); list_open_cards = []; } //function for adding and removing classes to cards that do not match function unmatched(){ list_open_cards[0].classList.add("unmatched"); list_open_cards[1].classList.add("unmatched"); setTimeout(function(){ list_open_cards[0].classList.remove("show", "open", "unmatched","disabled"); list_open_cards[1].classList.remove("show", "open", "unmatched","disabled"); list_open_cards = []; },1100); } //function for counting moves function moveCounter(){ move_counter++; if(move_counter === 1){ displayTimer(); } move.innerHTML = move_counter; if(move_counter > 16 && move_counter <= 24){ stars = '<span class="star_style"><i class="fa fa-star"></i></span>'+'<span class="star_style"><i class="fa fa-star"></i></span>'; star_rating_board.innerHTML = stars; } if(move_counter > 24){ stars = '<span class="star_style"><i class="fa fa-star"></i></span>'; star_rating_board.innerHTML = stars; } } //function for timer - how many seconds function displayTimer(){ time_interval = setInterval(function(){ sec++; timer.innerHTML = sec+"secs"; },1000); } //function for displaying modal when game is completed function complete(){ document.getElementById("totalMove").innerHTML = move_counter; document.getElementById("totalTime").innerHTML = timer.innerHTML; star_rating_modal.innerHTML = "Rating "+ stars; star_rating_board.innerHTML = "Rating "+ stars; modal.style.display = "block"; match_counter = 0; clearInterval(time_interval); } //function for closing modal function close(){ modal.style.display = "none"; init(); } start_again.addEventListener('click', close); restart.addEventListener('click', init); for (var i = 0; i < card_array.length; i++) { card_array[i].addEventListener('click', openCard); }