0

Here is my JSbin: https://jsbin.com/wacefor/

Background: Card matching game that counts time and moves.

Code Context

  • jQuery 2.2.2

Problem: How to disable the .click event when mouse is pressed multiple times on same card/square/block? Then when user clicks on same block/square/card later it should register again as a click? At the moment when user clicks multiple times on one card/square/block a win is counted after 8 clicks which it should not do.

Attempts:

  • .die()
  • .unbind()
  • .one()
  • .prop()

Closest I got was to .unbind() the addCardListener, but then it does not load the finish screen when all cards are matched. I did the following look at <\MY ATTEMPT>:


/** * @description Open card: Comparison * @param {.open} - Second click occurs * @returns {open show} - If the card has same value as in the index then card stays open. If the value is not the same as in index card closes */ if (opened.length > 1) { if (card === opened[0]) { $deck.find('.open').addClass('match'); setTimeout(function() { $deck.find('.match').removeClass('open show'); }, delay)<MY ATTEMPT>.unbind('click', addCardListener);<MY ATTEMPT> match++;


So I unbind it completely, then tried to bind no luck. I believe the solution is simple. But I fail to see it...

/** 
* Create a list to store the cards that will be used in the game. 
*The list we use is an array of text that will be used in pairs. The reason we use pairs is so that we can pair the elements to create a match. 
*/

/**  Below we will create global variables. 
*/
var symbols = ['bus', 'bus', 'bell', 'bell', 'bug', 'bug', 'child', 'child', 'flag', 'flag', 'magnet', 'magnet', 'heart', 'heart', 'rocket', 'rocket'], 
  opened = [],
  match = 0,
  moves = 0,
  $deck = jQuery('.deck'),
  $scorePanel = $('#score-panel'),
  $moveNum = $('.moves'),
  $ratingThumbs = $('i'),
  $restart = $('.restart'),
  delay = 800,
  gameCardsQTY = symbols.length / 2,
  rank3thumbs = gameCardsQTY + 2,
  rank2thumbs = gameCardsQTY + 6,
  rank1thumbs = gameCardsQTY + 10;
  var c = 0;
  var t;
  var timer_is_on = 0;


/**
* @description Timer countdown of 60 sec
* @param [.click]  - ArrOn click of timer countdown begin
* @returns [startGame] When countdown rech 0 restart game screen appears
*/
/*$("#count").click( function(){
   var counter = 120;
   setInterval(function() {
     counter--;
      if (counter >= 0) {
         span = document.getElementById("count");
         span.innerHTML = counter;
      }
      if (counter === 0) {
        swal({
  title: 'Out of Time!',
  confirmButtonColor: '#02ccba',
  confirmButtonText: 'Need another brain-try!'
  }).then(function(isConfirm) {
      if (isConfirm) {
            startGame();
         }
       });
       }
     }, 50);
});*/


/**
* @description Timer counts up
* @param [.click]  - On click of timer countdown begin
* @returns [startGame] Countdown will continue untill player wins
*/
function timedCount() {
    document.getElementById("count").value = c;
    c = c + 1;
    t = setTimeout(function(){ timedCount() }, 1000);
}

function startCount() {
    if (!timer_is_on) {
        timer_is_on = 1;
        timedCount();
    }
}

function resetCount() {
        stopCount();
        c = 0;
        startCount();
}

function stopCount() {
    clearTimeout(t);
    timer_is_on = 0;
}

/**
* @description Card shuffle Here the cards are shuffled according to this setup and code http://stackoverflow.com/a/2450976
* @param [array]  - Array is parsed
* @returns [array] Array values are shuffled 
*/
function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;
  while (0 !== currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}


/**
* @description Game setup: Cards are placed inside the grid.
* @param {array}  - Shuffled values are parsed into grid
* @returns {array} - Cards are generated on the grid blank side up
*/
function startGame() {
  var cards = shuffle(symbols);
  $deck.empty();
  match = 0;
  moves = 0;
  $moveNum.text('0');
  $ratingThumbs.removeClass('fa-thumbs-up-o').addClass('fa-spinner');
 for (var i = 0; i < cards.length; i++) {
  $deck.append($('<li class="card"><i class="fa fa-' + cards[i] + '"></i></li>'))
 }
 addCardListener();
}


/**
* @description Game thumb rating and score: you will see your thumb rating and score
* @param {array}  - Full thumbs are calculated
* @returns {array} - Three thumbs are displayed and the score is 0
*/
function setRating(moves) {
 var rating = 3;
 if (moves > rank3thumbs && moves < rank2thumbs) {
  $ratingThumbs.eq(2).removeClass('fa-thumbs-up').addClass('fa-thumbs-up-o');
  rating = 2;
 } else if (moves > rank2thumbs && moves < rank1thumbs) {
  $ratingThumbs.eq(1).removeClass('fa-thumbs-up').addClass('fa-thumbs-up-o');
  rating = 1;
 }
 return { score: rating };
}


/**
* @description Game Completion: Moves are displayed and score
* @param {string}  - Moves are read in and score from setRatings()
* @returns {string}  - Text is called from the object then a popup displays a screen with an option to cancel or confirm
*/
function endGame(moves, score) {
 swal({
  allowEscapeKey: false,
  allowOutsideClick: false,
  title: 'Congratulations! You Won!',
  text: 'With ' + moves + ' Moves and ' + score + ' Thumbs.\n Great man!' + ' Total time : ' + c,
  type: 'great',
  showCancelButton: false,
  confirmButtonColor: '#02ccba',
  confirmButtonText: 'Need another brain-try!'
 }).then(function(isConfirm) {
  if (isConfirm) {
   startGame();
  }
 })
}

/**
* @description Refresh your game: Press refresh to start all over and resest deck to orginal state
* @param {.click}  - User clicks restart to reshuffle grid
* @returns {startgame()} - User gets notified in popup to accept refresh or not
*/
$restart.bind('click', function() {
  swal({
    allowEscapeKey: false,
    allowOutsideClick: false,
    title: 'But why?',
    text: "All your achievement lost with one click!",
    showCancelButton: true,
    confirmButtonColor: '#0e2c98',
    cancelButtonColor: '#1f2323',
    confirmButtonText: 'Yes, let me hav\'em!'
  }).then(function(isConfirm) {
    if (isConfirm) {
      startGame();
    }
  })
});


/**
* @description Listen to the screen: Here all events that is activated by a click is logged as user events
* @param {addCardListener}  - Grid waits for clicks. Any click is logged and compared to what was clicked
* @returns {startgame()} - User clicks are compared in pairs to check if a card match. If card match then cards stay open. If it does not match cards return to previous sate and game continues.
*/
var addCardListener = function() {


/**
* @description Flipping the card: Cards turns around
* @param {click}  - User clicks in grid
* @returns {open show} - Card is turned around and kept open.
*/
$deck.find('.card:not(".match, .open")').on('click', function() {
 if($('.show').length > 1) { return true; }

 var $this = $(this),
 card = $this.context.innerHTML;
   $this.addClass('open show');
 opened.push(card);

    /**
 * @description Open card: Comparison
 * @param {.open}  - Second click occurs
 * @returns {open show} - If the card has same value as in the index then card stays open. If the value is not the same as in index card closes
 */
  if (opened.length > 1) {
     if (card === opened[0]) {
        $deck.find('.open').addClass('match');
           setTimeout(function() {
         $deck.find('.match').removeClass('open show');
       }, delay);
       match++;
    } else {
     $deck.find('.open').addClass('notmatch');
   setTimeout(function() {
   $deck.find('.open');
   }, delay);
            setTimeout(function() {
            $deck.find('.open').removeClass('open show notmatch');
      }, delay);
    }
    opened = [];
       moves++;
    setRating(moves);
       $moveNum.html(moves);
   }


 /**
 * @description Game ending: It all ends the game
 * @param {score}  - Game score and thumbs are calculated and checked.
 * @returns {moves, score} - Game scores are displayed and status of thumbs if moves were not over the 19 count threshold is displayed
 */
 if (gameCardsQTY === match) {
  setRating(moves);
  var score = setRating(moves).score;
  setTimeout(function() {
   endGame(moves, score);
  }, 200);
  }
});
};

startGame();
@import url('https://fonts.googleapis.com/css?family=Istok+Web|Libre+Barcode+39+Text|Zilla+Slab+Highlight');



html,
body {
  width: 100%;
  color: #2e3d49;
}

body {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-box-align: center;
  -ms-flex-align: center;
   align-items: center;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
  background: #FFF;
  overflow: hidden;
  font-family: 'Istok', cursive;
}

h1 {
  font-family: 'Istok', cursive;
  font-weight: 400;
}

.deck {
  width: 500px;
  margin: 2% auto;
  background: #010223; 
  padding: 10px;
  box-shadow: 12px 15px 20px 0px rgba(46, 61, 73, 0.5);
}

.deck .card {
  height: 100px;
  width: 100px;
  background: #bd1414;
  display: inline-block;
  margin: 0 10px 10px 0px;
  line-height: 100px;
  font-size: 20px;
  color: #000000;
  text-align: center;

}
.deck .card:nth-child(4n) {
  margin: 0 0 10px 0;
}

.deck .card:nth-child(n+13) {
  margin: 0 10px 0 0;
}

.deck .card:nth-child(n+13):nth-child(4n) {
  margin: 0;
}

.deck .card.open {
  -webkit-transform: rotateY(0);
          transform: rotateY(0);
  background: #dedede;
  cursor: default;
}

.deck .card.show {
  font-size: 33px;
}

.deck .card.match {
  -webkit-transform: rotateY(0);
          transform: rotateY(0);
  cursor: default;
  background: #dedede;
  font-size: 33px;
}

.deck .card.notmatch {
  background: #abb516;
}

#score-panel {
  text-align: left;
  width: 345px;
  margin-bottom: 10px;
}

#score-panel .thumbs {
  margin: 0;
  padding: 0;
  display: inline-block;
  margin: 0 5px 0 0;
}

#score-panel .thumbs li {
  list-style: none;
  display: inline-block;
}
#score-panel .restart {
  padding-left: 200px;
  cursor: pointer;
  font-size: 20px; 
}

*::-moz-selection {
  background: transparent;
}

*::selection {
  background: transparent;
}

.swal2-overlay {
  background-color: white;
  width: 80%
}

.font-color {
  color: white;
}

#count {
  padding-left: 20%;
  display: block;
}


.swal2-input, 
.swal2-select, 
.swal2-radio, 
.swal2-checkbox, 
.swal2-textarea {
  display: none;
}
<!DOCTYPE html>
<html >
 <head>
  <meta charset="UTF-8">
  <title>Simple Matching Game</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css"/>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/sweetalert2/3.0.3/sweetalert2.min.css"/>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.css"/>
  <link rel="stylesheet" href="css/style.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/css/bootstrap.min.css" />
 </head>
 <body>
  <div class="responsive-container">
   <h1>Matching Game</h1>
   <!-- <span id="count">120 seconds <a href="#" id="startclock">Start your countdown</a></span> -->
   <button type="button" class="btn btn-primary" onmouseenter="startCount()">Start counter!</button>
   <input type="text" class="form-control" id="count" disabled>
   <button type="button" class="btn btn-success" onclick="stopCount()">Pause counter</button>
   <button type="button" class="btn btn-warning" onclick="resetCount()">Reset counter</button>
   <div class="row">
    <div class=" md-col-6" id="score-panel">
     <ul class="thumbs">
      <li><i class="fa fa-thumbs-up">&nbsp; </i></li>
      <li><i class="fa fa-thumbs-up">&nbsp; </i></li>
      <li><i class="fa fa-thumbs-up">&nbsp; </i></li>
     </ul>
     <span class="moves">0</span> Moves
    </div>
    <div class="md-col-6" id="score-panel">
     <div class="restart" onclick="resetCount()">Restart &nbsp;
      <i class="fa fa-repeat"></i>
     </div>
    </div>
   </div>
  <ul onmouseenter="startCount()" class="deck"></ul>
 </div>
 <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js'></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/js/bootstrap.min.js"></script>
 <script src='https://cdn.jsdelivr.net/sweetalert2/3.0.3/sweetalert2.min.js'></script>
 <script src="js/index.js"></script>
</body>
</html>
  • In a nutshell, add a class when clicking a card, check for that class when clicking to see if it's the first time it's clicked. Then just remove that class on all other cards when a card is clicked, and voila. – adeneo Sep 25 '17 at 23:18
  • @adeneo, thanks helped me in sorting the classes. I used the .data() element to solve the issue. – gen-ass Sep 26 '17 at 08:10
  • @adeneo, so I discovered the bug is not gone after editing it, do you have any other suggestions? – gen-ass Sep 26 '17 at 17:58

0 Answers0