Juego de Memoria

  • por

Introducción

El juego de memoria es un juego de niños común que se juega con una baraja de cartas. Las cartas tienen imágenes en uno de los lados y cada imagen aparece en dos (o a veces cuatro) cartas.

El juego comienza con todas las cartas boca abajo y los jugadores se turnan para dar la vuelta a dos cartas. Si las dos cartas tienen la misma imagen, se quedan con las cartas sino se vuelven a poner las cartas boca abajo.

El ganador es la persona con más cartas una vez no quedan cartas boca abajo en el caso de multijugador, en el caso de jugar contra la maquina se puede tener en cuenta el tiempo o el número de veces que has necesitado voltear cartas para completar el juego.

Las normas

La baraja consta de n tipos de cartas diferentes (ya sea n pares de cartas o n conjuntos de 4 cartas).

Cada turno, le das la vuelta a dos cartas (una a la vez, para que puedas ver la primera antes de elegir la segunda).

Si las dos cartas coinciden, se eliminan del juego sino se devuelven a la mesa.

El juego termina cuando se retiran todas las cartas.

Aquí el código

<!DOCTYPE html>
<html lang='en' class=''>
<head>
    <meta charset='UTF-8'>
    <title>Memory Cards</title>
    <link rel="stylesheet" href="https://netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
    <link rel="stylesheet" href="dist/default.css">
</head>
<body>
  
<div id="app">
  <div class="info">
    <div><span class="label">Time:</span><span class="value">{{ time }} </span></div>
    <div><span class="label">Turns:</span><span class="value">{{ turns }} </span></div>
  </div>
  <div class="cards">
    <div class="card" v-for="card in cards" :class="{ flipped: card.flipped, found: card.found }" @click="flipCard(card)">
      <div class="back"></div>
      <div class="front" :style="{ backgroundImage: 'url(' + card.image + ')' }"></div>
    </div>
  </div>
  <div class="splash" v-if="showSplash">
    <div class="overlay"></div>
    <div class="content">
      <div class="title">You won!</div>
      <div class="score">Score: {{ score }}</div>
      <button class="newGame" @click="resetGame()">New game</button>
    </div>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js"></script>
<script src="dist/script.js"></script>

</body>

</html>

dist/default.css

@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,900|Dosis:300,400,600,700,800|Droid+Sans:400,700|Lato:300,400,700,900|PT+Sans:400,700|Ubuntu:300,400,500,700|Open+Sans:400,300,600,700|Roboto:400,300,500,700,900|Roboto+Condensed:400,300,700|Open+Sans+Condensed:300,700|Work+Sans:400,300,700|Play:400,700|Maven+Pro:400,500,700,900&subset=latin,latin-ext);
* {
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}

html {
  background-color: #292C33;
  color: White;
  font-size: 16px;
  font-family: 'Open Sans', 'Helvetica', 'Arial', sans-serif;
  font-weight: 400;
  font-smoothing: antialiased;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#app {
  margin: 2em;
}

.info {
  text-align: center;
  padding-bottom: 1em;
  border-bottom: 1px solid #555;
}
.info > div {
  display: inline-block;
  width: 200px;
}
.info > div .label {
  margin-right: 5px;
}
.info > div .value {
  font-weight: bold;
}

.cards .card {
  position: relative;
  display: inline-block;
  width: 150px;
  height: 225px;
  margin: 1em 2em;
  -moz-transition: opacity 0.5s;
  -o-transition: opacity 0.5s;
  -webkit-transition: opacity 0.5s;
  transition: opacity 0.5s;
}
.cards .card .front, .cards .card .back {
  border-radius: 5px;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  background-color: White;
  -moz-backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  -moz-transform: translateZ(0);
  -ms-transform: translateZ(0);
  -webkit-transform: translateZ(0);
  transform: translateZ(0);
  -moz-transition: -moz-transform 0.6s;
  -o-transition: -o-transform 0.6s;
  -webkit-transition: -webkit-transform 0.6s;
  transition: transform 0.6s;
  -moz-transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
}
.cards .card .back {
  background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/102308/card_backside.jpg");
  background-size: 90%;
  background-position: center;
  background-repeat: no-repeat;
  font-size: 12px;
}
.cards .card .front {
  -moz-transform: rotateY(-180deg);
  -ms-transform: rotateY(-180deg);
  -webkit-transform: rotateY(-180deg);
  transform: rotateY(-180deg);
  background-size: 90%;
  background-repeat: no-repeat;
  background-position: center;
}
.cards .card.flipped .back, .cards .card.found .back {
  -moz-transform: rotateY(180deg);
  -ms-transform: rotateY(180deg);
  -webkit-transform: rotateY(180deg);
  transform: rotateY(180deg);
}
.cards .card.flipped .front, .cards .card.found .front {
  -moz-transform: rotateY(0deg);
  -ms-transform: rotateY(0deg);
  -webkit-transform: rotateY(0deg);
  transform: rotateY(0deg);
}
.cards .card.found {
  opacity: 0.3;
}

.splash {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}
.splash .overlay {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.6);
}
.splash .content {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  width: 400px;
  height: 200px;
  margin: auto;
  text-align: center;
  background-color: rgba(51, 51, 51, 0.9);
  -moz-border-radius: 10px;
  -webkit-border-radius: 10px;
  border-radius: 10px;
  -moz-box-shadow: 5px 5px 20px rgba(0, 0, 0, 0.8);
  -webkit-box-shadow: 5px 5px 20px rgba(0, 0, 0, 0.8);
  box-shadow: 5px 5px 20px rgba(0, 0, 0, 0.8);
  padding: 1em;
}
.splash .content .title {
  font-size: 1.8em;
  padding: 0.5em;
}
.splash .content .score {
  padding: 0.5em;
}
.splash .content button {
  margin-top: 1.0em;
  background-color: #444;
  padding: 5px 20px;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
  border-radius: 4px;
  border: 1px solid #555;
  color: White;
  font-size: 1.4em;
}

dist/script.js

let CardTypes = [
  { name: "pato", image: "https://www.dibujofacildecolorear.com/wp-content/uploads/2020/07/pato-de-pocoyo-para-colorear-912x1024.jpg" },
  { name: "eli", image: "https://www.dibujofacildecolorear.com/wp-content/uploads/2020/07/eli-pocoy%C3%B3-para-colorear-912x1024.jpg" },
  { name: "lula", image: "https://www.dibujofacildecolorear.com/wp-content/uploads/2020/07/pajaroto-pocoy%C3%B3-para-colorear-912x1024.jpg" },
  { name: "pocoyo", image: "https://www.dibujofacildecolorear.com/wp-content/uploads/2020/07/Pocoy%C3%B3-para-colorear-1-912x1024.jpg" },
  { name: "valentina", image: "https://www.dibujofacildecolorear.com/wp-content/uploads/2020/07/Valentina-pocoy%C3%B3-para-colorear-912x1024.jpg" },
  { name: "pulpo", image: "https://www.dibujofacildecolorear.com/wp-content/uploads/2020/07/pulpo-de-pocoyo-para-colorear-912x1024.jpg" },
  { name: "nina", image: "https://www.dibujofacildecolorear.com/wp-content/uploads/2020/07/Nina-de-pocoyo-para-colorear-912x1024.jpg" },
  { name: "todos", image: "https://www.dibujofacildecolorear.com/wp-content/uploads/2020/07/dibujo-de-pocoyo-y-sus-amigos-para-colorear-912x1024.jpg" }
];

let shuffleCards = () => {
  let cards = [].concat(_.cloneDeep(CardTypes), _.cloneDeep(CardTypes));
  return _.shuffle(cards);
}

let shuffleCard = () => {	
	let c = CardTypes;
  return _.shuffle(c);
 }
 
new Vue({
  el: "#app",
  
  data: {
    showSplash: false,
    cards: [],
    started: false,
    startTime: 0,
    turns: 0,
    cardsshow: 4,
    flipBackTimer: null,
    timer: null,
    time: "--:--",
    score: 0
  },
  
  methods: {
    resetGame() {
      this.showSplash = false;
      CardTypes = shuffleCard();
      CardTypes = CardTypes.splice(0,this.cardsshow);
      let cards = shuffleCards()	
      console.warn(cards)
      this.turns = 0;
      this.score = 0;
      this.started = false;
      this.startTime = 0;
      
      _.each(cards, (card) => {
        card.flipped = false;
        card.found = false;
      });
      
      this.cards = cards;
    },
    
    flippedCards() {
      return _.filter(this.cards, card => card.flipped);
    },
    
    sameFlippedCard() {
      let flippedCards = this.flippedCards();
      if (flippedCards.length == 2) {
        if (flippedCards[0].name == flippedCards[1].name)
          return true;
      }
    },
    
    setCardFounds() {
      _.each(this.cards, (card) => {
        if (card.flipped)
          card.found = true;
      });
    },
    
    checkAllFound() {
      let foundCards = _.filter(this.cards, card => card.found);
      if (foundCards.length == this.cards.length)
        return true;
    },
    
    startGame() {
      this.started = true;
      this.startTime = moment();
      
      this.timer = setInterval(() => {
        this.time = moment(moment().diff(this.startTime)).format("mm:ss");
      }, 1000);
    },
    
    finishGame() {
      this.started = false;
      clearInterval(this.timer);
      let score = 1000 - (moment().diff(this.startTime, 'seconds') - CardTypes.length * 5) * 3 - (this.turns - CardTypes.length) * 5;
      this.score = Math.max(score, 0);
      this.showSplash = true;
    },
    
    flipCard(card) {
      if (card.found || card.flipped) return;
      
      if (!this.started) {
        this.startGame();
      }
      
      let flipCount = this.flippedCards().length;
      if (flipCount == 0) {
        card.flipped = !card.flipped;
      }
      else if (flipCount == 1) {
        card.flipped = !card.flipped;
        this.turns += 1;

        if (this.sameFlippedCard()) {
          // Match!
          this.flipBackTimer = setTimeout( ()=> {
            this.clearFlipBackTimer();
            this.setCardFounds();
            this.clearFlips();

            if (this.checkAllFound()) {
              this.finishGame();
            } 

          }, 200);
        }
        else {
          // Wrong match
          this.flipBackTimer = setTimeout( ()=> {
            this.clearFlipBackTimer();
            this.clearFlips();
          }, 1000);
        }
      }
    },
    
    clearFlips() {
      _.map(this.cards, card => card.flipped = false);
    },
    
    
    clearFlipBackTimer() {
      clearTimeout(this.flipBackTimer);
      this.flipBackTimer = null;
    }
  },
  
  created() {
    this.resetGame();
  }
});  

Enlace al juego

http://www.lmcdevloper.es/recursos/vuejs/MemoryGame/index.html

Enlace al código GITHUB

https://github.com/lmcDevloper/memory-cards