Reputation: 47
I'm creating a dice bot for Discord, and I've got a parameter that is supposed to remove any dices that have rolled a '1' from the requested dice array, so that they can be re-rolled until such times that there are no more 1's.
For example, if the user rolled this dice sequence..
4 5 3 2 1 1
The code would identify that there are two 1's rolled, remove them from the array, and try and re-roll them until they turn up, say '2' and '5' instead, then add them back to the array.
I'm struggling to make my loop function effectively to process the re-rolling process. Here's what I've done so far:
// Reroller
while (rerolls >= 1) {
rerolled.push(Math.floor(Math.random() * diceType + 1));
var latestReroll = rerolled.slice(rerolled.length - 1);
console.log("Latest reroll:" + latestReroll);
// check if the lastest reroll was a 1. If so, delete it and increase the reroll counter accordingly.
if (latestReroll = 1) {
console.log("Rerolling the latest roll.");
rerolled.pop()
console.log(rerolled.push(Math.floor(Math.random() * diceType + 1)));
console.log("New reroll:" + latestReroll);
}
rerolls--;
}
The code tracks the amount of rerolls required by counting the 1's in the previous array (this part works fine and isn't included in the code sample). It's supposed to start creating a new array that could eventually be added to the main dicepool, start generating new numbers, and checking if the newest number generated is a 1 (re-rolling if so). At the moment, it doesn't work. The rerolled array still contains 1s.
I've exhausted my own newbie attempts to try and fix it thus far, so I'd greatly appreciate some help!
Upvotes: 0
Views: 885
Reputation: 21130
The issue you face is due to the lines:
var latestReroll = rerolled.slice(rerolled.length - 1); // ... if (latestReroll = 1) {
There are two issues here:
slice
returns an array, not the last element. Meaning that will never be 1
. The closest it will be is [1]
. Use the array accessors array[index]
instead.latestReroll = 1
the single =
is the assignment operator. For equality you want to use ==
or ===
.This can be fixed by changing the lines into:
var latestReroll = rerolled[rerolled.length - 1];
// ...
if (latestReroll == 1) {
Note that this fixes the first re-roll, but the re-roll itself is never checked and can still be a 1.
Something like this could also be achieved in the following manner:
class Die {
constructor(sides) {
this.sides = sides;
}
roll() {
this.value = Math.floor(Math.random() * this.sides) + 1;
}
}
const dice = Array.from({length: 6}).map(() => new Die(6));
let reroll = dice;
while (reroll.length) {
reroll.forEach(die => die.roll());
reroll = reroll.filter(die => die.value == 1);
console.log(...dice.map(die => die.value));
}
You could create two arrays. One that hold the dice and one that holds the dice that need to be re-rolled (which is initially all dice). As long as the reroll
array is not empty you re-roll the dice in the array. Only keeping the 1s after each roll.
Upvotes: 1
Reputation: 20151
Firstly, I would encapsulate a single dice roll into its own method:
function roll_die(min, max) {
return Math.floor(Math.random() * (max - min + 1) + 1);
}
this makes it easier to keep that code correct and to understand the surrounding code.
As mentioned in Nina's answer, you can use a while loop instead of a for loop to get a valid roll, assuming you don't need to tell the user that this was a reroll:
function rerolling_die(max) {
let roll;
do {
roll = roll_die(1, max);
} while(roll == 1);
return roll;
}
However this has one potential pitfall - the number of rolls is not limited, and the runtime will be indeterminate. It's not a big problem, for any real board game the number of rolls is likely to be few, but if you were rolling a large number of times (e.g. for a simulation, or analysis for an AI player), then it would be better if that was just 1 roll every time.
Since the 1 rolls are evenly redistributed among the other numbers, there is no difference between a 6 die which is rerolled until it isn't 1 and a die which just has 2-6.
So we can in fact remove the act of rerolling entirely:
let roll = roll_die(2, 6);
Upvotes: 1
Reputation: 386654
You could take a while loop and check the value in advance befor adding to the array.
let dice = getRoll();
while (dice === 1) dice = getRoll();
// add roll
For getting directly a random value without 1
, you could use 5
as factor and take an offset of 2
.
let dice = Math.floor(Math.random() * 5) + 2;
console.log(dice);
Upvotes: 1