0

I wish I wouldn't repeat the images until I send all the photos possible, is there a way?

const discord = require('discord.js');
const image = require('../image.json')
var rand = image[Math.floor(Math.random() * image.length)];
exports.run = async (client, message, args) => {

         const embed = new Discord.MessageEmbed()
        .setColor('RED')
        .setDescription(`Dog`)
        .setImage(rand)
         await message.channel.send(embed);
}
  • 1
    Welcome to StackOverflow! Could you please clarify on what you mean? Thanks! – Axiumin_ Nov 09 '20 at 23:21
  • You'd be better off creating an array of 1 thru N, shuffling that array, and then just looping through your shuffled array in sequence. You can visualize and find the shuffling code here: https://bost.ocks.org/mike/shuffle/. Otherwise you will need a way to keep track of which items from the set you've already shown, and iteratively regenerate random numbers every time you have a collision... which becomes very frequent after you've already shown 90% of your images. – Marc Nov 09 '20 at 23:22

2 Answers2

0

As I mentioned in my comment, instead of choosing a random item from a set and then trying to inspect whether you've already selected that random item, take the full set and shuffle it. Then you can just iterate over the shuffled set instead of trying to pick a random item that you hope doesn't collide with an item you've previously selected.

Looks something like this:

let arrayLen = 25; //assume you have a list of 25 items
let imageList = [...Array(arrayLen).keys()]; // makes an array of 0 thru arrayLen
console.log("Before: ", imageList);
let shuffledImages = shuffle(imageList); // <-- you'll want to iterate over shuffled images
console.log("After: ", shuffledImages); 

/**
 * Add loop code that you had been using to generate a new random, 
 * but just iterate over `shuffledImages` array instead
 */

// This is the Fisher-Yates shuffle algorithm
function shuffle(array) {
  var m = array.length, t, i;

  // While there remain elements to shuffle…
  while (m) {

    // Pick a remaining element…
    i = Math.floor(Math.random() * m--);

    // And swap it with the current element.
    t = array[m];
    array[m] = array[i];
    array[i] = t;
  }

  return array;
}
Marc
  • 11,403
  • 2
  • 35
  • 45
  • That's a lot like the highest voted Answer on this Question. https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array – computercarguy Nov 09 '20 at 23:49
  • Yes, it's similar. I hadn't seen that answer. Feel free to recommend the question above as a duplicate. – Marc Nov 09 '20 at 23:51
  • It looks like the asker wants to be able to keep getting images even after the entire array is exhausted; I have tried to address this in my answer. – BrownieInMotion Nov 09 '20 at 23:52
  • 1
    While your Answer is a dup, the Question isn't. And I'm not saying your Answer is bad, either. I'm just noticing a similarity. – computercarguy Nov 09 '20 at 23:53
  • i don't know much about english, what did you mean by "but just iterate over` shuffledImages` array instead "? am i supposed to add something to the var rand? my var rand: var rand = list [Math.floor (Math.random () * list.length)]; – gari30voos Nov 09 '20 at 23:59
  • @gari30voos if you use my answer, you can just replace `.setImage(rand)` with `.setImage(images.next().value)` – BrownieInMotion Nov 10 '20 at 00:04
0

It looks like you want to be able to always get images even after exhausting the list, but that you don't want to have duplicates until you've gone through the entire array.

Here is a possible implementation using a generator function and the Fisher-Yates shuffle:

// shuffle a copy of the array
function shuffled(arr) {
  const copy = arr.slice();
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    const temp = copy[i];
    copy[i] = copy[j];
    copy[j] = temp;
  }
  return copy;
}

// give next element in array; if exhausted, shuffle and repeat
function* imageGenerator(arr) {
  while (true) {
    for (const e of shuffled(arr)) {
      yield e;
    }
  }
}

// proof of concept; [1, 2, 3] would be replaced with your array
const images = imageGenerator([1, 2, 3]);
for (let i = 0; i < 5; i++) {
  // get next image
  console.log(images.next().value);
}
.as-console-wrapper {min-height: 100%;}

Here's how it might look in your case:

const discord = require('discord.js');
const image = require('../image.json')

// shuffle a copy of the array
function shuffled(arr) {
  const copy = arr.slice();
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    const temp = copy[i];
    copy[i] = copy[j];
    copy[j] = temp;
  }
  return copy;
}

// give next element in array; if exhausted, shuffle and repeat
function* imageGenerator(arr) {
  while (true) {
    for (const e of shuffled(arr)) {
      yield e;
    }
  }
}

const images = imageGenerator(image);

exports.run = async (client, message, args) => {
  const embed = new Discord.MessageEmbed()
    .setColor('RED')
    .setDescription(`Dog`)
    .setImage(images.next().value)
    await message.channel.send(embed);
}
BrownieInMotion
  • 1,162
  • 6
  • 11
  • thx for the dedication for helping me, but it still keeps repeating even before I finish, I left only 4 images in the list for me to test and repeated the same image before finishing the 4 images, do you imagine what it can be? – gari30voos Nov 10 '20 at 00:22
  • 1
    your edition worked now, I LOVE YOUUUUUUUUUUU!!!!!!! – gari30voos Nov 10 '20 at 00:27
  • Keep in mind that this only prevents duplicates to some extent. A possible output is `1, 2, 3, 4, 2, 3, 1, 4`, and you will notice that if you start counting at output 2, you will see the string `2, 3, 4, 2`. These duplicates are unpreventable. – BrownieInMotion Nov 10 '20 at 00:29
  • just making a question, is it possible to do this with a .json with texts? – gari30voos Nov 10 '20 at 00:49