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>