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:
Does anyone know how to fix this or what's causing this?
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]}`);