1

I'm making a Discord.js bot and one of the functions of the bot is to return a random item from a Javascript array of facts when a user types "!fact". This question has been asked a lot by other users and I've used code from answers given to them but I've run into one problem: the bot gets "stuck" on one fact and doesn't go through the list randomly every time "!fact" is typed. This is an example of the code I have so far:

var facts = [ "Fact 1", "Fact 2", "Fact 3", "Fact 4" ]
var fact = Math.floor(Math.random() * facts.length);

And then, for the bot to send the message:

client.on('message', message => {
    if (message.content === "!fact") {
        message.channel.send(facts[fact]);
        console.log('Message sent');
    }
});

But this would only return something like Fact 1 over and over, no matter how many times "!fact" is typed. How can I make it change every time?

  • 1
    put your fact value inside the if condition and it will keep on updating it – vinayak shahdeo Jan 27 '20 at 19:13
  • browser speed test says function call and assignment inside if condition are the same speed, and node.js speed test suggests a function (var fact = ()=> Math.floor(Math.random() * facts.length);) call is slightly faster – just another profile name Jan 27 '20 at 19:29

2 Answers2

4

You're determining your random fact just once at startup using this line:

var fact = Math.floor(Math.random() * facts.length);

To get a random fact each time the if-condition evaluates to true you need to re-assign a new random integer to facts in there:

    client.on('message', message => {
        if (message.content === "!fact") {
            fact = Math.floor(Math.random() * facts.length);
            message.channel.send(facts[fact]);
            console.log('Message sent');
        }

});
obscure
  • 11,916
  • 2
  • 17
  • 36
2

Math.random() return a float value between 0 and 1, so multiply this number for an integer not necessary (almost never) return an integer number, that is actually what you need to iterate over an array.

https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Math/random

The Math.random() function returns a floating-point, pseudo-random number in the range 0 to less than 1 (inclusive of 0, but not 1) with approximately uniform distribution over that range — which you can then scale to your desired range. The implementation selects the initial seed to the random number generation algorithm; it cannot be chosen or reset by the user.

To work around this you can typically use Math.round() or Math.floor.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor

The Math.floor() function returns the largest integer less than or equal to a given number.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round

The Math.round() function returns the value of a number rounded to the nearest integer.

Since you need to limit your range on your facts.length you can use Math.floor, to never get the length value since the index of arrays to start on 0, in other words, the index of the last fact is equal to (facts.length - 1).

client.on('message', message => {
  if (message.content === "!fact") {
    const factIndex = Math.floor(Math.random() * facts.length);
    const fact = facts[factIndex]
    message.channel.send(fact);
    console.log('Message sent');
}

});