console
var BRAINYMO = BRAINYMO || {};
BRAINYMO.Game = (function() {
var activeCards = [];
var numOfCards;
var cardHitCounter = 0;
var card;
var timer;
var storage;
function handleCardClick() {
var connection = $(this).data('connection');
var hit;
if ( !$(this).hasClass('active') ) {
$(this).addClass('active');
activeCards.push($(this));
if (activeCards.length == 2) {
hit = checkActiveCards(activeCards);
}
if (hit === true) {
cardHitCounter++;
activeCards[0].add(activeCards[1]).unbind().addClass('wobble cursor-default');
activeCards = [];
if(cardHitCounter === (numOfCards / 2)) {
activeCards = [];
cardHitCounter = 0;
endGame();
}
}
else if(activeCards.length === 3) {
for(var i = 0; i < activeCards.length - 1; i++) {
activeCards[i].removeClass('active');
}
activeCards.splice(0, 2);
}
}
}
function endGame() {
timer.stopTimer();
var time = timer.retrieveTime();
var timeFromStorage = storage.retrieveBestTime();
if (timeFromStorage != undefined && timeFromStorage != '') {
if (time.minutes < timeFromStorage.minutes || (time.minutes == timeFromStorage.minutes && time.seconds < timeFromStorage.seconds) ) {
storage.setBestTime(time);
}
}
else {
storage.setBestTime(time);
}
timer.updateBestTime();
}
function checkActiveCards(connections) {
return connections[0].data('connection') === connections[1].data('connection');
}
return function(config) {
this.startGame = function() {
card = new BRAINYMO.Card();
timer = new BRAINYMO.Timer();
storage = new BRAINYMO.Storage();
numOfCards = config.cards.length;
card.attachCardEvent(handleCardClick, config);
};
this.generateCardSet = function() {
card.generateCards(config.cards);
activeCards = [];
timer.stopTimer();
timer.startTimer();
};
this.startGame();
}
})();
BRAINYMO.Card = (function () {
var $cardsContainer = $('.cards-container');
var $cardTemplate = $('#card-template');
function prepareCardTemplate (card) {
var template = $cardTemplate
.clone()
.removeAttr('id')
.removeClass('hide')
.attr('data-connection', card.connectionID);
if (card.backImg != '' && card.backImg != undefined) {
template.find('.back').css({
'background': 'url(' + card.backImg + ') no-repeat center center',
'background-size': 'cover'
});
}
else if (card.backTxt != '' && card.backTxt != undefined) {
template.find('.back > label').html(card.backTxt);
}
return template;
}
function shuffleCards(cardsArray) {
var currentIndex = cardsArray.length, temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = cardsArray[currentIndex];
cardsArray[currentIndex] = cardsArray[randomIndex];
cardsArray[randomIndex] = temporaryValue;
}
return cardsArray;
}
return function() {
this.generateCards = function(cards) {
var templates = [];
var preparedTemplate;
cards.forEach(function (card) {
preparedTemplate = prepareCardTemplate(card);
templates.push(preparedTemplate);
});
templates = shuffleCards(templates);
$cardsContainer.hide().empty();
templates.forEach(function(card) {
$cardsContainer.append(card);
});
$cardsContainer.fadeIn('slow');
};
this.attachCardEvent = function(func) {
$cardsContainer.unbind().on('click', '.flip-container', function() {
func.call(this);
});
}
}
})();
BRAINYMO.Timer = (function() {
var $timer = $('.timer');
var $seconds = $timer.find('#seconds');
var $minutes = $timer.find('#minutes');
var $bestTimeContainer = $timer.find('.time');
var minutes, seconds;
function decorateNumber(value) {
return value > 9 ? value : '0' + value;
}
return function() {
var interval;
var storage = new BRAINYMO.Storage();
this.startTimer = function() {
var sec = 0;
var bestTime;
interval = setInterval( function() {
seconds = ++sec % 60;
minutes = parseInt(sec / 60, 10);
$seconds.html(decorateNumber(seconds));
$minutes.html(decorateNumber(minutes));
}, 1000);
$timer.delay(1000).fadeIn();
this.updateBestTime();
};
this.updateBestTime = function() {
bestTime = storage.retrieveBestTime();
if(bestTime != undefined && bestTime != '') {
$bestTimeContainer
.find('#bestTime')
.text(bestTime.minutes + ':' + bestTime.seconds)
.end()
.fadeIn();
}
};
this.stopTimer = function() {
clearInterval(interval);
};
this.retrieveTime = function() {
return {
minutes: decorateNumber(minutes),
seconds: decorateNumber(seconds)
}
};
}
})();
BRAINYMO.Storage = (function() {
return function() {
this.setBestTime = function(time) {
localStorage.setItem('bestTime', JSON.stringify(time));
};
this.retrieveBestTime = function() {
return JSON.parse(localStorage.getItem('bestTime'));
};
}
})();
$(function() {
var brainymo = new BRAINYMO.Game({
cards: [
{
backImg: 'https://s23.postimg.org/gmp35oru3/grunt.jpg',
connectionID: 1
},
{
backTxt: 'GRUNT',
connectionID: 1
},
{
backImg: 'https://s23.postimg.org/4q21yyfaj/react.jpg',
connectionID: 2
},
{
backTxt: 'REACT',
connectionID: 2
},
{
backImg: 'https://s23.postimg.org/raxfi9r6z/gsap.jpg',
connectionID: 3
},
{
backTxt: 'GSAP',
connectionID: 3
},
{
backImg: 'https://s23.postimg.org/bmrmxqm7f/ember.jpg',
connectionID: 4
},
{
backTxt: 'EMBER',
connectionID: 4
},
{
backImg: 'https://s23.postimg.org/o5cts28kr/karma.jpg',
connectionID: 5
},
{
backTxt: 'KARMA',
connectionID: 5
},
{
backImg: 'https://s23.postimg.org/ck2nkcn3f/webpack.jpg',
connectionID: 6
},
{
backTxt: 'WEBPACK',
connectionID: 6
},
{
backImg: 'https://s23.postimg.org/prxfzjv8r/angular.jpg',
connectionID: 7
},
{
backTxt: 'ANGULAR',
connectionID: 7
},
{
backImg: 'https://s23.postimg.org/oje5rnsob/mongo.jpg',
connectionID: 8
},
{
backTxt: 'MONGO DB',
connectionID: 8
},
]
});
$('#btn-start').click(function() {
brainymo.generateCardSet();
$(this).text('Restart');
});
});
<div class="align-center">
<h1 class="heading">Brainymo</h1>
<p class="desc">Frontend Arsenal Memory Game</p>
<button class="btn" id="btn-start">
Start
</button>
<div class="cards-container">
<div class="flip-container hide" id="card-template">
<div class="flipper">
<div class="front">
<label>frontend technologies</label>
</div>
<div class="back">
<label></label>
</div>
</div>
</div>
</div>
<div class="timer">
<label id="minutes"></label>:
<label id="seconds"></label>
<div class="time">
MY BEST TIME: <span id="bestTime"></span>
</div>
</div>
</div>
$white: #FFFFEA;
$red: #FF5E5B;
$blue: #00CECB;
$yellow: #FFED66;
$abel: 'Abel', sans-serif;
$lobster: 'Lobster', cursive;
$bgPattern: "https://www.transparenttextures.com/patterns/inspiration-geometry.png";
@mixin transform($transforms) {
-moz-transform: $transforms;
-o-transform: $transforms;
-ms-transform: $transforms;
-webkit-transform: $transforms;
transform: $transforms;
}
body {
background-color: $white;
background-image: url($bgPattern);
font-family: $abel;
color: $red;
}
.heading {
font-size: 52px;
font-family: $lobster;
color: $red;
margin-bottom: 0;
}
p.desc {
letter-spacing: 0.5px;
margin-top: 0;
margin-bottom: 60px;
}
.cards-container {
display: block;
margin: 40px;
}
.flip-container {
position: relative;
display: inline-block;
margin: 15px;
perspective: 1000px;
cursor: pointer;
.flipper {
position: relative;
-webkit-transform-style: preserve-3d;
-webkit-transition: 0.5s;
-moz-transform-style: preserve-3d;
-moz-transition: 0.5s;
-ms-transform-style: preserve-3d;
-ms-transition: 0.5s;
-o-transform-style: preserve-3d;
-o-transition: 0.5s;
}
&.active .flipper {
@include transform(rotateY(180deg));
}
}
.flip-container,
.front,
.back {
border-radius: 5px;
color: $white;
width: 180px;
height: 220px;
}
.front,
.back {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
.front {
background-color: $red;
z-index: 2;
@include transform(rotateY(0));
label {
cursor: pointer;
display: inline-block;
font-size: 22px;
padding-top: 15px;
}
}
.back {
background-color: $blue;
text-align: center;
vertical-align: middle;
display: table-cell;
@include transform(rotateY(180deg));
label {
display: block;
width: 100%;
font-size: 24px;
margin-top: 10px;
}
}
.timer {
display: none;
position: fixed;
pointer-events: none;
left: 30px;
top: 30px;
label#minutes,
label#seconds {
display: inline-block;
font-size: 20px;
}
.time {
display: none;
font-size: 13px;
}
}
.btn {
display: inline-block;
background-color: $yellow;
padding: 15px 40px;
border: none;
border-radius: 30px;
font-family: $abel;
font-size: 20px;
text-decoration: none;
text-transform: uppercase;
color: $red;
box-shadow: 0 3px 0 $red;
cursor: pointer;
transition: all 100ms linear;
&:hover {
@include transform(translateY(-4px));
box-shadow: 0 7px 0 $red;
}
&:focus { outline: 0; }
}
#github {
position: absolute;
top: 0;
right: 0;
border: 0;
}
.align-center {
text-align: center;
}
.hide {
display: none !important;
}
.cursor-default {
cursor: default !important;
}
@media screen and (max-width: 1200px) {
.flip-container, .front, .back {
width: 140px;
height: 180px;
}
.timer {
padding: 10px;
border-radius: 5px;
background-color: $white;
}
}
@media screen and (max-width: 992px) {
.flip-container, .front, .back {
width: 100px;
height: 140px;
}
.front label {
display: inline-block;
font-size: 16px;
padding-top: 10px;
}
.cards-container {
margin: 40px 10px;
}
.timer {
top: 10px;
left: 10px;
}
}
@media screen and (max-width: 768px) {
.flip-container, .front, .back {
width: 80px;
height: 120px;
}
}
@keyframes wobble {
from { transform: none; }
15% { transform: translate3d(-10%, 0, 0) rotate3d(0, 0, 1, -5deg); }
30% { transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 3deg); }
45% { transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -3deg); }
60% { transform: translate3d(5%, 0, 0) rotate3d(0, 0, 1, 2deg); }
75% { transform: translate3d(-10%, 0, 0) rotate3d(0, 0, 1, -1deg); }
to { transform: none; }
}
.wobble {
animation: wobble 600ms ease-in-out;
}