Making a Dice Roller for Dungeons and Dragons Dice Pt.1

Making a Dice Roller for Dungeons and Dragons Dice Pt.1

As I'm learning more and more vanilla Javascript I want to lean harder into projects. I struggled for a little while to come up with anything meaningful as a goal, until recently. Ultimately, I'd like to try to build a light version of a Virtual Table Top system to go alongside my love for Dungeons and Dragons and other table top games. That being said, I have absolutely no idea what I'm doing, so this should be fun!

I figured I'll start with one of the easiest components to build, a dice roller. This will start off as a simple Javascript app that I will pretty up with HTML and CSS, but ultimately I want to convert it into a React component so I can use it as part of a larger system.

I started with a d4. I knew I wanted to create a function to be able to call to run this, and started with the simplest part of the function. Get a random number, multiply it by 4, then add 1 to it so the number would be 1-4 versus 0-3. I set x as my argument here knowing I'd eventually want to have multiple dice rolled. Here's what that looks like:

const d4 = x => {
  return Math.floor(Math.random() * 4) + 1;
}

A console.log of the above code returned a random number between 1 and 4. Perfect! Next comes the idea of being able to roll multiple d4 dice. I began by putting together an if...else statement that determined whether there was more than one dice passed through.

const d4 = x => {
  if (typeof x === 'undefined') {
    return Math.floor(Math.random() * 4) + 1;
  } else {
    // Some other code
  }
}

I had initially set the first if line to if(x === ''). This of course set the type of x to be a string and trying to apply that number to later code could generate a NaN error in the log. A quick Google search reminded me of typeof and applying that to the if line instead basically says "if nothing is passed to the function, run this code, otherwise continue".

The second part of this code was to apply the multiple dice roll. At first I pulled the very educated move of just multiplying the random generation by x, the number of dice passed, like so:

const d4 = x => {
  if (typeof x === 'undefined') {
    return Math.floor(Math.random() * 4) + 1;
  } else {
    return (Math.floor(Math.random() * 4) + 1) * x;
  }
}

This technically worked, however it was effectively just multiplying the normal response by x instead of giving me a new random roll. This seemed obvious after I ran it, but remember I'm fresh at this!

The next thought process was a loop, but I wanted to make sure the loop ran at least once. This led me to the do...while loop, which started off as a smart idea but never quite worked as expected. I instead kept my original code and used a for loop in the "else" section. I effectively wanted to run the randomization, run through the loop as many times a x was set to run, adding the new randomization from each loop to the original randomization. I'm sure there is an easier way to do this, but this is where I landed:

const d4 = x => {
  if (typeof x === 'undefined') {
    return Math.floor(Math.random() * 4) + 1;
  } else {
    let dice = 0; // initialize the dice
    for (let i = 1; i <= x; i++) { // loop through x number of times
      let diceR = (Math.floor(Math.random() * 4) + 1); // New variable to hold the dice value
      console.log(diceR); // Log the new dice value to make sure everything adds up
      dice = dice + diceR; // New dice value added to dice
    }
    return dice // Return the total amount once done
  }
}

This worked perfectly! If you console.log(d4()); with no arguments, it runs the one time and gives you a random number between 1-4. If you pass an argument, like running the dice twice console.log(d4(2)); it will run twice, taking two different random numbers and passing them together. Great!

I started to build out another function for d6 before realizing I could simply turn the multiplication applied to the Math.random call into a variable itself and change my dice type. I created a new argument called diceType and changed our x argument to diceNumber. I also changed the function name to be dice, and adjusted the dice variable in the code to diceC for dice count. This is what that change ultimately looked like:

const dice = (diceType, diceNumber) => {
  if (typeof diceNumber === 'undefined') {
    return Math.floor(Math.random() * diceType) + 1;
  } else {
    let diceC = 0;
    for (let i = 1; i <= diceNumber; i++) {
      let diceR = (Math.floor(Math.random() * diceType) + 1);
      console.log(diceR);
      diceC = diceC + diceR;
    }
    return diceC;
  }
}
console.log(dice(4,2));

Finally, I wanted to add some logic at the top of the function that checked whether the dice passed was the typical dice used in DnD, a d2, d4, d6, d8, d10, d12, or d20. It's a little long, but this is what I came up with:

const dice = (diceType, diceNumber) => {
  if (diceType === 2 || diceType === 4 || diceType === 6 || diceType === 8 || diceType === 10 || diceType === 12 || diceType === 20) {
    if (typeof diceNumber === 'undefined') {
      return Math.floor(Math.random() * diceType) + 1;
    } else {
      let diceC = 0;
      for (let i = 1; i <= diceNumber; i++) {
        let diceR = (Math.floor(Math.random() * diceType) + 1);
        console.log(diceR);
        diceC = diceC + diceR;
      }
      return diceC;
    }
  } else {
    return 'You must choose the right type of dice (2, 4, 6, 8, 10, 12, 20)';
  }
}


console.log(dice(6,4)); // Returns the total of 4d6
console.log(dice(5,2)); // Returns 'You must choose the right type of dice (2, 4, 6, 8, 10, 12, 20)

And we're done! I'm pretty happy this worked the way I wanted it to, and while it's pretty simple, it performs the basis of a pretty important task! The next step is to set up a GUI that can be used to select dice choice graphically, as well as a way to pass multiple dice types. I'll be putting that together in part two of this article.

I know there is probably a way to make this code a bit shorter. If you have any suggestions I would love to hear them!