css Audio - Active file-generic CSS - Active Generic - Active HTML - Active JS - Active SVG - Active Text - Active file-generic Video - Active header Love html icon-new-collection icon-person icon-team numbered-list123 pop-out spinner split-screen star tv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <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 rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
    <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">
        		<li><i class="fa fa-star"></i></li>
        		<li><i class="fa fa-star"></i></li>
        		<li><i class="fa fa-star"></i></li>
        	</ul>

        	<div class="moves">
                <span id="moves-made">0 Moves </span>
            </div>
            

            <div class="timer">
                <span id="timer">
                    0:00
                </span>
            </div>

            <div class="restart">
        		<i class="fa fa-repeat"></i>
        	</div>
        </section>

        <ul class="deck" id="deck">
            <li class="card not-shown">
                <i class="fa fa-diamond"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-paper-plane-o"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-anchor"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-bolt"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-cube"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-anchor"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-leaf"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-bicycle"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-diamond"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-bomb"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-leaf"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-bomb"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-bolt"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-bicycle"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-paper-plane-o"></i>
            </li>
            <li class="card not-shown">
                <i class="fa fa-cube"></i>
            </li>
        </ul>
    </div>


    <div id="success-modal" class="modal">
        <div id="success-modal-content" class="modal-style">
            <div class="modal-content">
                 <span class="close-button">&times;</span>
            <h3>Congratulations!</h3>
            <p id="success-message">Test</p>
            <div id="star-rating-message"></div>
            <button id="button-restart">Play again?</button>
            </div>
           
        </div>
    </div>

    <script src="js/app.js"></script>
</body>
</html>

            
          
!
            
              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: 55%;
    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: 20%;
    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);
    margin: 1% 1%;
}

    .deck .card:after {
    content:'';
/*    float:left;*/
    padding-top:100%;


}

.deck .card.open {
    transform: rotateY(0);
    background: #02b3e4;
    cursor: default;
    transition: background 0.4s;
}

.not-shown {
    transform: rotateX(0) rotateY(0);
}

@media (hover: hover) {
    .not-shown:hover{
    background: #02b3e4;
    transform: scale(1.1);
    transition: all 0.05s;
    transform: rotateX(180deg) rotateY(180deg);    
    }
}


.deck .card.show {
    font-size: 33px;
     transform: rotateX(0deg) rotateY(0deg);
    transition: all 1s ease-in;

}


.deck .card.match {
    cursor: default;
    background: #02ccba;
    font-size: 33px;
    transition: background 0.8s;
    transform: skewX(180deg);


}

#deck .red-wrong {
    background-color: red;
}

/*
 * Styles for the Score Panel
 */

.score-panel {
    text-align: left;
    width: 50%;
    margin-bottom: 10px;
    margin-left: 3%;
    display: flex;
}

.score-panel .stars {
    margin: 0;
    padding: 0;
   /* display: inline-flex;*/
    margin: 0 5px 0 0;
    width: 25%;
}

.score-panel .stars li {
    list-style: none;
    display: inline-block;
    width: 25%;
}

.score-panel .moves {
    width: 25%;
}

.score-panel .timer {
    width: 25%;
}

.score-panel .restart {
/*    display: inline-flex;*/
    cursor: pointer;
    width: 25%;
}


/*Modal styles*/

#success-modal {
display: none;
}

.modal {
position: fixed;
z-index: 1;
left: 0;
top: 0;
height: 100%;
width: 100%;
background-color: rgba(0,0,0,0.2);


}

.modal-content {
     background: #ffffff url('../img/geometry2.png'); /* Background pattern from Subtle Patterns */ 
     padding: 1% 5% 5% 5%;
 }

.modal-style {
    background: linear-gradient(160deg, #aa7ecd 0%, #02ccba 100%);
    margin: 10% auto;
    width: 30%;
    padding: 3% 3% 3% 3%;
    box-shadow: 12px 15px 20px 0 rgba(46, 61, 73, 0.5);
    border-radius: 10px;

}

.close-button {
    float: right;
    font-size: 35px;
    color: grey;
    padding-top: 3%;
}

.close-button:hover, .close-button:focus {
    color: #000;
    cursor: pointer;
}

.modal-content p {
    margin-bottom: 10%;
}

#button-restart {
   margin-bottom: 0%;
   background: #2e3d49;
border-radius: 8px;
 box-shadow: 5px 2px 20px 0 rgba(46, 61, 73, 0.5);
 color: #fff;
 font-size: 18px;
 font-family: 'Coda', cursive;
}

#button-restart:hover, #button-restart:focus {
    cursor: pointer;
}



/*media queries*/


@media only screen and (max-width: 767px) {
    .deck {
        min-height: 500px;
    }

    .deck .card.show, .deck .card.match {
        font-size: 25px; 
    }
}

@media only screen and (max-width: 600px) {
    .deck {
        min-height: 350px;
    }

     .deck .card.show, .deck .card.match {
        font-size: 18px; 
    }
}

@media only screen and (max-width: 480px) {
    .deck {
        min-height: 300px;
    }
}
            
          
!
            
              /*
 * Create a list that holds all of your cards
 */



const listItems = document.getElementsByClassName("card");


// console.log(listItems);

const arrListItems = Array.prototype.slice.call(listItems);
// console.log(arrListItems);

const shuffledArray = shuffle(arrListItems);
// console.log(shuffledArray);


let newList = '';
for (i=0; i<shuffledArray.length; i++) {
	newList += shuffledArray[i].outerHTML;
}

function shuffleCards () {
	document.getElementById("deck").innerHTML = newList;
}

// shuffleCards(); - might be easier to work  with unshuffled cards for other parts



/*
 * Display the cards on the page
 *   - shuffle the list of cards using the provided "shuffle" method below
 *   - loop through each card and create its HTML
 *   - add each card's HTML to the page
 */





// 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;
}


/*
 * set up the event listener for a card. If a card is clicked:
 *  - display the card's symbol (put this functionality in another function that you call from this one) --- revealCard()
 *  - add the card to a *list* of "open" cards (put this functionality in another function that you call from this one) --- addOpenCard()
 *  - if the list already has another card, check to see if the two cards match
 *    + if the cards do match, lock the cards in the open position (put this functionality in another function that you call from this one) --- matchCards()
 *    + if the cards do not match, remove the cards from the list and hide the card's symbol (put this functionality in another function that you call from this one) --- hideCards()
 *    + increment the move counter and display it on the page (put this functionality in another function that you call from this one) --- updateMoveCounter()
 *    + if all cards have matched, display a message with the final score (put this functionality in another function that you call from this one)  --- checkIfWon()
 */


// max two cards, will be removed straight away. Cards currently revealed but not matched
let openCards = [];
// this only remains useful for console logging.
let matchedCards = [];
//this informs when the game is won
let matchedCount = 0;
// number of moves player has made - counts when cards are matched and when they are hidden
let moveCount = 0;
// to get cards currently showing that are to be matched
let matchingCards;
// to get cards currently showing that do not match and are to be hidden
let displayedCards;

// to access all cards in restart function
const allCards = document.getElementsByClassName('card');

//modal that appears on completing the game
const successModal = document.getElementById('success-modal');

// button that allows modal to be closed
const closeModalButton = document.getElementsByClassName('close-button')[0];

// button on modal that restarts game
const playAgainButton = document.getElementById('button-restart');

// button above game board, always present, always listening, allowing restart
const restartButton = document.getElementsByClassName("restart")[0];


// have restart button active throughout session
restartButton.addEventListener('click', restartGame);





// Game logic and listeners
//start with shuffle

shuffleCards();


//click event
	document.body.addEventListener('click', function(e) {
		
		// if it is a card that was clicked
		// and a card that isnt being shown
	if (e.target.classList.contains("not-shown") && (document.querySelectorAll('.show').length < 2)) {	
		if (document.querySelectorAll('.not-shown').length == 16 && moveCount === 0) {
			runTimer();
		}
		
		// console.log("card was clicked!");
		// this allows class name of clicked to be compared against array 
		let classMatch = e.target.querySelector('i').className;																	

		
			if (openCards.length < 1) {  // no open cards - first card opened
				// console.log("nothing in the array!");
				//shows the card
				revealCard(e);
				//adds to the open card array
				addOpenCard(e);
				
			} else {  // openCards has something in it, so this card is being compared against the first card that was opened.
				// console.log("there is something in the array");
					if (openCards.includes(classMatch)) {
						// only for console logging
						matchedCards.push(classMatch);
						//shows the card
						revealCard(e);
						// matches the cards, locks them open
						matchCards();
						// increments the move counter by one
						updateMoveCount();
						//resets open cards to zero, re-initialising event listeners
						openCards = [];
					} else {
						// shows the card
						revealCard(e);
						// hides the two open cards as they didn't match
						hideCards();

					}
			}

	}  else {
		console.log("clicked outside cards");
	}
});	



// Functions


function updateMoveCount () {
	moveCount += 1;
	if (moveCount === 1) {
		document.getElementById("moves-made").innerHTML =moveCount+" Move";
	} else {
		document.getElementById("moves-made").innerHTML =moveCount+" Moves";
	}

	adjustStars();
	
	// console.log(moveCount);
}


function matchCards() {
	
		matchedCount += 1;
		// don't want them to turn green instantly
		setTimeout(function() {
		matchingCards = document.querySelectorAll(".show");
		for (let i = 0; i< matchingCards.length; i++) {
			matchingCards[i].className = "card match";
			}
		console.log(matchingCards);
		checkIfWon();
		}, 1000);
}

function hideCards () {
	openCards = [];
	displayedCards = document.querySelectorAll(".show");

	// temporary red colour applied to indicate the cards don't match
	setTimeout(function() {
		for (let i = 0; i< displayedCards.length; i++) {
			displayedCards[i].className += " red-wrong";
			}
	}, 1000);


	setTimeout(function() { 
		// cards hidden
		console.log(displayedCards);
		for (let i = 0; i< displayedCards.length; i++) {
			displayedCards[i].className = "card not-shown";
			}
			}, 3000);
		updateMoveCount();

	}


function revealCard(e) {
	e.target.classList.add('show', 'open');
	e.target.classList.remove('not-shown');
	}

// 
function addOpenCard (e) {
	let classMatch = e.target.querySelector('i').className;
	openCards.push(classMatch);
	}

function checkIfWon () {
	if (matchedCount === 8) {
		// alert("You win! You completed the game in "+moveCount+" moves!");
		stopTimer();
		successModal.style.display='block';
		document.getElementById('success-message').innerHTML = "You win! You completed the game in "+moveCount+" moves in a time of "+completedTime+"!";
	if (moveCount > 0 && moveCount < 13) {
		document.getElementById('star-rating-message').innerHTML = "<i class='fa fa-star'><i class='fa fa-star'><i class='fa fa-star'>";
	}
	if (moveCount > 13 && moveCount < 19) {
	document.getElementById('star-rating-message').innerHTML = "<i class='fa fa-star'><i class='fa fa-star'>";
	}
	if (moveCount > 19 && moveCount < 26) {
	document.getElementById('star-rating-message').innerHTML = "<i class='fa fa-star'>";
	}

	if(moveCount > 26) {
		document.getElementById('star-rating-message').innerHTML = "...no stars. Try and complete in less moves next time.";
	}
}
		closeModal();
		

	}


function playAgain () {
	playAgainButton.addEventListener('click', restartGame);
	displayTimer.textContent = "0:00";
}

//closing modal functions
function closeModal () {
	closeModalButton.addEventListener('click', function () {
		successModal.style.display = 'none';
	});	
	window.addEventListener('click', windowCloseModal);
	playAgain();
}

function windowCloseModal (e) {
	if (e.target == successModal) {
		successModal.style.display = 'none';
	}
}

function restartGame () {
	// loop all cards and set class to not-shown
	for (let i = 0; i< allCards.length; i++) {
			allCards[i].className = "card not-shown";
			}

	// make sure everything is reset
	shuffleCards();
	moveCount = 0;
	document.getElementById("moves-made").innerHTML = moveCount;
	openCards = [];
	matchedCards = [];
	matchingCards = '';
	displayedCards = '';

	// make sure modal is not displaying
	successModal.style.display = 'none';
	stopTimer();
	displayTimer.textContent = "0:00";
	// Reset move count
	document.getElementById("moves-made").innerHTML =moveCount+" Moves";

}


//timer
const displayTimer = document.querySelector('#timer');
let clock;

let timerStart;
let timeNow;
let timerEnd;

let secondsElapsed;
let minutesElapsed;
let secondsRounded;
let secondsFormatted;
let timeElapsed;

let completedTime;

let clickToRun;
// runTimerOnFirstClick();


function runTimer() {
	timerStart = Date.now();
	clock = setInterval(function() {
	displayTime(clock);
	}, 1000)

	//remove it
	document.removeEventListener('click', runTimer);
}


function stopTimer() {

	clearInterval(clock);
	completedTime = document.querySelector('#timer').textContent;

	// console.log(completedTime);
}

function displayTime(clock) {
	timeNow = Date.now();
	secondsElapsed = (timeNow - timerStart) / 1000;
	minutesElapsed = Math.floor(secondsElapsed / 60);
	// seconds that take number of minutes into account
	secondsRounded = Math.floor(secondsElapsed % 60);
	secondsFormatted = secondsRounded < 10 ? '0'+secondsRounded: secondsRounded;
	timeElapsed = minutesElapsed+":"+secondsFormatted;
	displayTimer.textContent = timeElapsed;
	// console.log(timeElapsed);
}

const starRating = document.getElementsByClassName('stars')[0];

function adjustStars () {
	if (moveCount > 12) {
		starRating.innerHTML = "<li><i class='fa fa-star'></i></li><li><i class='fa fa-star'></i></li>";
	}
	if (moveCount > 18) {
		starRating.innerHTML = "<li><i class='fa fa-star'></i></li>";
	}
	if (moveCount > 25) {
		starRating.innerHTML = "<li><i class='fa fa-star-half'></i></li>";
	}

	if(moveCount > 27) {
		starRating.innerHTML = "<li><i>...</i></li>";
	}
}


// star rating system

// thresholds for moves 12 18 and 25 
// simple if statement after move adjustment function
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console