Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I updated my code according to a few suggestions from my last post, so I thought I'd repost it to see what other feedback I could get. I also commented it heavily and fixed some of the functionality.

One question I do have is what is the difference between defining a function by doing

var funcName = function(){};

rather than

function funcName() {};

Which one is better or is neither better and it's just a convention to do one over the other?

You can check out the game at mattgowie.com/project-2/. And here is the source:

    // Author: Matt Gowie
// Created on: 10/01/12
// Project for Web Dev 2400
$(document).ready(function(){
  "use strict";
  var numberOfPairs   = 30;
  var cardsToFlip     = [];
  var prevCardClasses = [];
  var matches         = 0;
  var score           = 0;
  var multiplier      = 10;
  var that            = this;
  var $board = $('.board'), $winMessage = $('.win-message');

  // Check if the player won the game by matching all of the card pairs
  var checkForWin = function() {
    // Are there no more cards on the board? 
    if($('.card-container').length === 0) {
      // Then the player must have won! Hide the board and show the win message
      $board.hide();
      $winMessage.show();
    }
  };

  $('.win-message a').click(function() { 
    // How are the previous cards being reset here?
    $('.matches').html('0');
    $('.score').html('0');
    $('.mult').html('10X');
    matches    = 0;
    score      = 0;
    multiplier = 10;
    buildGameBoard(); 
  });

  // Build a deck of cards
  //
  // numberOfPairs - integer for how many pairs we need, and is 
  //   currently restricted to <= 30
  //
  // Returns an array of pairs of integers. ex: [1, 1, 2, 2, 3, 3, ... ]
  function buildDeck(numberOfPairs) {
    var deck = [];
    for(var i = 0; i < numberOfPairs; i++){
      deck.push(i,i);
    }
    return deck;
  };

  // Shuffle the given ordered deck
  // deck - An ordered array of pairs of integers
  // Returns an array of pairs of integers which are no longer ordered
  function shuffleDeck(deck) {
    var rand, shuffled = [];
    // Randomly access each pair in the given deck and add it to the resulting
    // shuffled deck
    while(deck.length > 0){
      rand = Math.random() * deck.length;
      shuffled.push(deck.splice(rand, 1)[0]);
    }
    return shuffled;
  };

  // Build the cards for the given deck and append them to the board
  // deck - a shuffled deck 
  // Returns void
  function buildCards(deck) {
    var row = 1, col = 1;
    // Loop through each card in the deck, initializing it with it's relevent info
    for( var i = 1; i <= deck.length ; i++ ) {
      buildCard(deck[i - 1], row, col, i);
      col += 1;
      // Increment the row and reset the cols for every 10 cards
      if(i % 10 === 0) { row += 1; col = 1; }
    }
  };

  // Build the html for a card and append it to the board
  // cardClass - integer which corresponds to a specific card in the deck
  // row       - integer corresponding to this cards row number
  // col       - integer corresponding to this cards col number
  // id        - integer for identifing the card for click events
  // Returns void
  function buildCard(cardClass, row, col, id) {
    var $card = $('<div class="card back"></div>');
    var $container = $('<div class="container">');
    var $cardContainer = $('<div class="card-container">');

    // Associate this card with the given class, so we know what it is when flipped
    $card.data('cardClass', 'card' + cardClass);
    if(cardClass === 's-ace'){ $card.addClass('debug'); } // For debugging!

    // Associate the cards container with the current side of the card, which
    // when the game starts is always on its back
    $cardContainer.data('cardSide', 'back');

    // Add the id, row, and col to the card container for positioning and 
    // card identification when clicking
    $container.attr('id', "card" + id).addClass("row" + row).addClass("col" + col); 

    // Put the card and containers inside one another, and then append them to the board
    $container.html($cardContainer.html($card));
    $board.append($container);
  }

  // Reset and build the game board by creating a deck, shuffling, and dealing
  function buildGameBoard() {
    // Reset the GameBoard area
    $winMessage.hide();
    $board.show().html('');

    // Initialize a new deck, shuffle, and deal.
    var deck = buildDeck(numberOfPairs);
    deck = shuffleDeck(deck);
    buildCards(deck);

    // Bind the click function for every card on the new board
    $('.container').click(function() { clickCard(this); });
  };
  buildGameBoard();

  // Flip the clicked card and if > 1 card is flip check for a match
  // container - the container of the card that was clicked
  var clickCard = function(container) {
    var cardId = $(container).attr('id');

    // Do we currently have two cards flipped? Which implies we are checking for a match
    if(cardsToFlip.length < 2) { 

      // Flip the card if we don't have two cards flipped and the card clicked 
      //   is not the same card that is already flipped
      if(cardsToFlip.length <= 1 && cardsToFlip[0] !== cardId){
        cardsToFlip.push(cardId);
        flipCard(container);
      }

      // If there are two cards flipped over check for a match 
      if(cardsToFlip.length === 2){ 
        // checkMatch is delayed 2 seconds to allow player to look at cards
        setTimeout(function(){ checkMatch(); }, 2000);
      }
    }
  }

  function incrementScoreBoard() {
    matches += 1;
    $('.matches').html(matches);
    score += 10 * multiplier;
    $('.score').html(score);
    $('.mult').html('10X');
    multiplier = 10;
  }

  // Check to see if the two cards which are flipped over are a match
  var checkMatch = function() {
    console.log('checkMatch called!');
    var cardOneClass = $('#' + cardsToFlip[0]).find('.card').data('cardClass');
    var cardTwoClass = $('#' + cardsToFlip[1]).find('.card').data('cardClass');

    if(cardOneClass === cardTwoClass){  // Do these cards match?
      // Clear the cards from the board, increment the score board, and
      //   check to see if the user won. 
      $(cardsToFlip).each(function(i, e){ $("#" + e).html(''); });
      incrementScoreBoard();
      checkForWin();
    } else {
      // No match so lower the multiplyer
      if(multiplier !== 1){ multiplier -= 1; } 
      $('.mult').html(multiplier + 'X');
      // Flip the cards onto their back side
      $(cardsToFlip).each(function(i, e){ flipCard($("#" + e)); });
    }

    // Add the cards which were just flipped to the previous card area
    $('.prev-card1').attr('class', 'card back prev-card1 ' + prevCardClasses[0]);
    $('.prev-card2').attr('class', 'card back prev-card2 ' + prevCardClasses[1]);
    prevCardClasses = [];
    cardsToFlip = [];
  };

  // Flip the card container in the given container. 
  var flipCard = function(container) {
    var classToRemove, classToAdd, flipDir;
    var $cardContainer = $(container).children('.card-container');
    var $card = $cardContainer.children('.card');
    var cardSide = $cardContainer.data('cardSide');
    var cardClass = $card.data('cardClass');

    if(cardSide === 'back'){ // Is this card face down?
      classToRemove = 'back';
      classToAdd = cardClass;
      flipDir = 'rl';
      $cardContainer.data('cardSide', 'front');
    } else { // This card is face up.
      classToRemove = 'front ' + cardClass;
      classToAdd = 'back';
      flipDir = 'lr';
      $cardContainer.data('cardSide', 'back');
      prevCardClasses.push(cardClass);
    }

    // Use jquery.flip plugin to flip the card up or down depending on vars
    //   set previously 
    $card.css("background-color", "#AB0000" );
    $card.flip({
      direction: flipDir,
      onBefore: function() {
        $card.removeClass(classToRemove).addClass(classToAdd);
      },
      onEnd: function() {
        $card.css({ 'background-color': 'rgba(0, 0, 0, 0.0)' });
      },
      speed: '200',
      color: '#AB0000'
    });
  };

});

Thanks for the help! It's much appreciated!

share|improve this question
5  
You can look at this post to see the [difference between a function expression vs declaration in Javascript][1] [1]: stackoverflow.com/questions/1013385/… – Kinjal Oct 15 '12 at 1:10
1  
Pretty nice update. Perhaps the checkMatch function is still doing a little too much (i.e. not just checking for a match, but also calculating the multiplier, flipping cards, updating the prev-cards stuff). That's the kind of stuff that could be broken into separate functions. But I'll let someone else take a closer look this time :) – Flambino Oct 15 '12 at 10:25

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.