0

I have a memory game. When you get 2 colors correct the boxes go black. At the end when you get all of them correct the boxes all should be black. My issue is I need some way to mix up the colors on refresh and haven't a clue how to do this. Code and JS fiddle below https://jsfiddle.net/zdxm9s5u/ Sorry for the French. As paulsm4 said, I need to implement Knuth Shuffle but am unsure how to do that with this code

var card1 = [];
var combos = 0;
// fonction pour cliquer sur les cartes, pour verifier si on a trouver une pair ou non en utilisant des condtions if

function onCardClicked(e) {
  const target = e.currentTarget;
  console.log(target.className.split(" "));
  target.className = target.className
    .replace('colour-hidden', '')
    .trim();

  card1.push(e.target);
  // verifie quil y a 2 cartes quon a cliquer dessus
  if (card1.length === 2) {
    // verifie si les deux cartes sont la meme couleur en verifiant la couleur dans la classname en utilisant une split pour verifier le 2ieme mot qui indentifie la coloueur
    if (card1[0].className.split(" ")[1] === card1[1].className.split(" ")[1]) {
      // si les deux couleurs sont la meme on ajoute +1 au combos
      combos++;
      //  mets un timeout avant que les cartes devient noir lorsquon trouve une pair
      setTimeout(() => {

        console.log(card1);
        card1[0].className += (" match-found");
        card1[1].className += (" match-found");
        //  vide le array pour quon peut choisir 2 nouvelles cartes
        card1 = [];

        //  verfie si combos est agele a 8 por voir si tu as gagner

        if (combos == 8) {
          //  sort element pour annoncer que tu a gagner par utilisant le class .gagne
          document.getElementById("win").style.display = "block";
        }
      }, 200);

      // le else pour quand les cartes sont pas la meme couleur et retourne la meme couleur quavant avec le meme timeout
    } else {
      setTimeout(() => {
        card1[0].className += (" colour-hidden");
        card1[1].className += (" colour-hidden");
        console.log("not a match");
        card1 = [];
      }, 200);
    }

  }



}
.row {
  text-align: center;
}

.card {
  display: inline-block;
  width: 150px;
  height: 150px;
  background-color: aliceblue;
  cursor: pointer;
}

.card.done {
  cursor: default;
}

.card.done:hover {
  cursor: default;
  box-shadow: none;
}

.card:hover {
  box-shadow: inset 0px 0px 0px 1px red;
  box-sizing: border-box;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}

.pink {
  background-color: magenta;
}

.cyan {
  background-color: cyan;
}

.green {
  background-color: green;
}

.purple {
  background-color: purple;
}

.orange {
  background-color: orange;
}

.yellow {
  background-color: yellow;
}

.colour-hidden {
  background-color: papayawhip;
}

.match-found {
  background-color: black;
}

.gagne {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: rgba( 0, 0, 0, 0.7);
  color: white;
  top: 0;
  left: 0;
  font-size: 50px;
  text-align: center;
  padding-top: 40%;
  display: none;
}
<div class="row">
  <div data-coulour="red" class="card red colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="orange" class="card orange colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="blue" class="card blue colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="pink" class="card pink colour-hidden" onclick="onCardClicked(event)"></div>

</div>

<div class="row">

  <div data-coulour="red" class="card red colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="cyan" class="card cyan colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="green" class="card green colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="pink" class="card pink colour-hidden" onclick="onCardClicked(event)"></div>

</div>

<div class="row">

  <div data-coulour="cyan" class="card cyan colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="orange" class="card orange colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="yellow" class="card yellow colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="blue" class="card blue colour-hidden" onclick="onCardClicked(event)"></div>

</div>

<div class="row">

  <div data-coulour="purple" class="card purple colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="purple" class="card purple colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="yellow" class="card yellow colour-hidden" onclick="onCardClicked(event)"></div>
  <div data-coulour="green" class="card green colour-hidden" onclick="onCardClicked(event)"></div>

</div>

<div class="gagne" id="win">TU AS GAGNE!!</div>
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
  • If I'm understanding your question correctly, it sounds like you want to "shuffle" some "collection" of "objects". Here's a good example: https://stackoverflow.com/a/2450976/421195 – paulsm4 Jun 09 '21 at 22:49
  • Like this! How would I got about implementing this into my current code. – Mathew Gregory Harrison Jun 09 '21 at 22:50
  • You could simply have an array that contained the colour of each block. When setting up the board, you could tell each block what the index is of its colour. Clicking the box would cause the index to be retrieved before being used as an offset into the array. It would then be entirely trivial to sort the array between games. I'd try card-shuffling. At each position of the array, swap the current element for one chosen at random. – enhzflep Jun 10 '21 at 00:22

2 Answers2

3

Shuffling the elements themselves would be too much work and extremely inefficient. Easy ways like shuffling the cards in each row, then shuffling the rows wouldn't actually be random. Harder ways like summing the cards into an array, shuffling, then re-appending are too resource-intensive.

Instead, declare an array of colors, loop through all cards, and use the Fisher-Yates (aka Knuth) Shuffle (from this answer) to shuffle the array and add the class to the element currently being looped through.

function shuffle(array) {
  var currentIndex = array.length,
    randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex--;

    // And swap it with the current element.
    [array[currentIndex], array[randomIndex]] = [
      array[randomIndex], array[currentIndex]
    ];
  }

  return array;
}
var rows = document.querySelectorAll(".row");
var colors = ["red", "blue", "pink", "cyan", "green", "purple", "orange", "yellow"];
rows.forEach((e) => {
  e.querySelectorAll('.card').forEach((f) => {
    var color = shuffle(colors)[0];
    f.setAttribute("data-coulour", color);
    f.classList.add(color);
  })
})

var card1 = [];
var combos = 0;
// fonction pour cliquer sur les cartes, pour verifier si on a trouver une pair ou non en utilisant des condtions if

function onCardClicked(e) {
  const target = e.currentTarget;
  console.log(target.className.split(" "));
  target.className = target.className
    .replace('colour-hidden', '')
    .trim();

  card1.push(e.target);
  // verifie quil y a 2 cartes quon a cliquer dessus
  if (card1.length === 2) {
    // verifie si les deux cartes sont la meme couleur en verifiant la couleur dans la classname en utilisant une split pour verifier le 2ieme mot qui indentifie la coloueur
    if (card1[0].className.split(" ")[1] === card1[1].className.split(" ")[1]) {
      // si les deux couleurs sont la meme on ajoute +1 au combos
      combos++;
      //  mets un timeout avant que les cartes devient noir lorsquon trouve une pair
      setTimeout(() => {

        console.log(card1);
        card1[0].className += (" match-found");
        card1[1].className += (" match-found");
        //  vide le array pour quon peut choisir 2 nouvelles cartes
        card1 = [];

        //  verfie si combos est agele a 8 por voir si tu as gagner

        if (combos == 8) {
          //  sort element pour annoncer que tu a gagner par utilisant le class .gagne
          document.getElementById("win").style.display = "block";
        }
      }, 200);

      // le else pour quand les cartes sont pas la meme couleur et retourne la meme couleur quavant avec le meme timeout
    } else {
      setTimeout(() => {
        card1[0].className += (" colour-hidden");
        card1[1].className += (" colour-hidden");
        console.log("not a match");
        card1 = [];
      }, 200);
    }

  }
}
.row {
  text-align: center;
}

.card {
  display: inline-block;
  width: 150px;
  height: 150px;
  background-color: aliceblue;
  cursor: pointer;
}

.card.done {
  cursor: default;
}

.card.done:hover {
  cursor: default;
  box-shadow: none;
}

.card:hover {
  box-shadow: inset 0px 0px 0px 1px red;
  box-sizing: border-box;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}

.pink {
  background-color: magenta;
}

.cyan {
  background-color: cyan;
}

.green {
  background-color: green;
}

.purple {
  background-color: purple;
}

.orange {
  background-color: orange;
}

.yellow {
  background-color: yellow;
}

.colour-hidden {
  background-color: papayawhip;
}

.match-found {
  background-color: black;
}

.gagne {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: rgba( 0, 0, 0, 0.7);
  color: white;
  top: 0;
  left: 0;
  font-size: 50px;
  text-align: center;
  padding-top: 40%;
  display: none;
}
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Memory Game</title>
  <script src="app.js"></script>
  <link rel="stylesheet" href="./style.css">
</head>

<body>
  <div class="row">
    <div data-coulour="red" class="card red colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="orange" class="card orange colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="blue" class="card blue colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="pink" class="card pink colour-hidden" onclick="onCardClicked(event)"></div>
  </div>
  <div class="row">
    <div data-coulour="red" class="card red colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="cyan" class="card cyan colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="green" class="card green colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="pink" class="card pink colour-hidden" onclick="onCardClicked(event)"></div>
  </div>
  <div class="row">
    <div data-coulour="cyan" class="card cyan colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="orange" class="card orange colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="yellow" class="card yellow colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="blue" class="card blue colour-hidden" onclick="onCardClicked(event)"></div>
  </div>
  <div class="row">
    <div data-coulour="purple" class="card purple colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="purple" class="card purple colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="yellow" class="card yellow colour-hidden" onclick="onCardClicked(event)"></div>
    <div data-coulour="green" class="card green colour-hidden" onclick="onCardClicked(event)"></div>
  </div>
  <div class="gagne" id="win">TU AS GAGNE!!</div>
  <script src="app.js"></script>
</body>
Spectric
  • 30,714
  • 6
  • 20
  • 43
0

Here's an example that further explains my comment. A slicker implementation would only specify each colour once, then use code to create and fill an array of suitable size.

"use strict";
window.addEventListener('load', onLoaded, false);

let colours = [
  'red', 'red',
  'green', 'green',
  'blue', 'blue',
  'yellow', 'yellow',
  'purple', 'purple',
  'teal', 'teal',
  'orange', 'orange',
  'olive', 'olive'
];

function onBtnClick(evt) {
  shuffleAndUpdate();
}

function shuffleAndUpdate() {
  shuffleColourArray();
  let tdCollection = document.querySelectorAll('td');

  tdCollection.forEach((el, idx, col) => {
    el.style.backgroundColor = colours[idx];
    // sets TDs data-index=idx
    // wont change. Each elem always indexes
    // the same element in the array. We shuffle
    // the array.
    //
    // use the onclick handler of the square to
    // retrieve this index so you can check array
    // elems for a match when second tile is clicked.
    el.dataset.index = idx;
  });
}

function onLoaded(evt) {
  document.querySelector('button').addEventListener('click', onBtnClick, false);
  shuffleAndUpdate();
}

function shuffleColourArray() {
  for (var curElem = 0, nElems = colours.length; curElem < nElems; curElem++) {
    var tmp = colours[curElem];
    var newIndex = Math.floor((Math.random() * nElems));
    colours[curElem] = colours[newIndex];
    colours[newIndex] = tmp;
  }
}
td {
  border: solid 1px black;
  width: 32px;
  height: 32px;
}
<table>
  <tbody>
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </tbody>
</table>
<button>Re-shuffle</button>
enhzflep
  • 12,927
  • 2
  • 32
  • 51