Home > front end >  How to use only twice the same item in an array in js?
How to use only twice the same item in an array in js?

Time:11-18

I'm currently working on a Pairs game in JavaScript but I don't know how to use the picture only two times not more.

I've made an Array of objects with the pictures that have as key ID, src and a name. I loop through this array to have the id and use it in the template in a random way. So I don't have the same picture next to each other.

This is the current state of my code :

for (let index = 0 ; index < 18; index  ) {
    let x = Math.round(Math.random() * 8);
    
    let template = document.getElementsByTagName('template')[0];
    let target = document.getElementById('Playground');
    let clone = template.content.cloneNode(true);

    clone.querySelector("img").src= item[x].src;
    clone.querySelector("img").alt = item[x].id;
    clone.querySelector('button').setAttribute('id', i  );
    clone.querySelector('button').setAttribute('Onclick', null);

    target.appendChild(clone);
};

I think the issue is the x variable that generate randomly a picture in the template. But the same picture return more than or less than 2 time or some pictures aren't used.

Can someone help me please ?

CodePudding user response:

The best way to think about it if you have a finite number of items is that you either create the array you need for your final solution (Option A) or to find a way to exclude items from random selection after you don't want them anymore (Option B).

First I will refactor your template copy into a function called render, and your total iterations (18) and maxIndex (8) into constants:

const render = (currItem, index) => {
    let template = document.getElementsByTagName('template')[0];
    let target = document.getElementById('Playground');
    let clone = template.content.cloneNode(true);

    clone.querySelector("img").src= currItem.src;
    clone.querySelector("img").alt = currItem.id;
    clone.querySelector('button').setAttribute('id', index);
    clone.querySelector('button').setAttribute('onClick', null);

    target.appendChild(clone);
};
// The following variables will make your code dynamic, so if you add more items to the game it will continue working correctly
const total = item.length * 2; 
const maxIndex = item.length - 1;

Option A

This option is for educational purposes and as you have a finite list it may be OK, but it is less performatic.

const items = [...item, ...item]; // this is creating a new array with all items twice

// shuffle the items in the array
for (let i = items.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i   1));
    [items[i], items[j]] = [items[j], items[i]];
}

// The array is shuffled with 2 instances of each item, so this will show the desired values
items.forEach(render)

Option B

In this option we will create a second array that exclude items that were used twice.

const rendered = [] // will store items rendered once
while(item.length > 0) { // will run until item has no element
    let index = Math.round(Math.random() * (item.length - 1)); // max index is based on the current length of item array
    const currItem = item[index];
    render(currItem, index);
    if (rendered.includes(currItem)) {
        item.splice(index, 1); // remove item after the second time it is rendered
    } else {
        rendered.push(currItem); // add to the rendered array after the first pass
    }
}

CodePudding user response:

From your posted code, I think all unique elements are in an array called items. To make sure you have 2 copies of each, you can create a new array that includes items twice:

const doubleItems = items.concat(items);

To get a random element from an array, you can write:

const randomIndex = Math.floor(Math.random() * doubleItems.length);
const randomElement = doubleItems[randomIndex];

(Notice the .floor, not .round!)

To make sure you don't accidentally keep fetching the same random element multiple times, you can remove every element you pick from your source:

doubleItems.splice(randomIndex, 1);

If you do this in a while loop, you can keep on going until all elements are placed!

const items = [
  { src: "A" },
  { src: "B" },
  { src: "C" },
  { src: "D" },
  { src: "E" },
  { src: "F" },
  { src: "G" },
  { src: "H" }
];

const doubleItems = items.concat(items);

while (doubleItems.length) {
  // Pick random element
  const randomIndex = Math.floor(Math.random() * doubleItems.length);
  const randomElement = doubleItems[randomIndex];
  
  // Remove element
  doubleItems.splice(randomIndex, 1);
  
  // Simplified for brevity
  const tile = document.createElement("div");
  tile.innerText = randomElement.src;
  document.body.appendChild(tile);
  
}
body {
  display: grid;
  grid-template-columns: 30px 30px 30px 30px;
  grid-template-rows: 30px 30px 30px 30px;
  grid-gap: 4px;
}

div {
  border: 1px solid black;
  display: flex;
  align-items: center;
  justify-content: center;
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related