Pen Settings

HTML

CSS

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

JavaScript

Babel includes JSX processing.

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

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

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.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <body>

    <div class="container">
        <header class="row text-center">
            <h1 class="col pt-2 mt-2">Memory Match</h1>
        </header>

        <section class="row score-panel">
            <ul class="stars col-3 m-0 p-2" title="Score">
                <li>
                    <i class="fas fa-star"></i>
                </li>
                <li>
                    <i class="fas fa-star"></i>
                </li>
                <li>
                    <i class="fas fa-star"></i>
                </li>
            </ul>

            <div class="col-3 m-0 p-2 text-center" title="Attempted matches">
                <span class="moves">0</span>
                <span class="moves-label">Moves</span>
            </div>

            <div class="col-3 m-0 p-2 text-center" title="Time elapsed">
                <span class="timer">0</span>
                <span class="timer-label">Seconds</span>
            </div>

            <div class="restart col-3 m-0 p-2 text-right" title="Start over">
                <i class="fas fa-redo"></i>
            </div>
        </section>

        <ul class="row deck p-4">
            <!-- Created dynamically via js/app.js -->
        </ul>
    </div>
</body>
              
            
!

CSS

              
                /******************************************************************************
  MASTER STYLESHEET



  INFORMATION
  Project...................Memory Game
  Purpose...................Udacity Front-End Nanodegree Program
                            Project 2
  Creator...................Ryan Delk
  Last Change...............June 3, 2018



  CONTENTS
  1. Global.................Global variables and styles
  2. Squares................Square styling
  3. Scoring................Score panel styling
  4. Animation..............Animation speeds
  5. Media..................Media queries and breakpoints

******************************************************************************/

/**************************************
    1. Global
**************************************/

/* Defining color palette to be used throughout CSS */
:root {
    --color-gradient-1: #02ccba;
    --color-gradient-2: #aa7ecd;
    --color-square-open: #02b3e4;
    --color-square-match: #02ccba;
    --color-shadow: rgba(46, 61, 73, 0.5);
}

html {
    box-sizing: border-box;
}

*,
*::before,
*::after {
    box-sizing: inherit;
}

html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
    width: 100%;
}

body {
    background: #ffffff url('https://res.cloudinary.com/rdelk/image/upload/v1528058711/FEND%20-%20Project%202/geometry2.png');
    font-family: 'Coda', cursive;
}

.container {
    height: 680px;
    max-width: 660px;
}

h1 {
    font-family: 'Open Sans', sans-serif;
    font-weight: 300;
}

li {
    list-style: none;
}



/**************************************
    2. Squares
**************************************/

/* Background container for squares */
.deck {
    background: linear-gradient(160deg, var(--color-gradient-1) 0%, var(--color-gradient-2) 100%);
    border-radius: 10px;
    box-shadow: 12px 15px 20px var(--color-shadow);
}

/* Default square styling */
.deck .square {
    background: #2e3d49;
    border-radius: 6px;
    box-shadow: 5px 2px 20px var(--color-shadow);
    color: #ffffff;
    cursor: pointer;
    height: 120px;
    font-size: 0;
}

/* List items under the deck */
.deck .li {
    align-content: center;
}

/* Emphasize square on hover */
.square-hover {
    box-shadow: 5px 10px 20px var(--color-shadow);
    transform: scale(1.02);
}

/* Change background color of square that has been flipped */
.deck .square.open {
    background: var(--color-square-open);
    cursor: default;
}

/* Make icons appear when square is flipped */
.deck .square.show {
    font-size: 33px;
}

/* Change styling to identify squares that have been matched */
.deck .square.match {
    background: var(--color-square-match);
    cursor: default;
    font-size: 33px;
}



/**************************************
    3. Scoring
**************************************/

/* Keep star icons in a horizontal line */
.score-panel .stars li {
    display: inline-block;
    list-style: none;
}

/* Make cursor a pointer to show that "Reset" icon is clickable */
.score-panel .restart {
    cursor: pointer;
}



/**************************************
    4. Animation
**************************************/

/* Animation speed */
.square.animated.flipInY {
    animation-duration: 0.5s;
    -o-animation-duration: 0.5s;
    -ms-animation-duration: 0.5s;
    -moz-animation-duration: 0.5s;
    -webkit-animation-duration: 0.5s;
}
              
            
!

JS

              
                ///////////////////////////////////////////////////////////////////////////////
//  MASTER JS
//
//
//
//  INFORMATION
//  Project.................Memory Game
//  Purpose.................Udacity Front-End Nanodegree Program
//                          Project 2
//  Creator.................Ryan Delk
//  Last Change.............June 5, 2018
//
//
//
//  CONTENTS
//  1. INITIALIZATION
//    a. Ready..............Functions to call on $(document).ready
//    b. Start..............Functions to start the game
//    c. Reset..............Reset current game
//
//  2. SQUARES
//    a. Matching...........Functions to determine matches
//    b. Styling............Functions to style the squares upon interaction
//
//  3. SCORING
//    a. Stars..............Functions to decrement stars
//    b. Timer..............Functions to time the current game
//    c. Win................Declare when game is won
//
//
//
//  NOTES
//    To jump to a specific section, search (CTRL + F) for the
//    section's primary heading number, followed by its
//    subsection's letter.
//
//    e.g. Search for "2b" to go to the Squares/Styling section
//
///////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////
//  1a. Ready
///////////////////////////////////////

// Variables
const arrIcons = ['burn', 'burn', 'infinity', 'infinity', 'moon', 'moon', 'skull', 'skull', 'code-branch', 'code-branch', 'terminal', 'terminal', 'crow', 'crow', 'seedling', 'seedling'];
let $deck = $('.deck'),
  $moves = $('.moves'),
  $movesLabel = $('.moves-label'),
  $reset = $('.fa-redo'),
  $timer = $('.timer'),
  $timerLabel = $('.timer-label'),
  arrIconsOpen = [],
  movesCount = 0,
  paused = false,
  started = false,
  timeCount = 0;

// Run after the page has finished loading
$(document).ready(function () {

  // Call function to create game elements
  init();

  // Reset the game when button is clicked
  $reset.click(resetGameWarning);
});



///////////////////////////////////////
//  1b. Start
///////////////////////////////////////

// Call functions to enable game functionality, establish global variables
function init() {

  // Squares need to exist before their classes can be selected
  createSquares();

  // Variables for selectors that can only be called after squares are created
  let $square = $('.square');

  // Enable functionality for square interaction
  hoverSquare();
  $square.click(flipSquares);

  // Properties for "Reset" and "Win" dialog boxes
  vex.defaultOptions.className = 'vex-theme-default';
  vex.dialog.buttons.YES.text = 'Yes';
  vex.dialog.buttons.NO.text = 'No';
};

// Shuffle the icons, then create li items ($('.square')) for each
function createSquares() {
  let icons = shuffle(arrIcons);
  for (let icon of icons) {
    $deck.append($('<li class="col-3 p-3"><div class="square p-3 d-flex align-items-center justify-content-center animated"><i class="fas fa-' + icon + '"></i></div></li>'));
  };
};

// Function to shuffle array items
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;
};



///////////////////////////////////////
//  1c. Reset
///////////////////////////////////////

// Reset game to initialization state
function resetGame() {
  $deck.empty();
  movesCount = -1;
  moveCounter();
  paused = false;
  $timerLabel.html('Seconds');
  $('.far.fa-star').toggleClass('fas far');
  arrIconsOpen = [];
  resetTimer();
  init();
};

// Modal dialog to confirm reset
function resetGameWarning() {
  paused = true;

  vex.dialog.confirm({
    message: `Are you sure you wish to reset?`,
    callback: function (value) {
      if (value) {
        resetGame();
      } else {
        paused = false;
      }
    }
  });
};



///////////////////////////////////////
//  2a. Matching
///////////////////////////////////////

//  Check if the two open squares match
function checkMatch() {

  // If the array elements are the same
  if (arrIconsOpen[0] === arrIconsOpen[1]) {
    $deck.find('.open').removeClass('open show flipInY shake').addClass('match rubberBand');
  } else {
    setTimeout(function () {
      $deck.find('.open').addClass('shake').removeClass('open show flipInY');
    }, 500);
  };

  // Increment move count
  moveCounter();

  // If all squares have been matched, win the game
  if ($('.match').length === 16) {
    winGame();
  };

  // Clear temp array
  arrIconsOpen = [];
};



///////////////////////////////////////
//  2b. Styling
///////////////////////////////////////

// When a square is clicked, do this stuff
function flipSquares() {

  // Working with currently clicked square
  let $this = $(this);

  // Traverse DOM element for this square's icon class
  let $thisClass = $this[0].firstChild.classList[1];

  // Prevent flipping over more than two cards at once
  if ($this.hasClass('open') || $this.hasClass('match') || $('.open').length === 2) {
    return;
  };

  // Start timer when first square is clicked
  if (started === false) {
    startTimer();
  };

  // If the temporary array doesn't yet have two items in it
  if (arrIconsOpen.length < 2) {
    $this.addClass('open show flipInY');

    // Add class of clicked square to the temp array
    arrIconsOpen.push($thisClass);
  };

  // If two squares have been flipped, check to see if they match
  if (arrIconsOpen.length === 2) {
    checkMatch();
  };
};

// Styling when hovering over a square that hasn't been flipped
function hoverSquare() {
  $('.square:not(.open)').hover(function () {
    $(this).toggleClass('square-hover');
  }, function () {
    $(this).toggleClass('square-hover');
  });
};


///////////////////////////////////////
//  3a. Stars
///////////////////////////////////////

// Change solid star icon class to outlined version when a star is removed
function removeStar() {
  let $star = $('.fas.fa-star:last');
  $star.toggleClass('fas far');

  // // Get current star count
  // let starCount = $('.fas.fa-star').length;
};

// Increment moves
function moveCounter() {

  // Increase move count by one
  movesCount++;

  // Grammar check so score doesn't read "1 Moves"
  if (movesCount === 1) {
    $movesLabel.html('Move');
  } else {
    $movesLabel.html('Moves');
  }

  // Star removal when specific move counts are hit
  switch (movesCount) {
    case 15:
      removeStar();
      break;
    case 20:
      removeStar();
      break;
    default:
      break;
  }

  // Update page display of move count
  $moves.html(movesCount);
};



///////////////////////////////////////
//  3b. Timer
///////////////////////////////////////

// Start the timer
function startTimer() {

  // Increment the counter every second
  timeCountVar = setInterval(function () {

    // Only increment if the game isn't "paused" (a modal window is open)
    if (paused === false) {
      timeCount++;

      // Grammar check so timer doesn't read "1 Seconds"
      if (timeCount === 1) {
        $timerLabel.html('Second');
      } else {
        $timerLabel.html('Seconds');
      }
      $timer.html(timeCount);
    }
  }, 1000);

  // Game has been started
  started = true;
};

// Clear the timer when game is reset
function resetTimer() {
  started = false;
  timeCount = 0;
  $timer.html(timeCount);

  clearInterval(timeCountVar);
};



///////////////////////////////////////
//  3c. Win
///////////////////////////////////////

// Modal dialog to announce that game has been won
function winGame() {

  // Pause the timer
  paused = true;

  // Reach for the stars
  let starCount = $('.fas.fa-star').length;

  // Announcement and option to reset
  vex.dialog.confirm({
    // message: 'You win with ' + (3 - $('.star').length) + ' or ' + starCount + ' stars',
    unsafeMessage: `<div class="text-center"><p>Way to go!</p>` +
      `<p>You just won the game with ${starCount}/3 star rating.</p>` +
      `<p>It took you ${timeCount} seconds to complete.</p>` +
      `<p>Would you like to play again?</p></div>`,
    callback: function (value) {
      if (value) {
        resetGame();
      }
    }
  });
};
              
            
!
999px

Console