javascriptnode.jsdiscorddiscord.jsdice

Discord.js dice roller problem returning (result+1)


I'm codding a discord bot and trying to implement a new dice code. I have this sketch:

 //dice rolling
    if(command.match(/(\d+)d(\d+)([+-]\d+)?/)) {
        let total = 0;
        let individualRolls = [];
        const rolls = command.match(/(\d+)d(\d+)/g);
        for (let i = 0; i < rolls.length; i++) {
            const [count, size] = rolls[i].split("d").map(val => parseInt(val));
            for(let j=0; j<count; j++){
                let roll = (Math.floor(Math.random() * size) + 1);
                individualRolls.push(roll);
                total += roll;
            }
        }
        const modifier = command.match(/([+-]\d+)/);
        if (modifier) {
            total += Number(modifier[0]);
        }
        message.channel.send(`You rolled ${command} and got ${total}!\nIndividual rolls: ${individualRolls}`);
    }

It actually works but when I roll like \*1d20+1d30 it gives a weird result. Let's suppose I've rolled a 20 and a 30, so the result should be 50, but the bot returns me 51, like the example below:

enter image description here

Does anyone know how to fix this or what's causing this?


Solution

  • The problem is with your modifier. Your current regex matches +1 in your command *1d20+1d30 because it doesn't really care if +1 is followed by the letter d. Check out the snippet below:

    let commands = ['*1d20+1d30', '*1d20+1d30+5', '*1d20+1d30-7'];
    let regex = /([+-]\d+)/;
    
    commands.forEach(command => {
      let modifier = command.match(regex);
    
      console.log(`${command}: ${modifier?.[0]}`);
    });

    If the modifier is only allowed to be at the end of the command, you can change your regex to only match the modifier if it's at the end. Adding the $ sign after the capturing group makes sure it only matches modifiers at the end of the string: /([+-]\d+)$/.

    let commands = ['*1d20+1d30', '*1d20+1d30+5', '*1d20+1d30-7'];
    let regex = /([+-]\d+)$/;
    
    commands.forEach(command => {
      let modifier = command.match(regex);
    
      console.log(`${command}: ${modifier?.[0]}`);
    });

    You could also use negative lookahead to exclude the character d from your match: /([+-]\d+)(?!d)/. The negative lookahead (?!) asserts that the pattern following it doesn't match.

    let commands = ['*1d20+1d30', '*1d20+1d30+5', '*1d20+1d30-7'];
    let regex = /([+-]\d+)(?!d)/;
    
    commands.forEach(command => {
      let modifier = command.match(regex);
    
      console.log(`${command}: ${modifier?.[0]}`);
    });

    You can run the snippet below and see that now it works as expected:

    let command = '*1d20+2d10-3';
    let total = 0;
    let individualRolls = [];
    let rolls = command.match(/(\d+)d(\d+)/g);
    
    for (let i = 0; i < rolls.length; i++) {
      let [count, size] = rolls[i].split('d').map((val) => parseInt(val));
    
      for (let j = 0; j < count; j++) {
        let roll = Math.floor(Math.random() * size) + 1;
        individualRolls.push(roll);
        total += roll;
      }
    }
    
    let modifier = command.match(/([+-]\d+)(?!d)/);
    
    if (modifier) {
      total += Number(modifier[0]);
    }
    
    console.log(`You rolled ${command} and got ${total}!
    Individual rolls: ${individualRolls}
    Modifier: ${modifier?.[0]}`);