Search code examples
javascriptnode.jsdiscorddiscord.jsrepeat

Node.js: How to avoid message repeating


I wrote a code for my discord.js bot. The bot randomly selects one quote from the list and sends it to the channel. I would like to prevent quotes from repeating but I'm not sure how.

const Discord = require('discord.js');
require('dotenv').config();
const client = new Discord.Client();

const config = require("./config.json");
    const quotes = [
    {
        id: "1",
        quote: "This is quote 1"
    },
    {   
        id: "2",
        quote: "This is quote 2"
    },
    {
        id: "3",
        quote: "This is quote 3"
    },
    {
        id: "4",
        quote: "This is quote 4"
    },
    {
        id: "5",
        quote: "This is quote 5"
    },
    ];

client.on('message', (msg) => {
    if (msg.content.startsWith("T!quote")) {
        const random = quotes[Math.floor(Math.random() * quotes.length)];
        msg.channel.send(`${random.quote}` + `Quote #: ` + `${random.id}`);
    }
});

Solution

  • Shuffle the array ... return each value in order ... when you've reached the end, re-shuffle, rinse and repeat

        const shuffler = inArray => {
            const array = [...inArray];
            let index = array.length;
            return () => {
                if (index === array.length) {
                    // (re-)shuffle
                    while(index) {
                        const j = Math.floor(Math.random() * (index--));
                        if (index !== j) {
                            [array[index], array[j]] = [array[j], array[index]];
                        }
                    }
                }
                return array[index++];
            }
        };
    
        const quotes = [
            {
                id: "1",
                quote: "This is quote 1"
            },
            {   
                id: "2",
                quote: "This is quote 2"
            },
            {
                id: "3",
                quote: "This is quote 3"
            },
            {
                id: "4",
                quote: "This is quote 4"
            },
            {
                id: "5",
                quote: "This is quote 5"
            },
        ];
        
        const getNextQuote = shuffler(quotes);
        /*
        client.on('message', (msg) => {
            if (msg.content.startsWith("T!quote")) {
                const random = getNextQuote();
                msg.channel.send(`${random.quote} Quote #: ${random.id}`);
            }
        });
        */
        for (let n = 0; n < 13; n++) {
            const random = getNextQuote();
            console.log(`${random.quote} Quote #: ${random.id}`);
        }

    Note: this won't always prevent two identical quotes in a row - since you could have

    • 1 3 4 2 5; then
    • 5 2 3 1 4

    when the array is re-shuffled - you could add some logic to check what the last item was in the array before you shuffle, and make sure it's not the first item in the array after the shuffle

    A trivial way to do this would be to "rotate" the array by one, say by shifting the first element off the array and pushing it to the end

    if (index === array.length) {
        const lastItem = array[index - 1]; // prevent repetition
        while(index) {
            const j = Math.floor(Math.random() * (index--));
            if (index !== j) {
                [array[index], array[j]] = [array[j], array[index]];
            }
        }
        // prevent repetition
        if (array[lastItem] === array[0]) {
            array.push(array.shift());
        }
    }