Rolling a die 60,000 times using if-else-if - javascript

I'm new to javascript and am facing trouble with the following problem.
Simulate rolling a die 60,000 times and display the frequency with which each face of the die finishes uppermost.
Use 6 variables to capture the frequencies and a 6-way if-else-if control structure need in the loop to increment them appropriately.
I know that I have to create an empty array which includes 6 variables and I have started the first iteration with 1.
What I don't understand is how to use the if-else-if statement to work through the 60000 iterations.
var array = [0, 0, 0, 0, 0, 0];
var i = 1;

You could introduce another variable for a random value between equal or greater than 0 and smaller than 6 and use it as index for the counting array.
Then you need a for loop, for counting the distribution of 60000 random values.
var array = [0, 0, 0, 0, 0, 0],
i,
r;
for (i = 0; i < 60000; i++) { // iterate 60000 times
r = Math.floor(Math.random() * 6); // generate random value
array[r]++; // increment counter
}
console.log(array);

for, Math.random:
var freqs = [0, 0, 0, 0, 0, 0];
var freqsLength = freqs.length; //* save array length into variable for more productivity
var rolls = 6000; //* how many time we want to roll dice
for(var i = 0; i < rolls; i++) { //* start rolling in loop
var j = Math.floor(Math.random() * freqsLength); //* get ramdom value
freqs[j]++; //* save freq result
}
alert(freqs);

Here's a working example with if-else:
var array = [0, 0, 0, 0, 0, 0];
var randomNumber;
for (var i = 0; i < 60000; i++) {
randomNumber = Math.floor(Math.random() * 6) + 1;
if(randomNumber === 1){
array[0]++;
}
else if(randomNumber === 2){
array[1]++;
}
else if(randomNumber === 3){
array[2]++;
}
else if(randomNumber === 4){
array[3]++;
}
else if(randomNumber === 5){
array[4]++;
}
else if(randomNumber === 6){
array[5]++;
}
}
console.log(array);

This question seems to be a homework, since you have to use if..else.
However, you don't need to use a if...else for this:
var arr = [0,0,0,0,0,0];
for(var i = 0; i < 60000; i++){
arr[~~(Math.random()*6)]++;
};
console.log(arr)
Explanation
The code has an for loop, which starts at 0 and ends at 60,000:
for(var i = 0; i < 60000; i++){
//...
};
For each iteration, a random value from 0 to 6 is generated...
Math.random()*6
... and converted to an integer using ~~.
Then, the element in the array at that random position is incremented:
arr[~~(Math.random()*6)]++;
Homework
Since this is in fact a homework and your requirements are:
Six variables
A six-way if..else
You can use this ugly, cumbersome and awkward code:
var one = two = three = four = five = six = 0;
for (var i = 0; i < 60000; i++) {
var random = ~~(Math.random() * 6) + 1;
if (random === 1) {
one++
} else if (random === 2) {
two++
} else if (random === 3) {
three++
} else if (random === 4) {
four++
} else if (random === 5) {
five++
} else if (random === 6) {
six++
}
};
var arr = [one, two, three, four, five, six];
console.log(arr)

Here's how I'd do it:
function randBetween(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
let counters = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0};
for (let i = 0; i < 60000; i++) {
counters[randBetween(1, 6)]++;
}
console.log(counters);
And here's what I'm guessing your teacher wants:
function randBetween(min, max) {
return Math.floor(Math.random() * max) + min;
}
let one = 0;
let two = 0;
let three = 0;
let four = 0;
let five = 0;
let six = 0;
for (let i = 0; i < 60000; i++) {
const n = randBetween(1, 6);
if (n === 1) { one++; }
else if (n === 2) { two++; }
else if (n === 3) { three++; }
else if (n === 4) { four++; }
else if (n === 5) { five++; }
else { six++; }
}
console.log(one, two, three, four, five, six);
You can decide for yourself which you think is the superior solution (Hint: How would you change each example to reflect rolling of a 100 sided die?)

Related

generate random numbers in specific range and using specific numbers?

How to generate random numbers in specific range and using specific numbers?
Example
given numbers [7,8];
given range [100-900];
output must be one of them 777, 787, 788, 878, 877, 888 etc...
Help me
const randomGenerateNumber = (maxRange:number, minRange:number, numbers:number[]) => {
//...what should i do in there??? Help me? Any Idea?
}
I think you don't want random numbers. It seems that you want a set of numbers based on some rules. Random means something else.
If I understand well your question you want to generate all possible numbers containing only a set of digits from a range of numbers. Is this an accurate description?
If so, this is similar with what you want: Generate random numbers only with specific digits
Edit:
You are right, so you want only one number.
In javascript you could do something like this:
I edited the algorithm to take into account min and max in probably the most lazy way. I didn't take into account cases where numbers can't be generated, it will return undefined.
There are so many ways to do this. Your algorithm can work too and maybe more efficient but it seems to have an issue with 0, it will generate numbers with 0 even if it's not in the digits array.
function randomGenerateNumber(minRange, maxRange, digits){
noTries = 0;
while(noTries++ < 100000)
{
var num = 0;
//get a random number from your range
len = Math.floor(Math.random() * (maxRange - minRange) + minRange);
//get the lenght of that random number
len = len.toString().length;
//generate a number with that length using only your set of digits
while(len--)
{
num = num * 10 + digits[Math.floor(Math.random() * digits.length)];
}
if(num >= minRange && num<= maxRange)
{
return num;
break;
}
}
}
//your testing cases
console.log(randomGenerateNumber(100,900,[7,8]))
console.log(randomGenerateNumber(299,300,[1,2,3,4,5,6,7,8,9]));
i did it. Is there any improvement. Little bit messy.
const getRandomNumber = (min: number, max: number, numbers: number[]): number => {
if (numbers.length === 9) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
let result = '';
//split maxDigits 100 => [1, 0, 0]
const maxDigits = max
.toString()
.split('')
.map(i => parseInt(i, 10));
//split minDigits 100 => [1, 0, 0]
const minDigits = min
.toString()
.split('')
.map(i => parseInt(i, 10));
//length of random number [minDigit, maxDigit] inclusive
const randomDigit = Math.floor(Math.random() * (maxDigits.length - minDigits.length + 1) + minDigits.length);
let alreadyHigh = false;
let alreadyLow = false;
let equal = true;
//4 conditions
//1. minDigits.length === maxDigits.length
//2. randomDigit === minDigits.length
//3. randomDigit === maxDigits.length
//4. randomDigit > minDigits.length && randomDigit < maxDigits.length
for (let i = 0; i < randomDigit; i++) {
const numbersToUse = i === 0 ? numbers : [...numbers, 0];
let availableNumbers = [];
if (minDigits.length === maxDigits.length) {
if (equal) {
for (let k = 0; k < numbersToUse.length; k++) {
if (minDigits[i] > maxDigits[i]) {
if (numbersToUse[k] >= 0 && numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
} else if (numbersToUse[k] >= minDigits[i] && numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
} else {
availableNumbers.push(maxDigits[i]);
}
}
} else {
if (!alreadyHigh) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] >= minDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
}
} else if (randomDigit === minDigits.length) {
if (!alreadyHigh) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] >= minDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
} else if (randomDigit === maxDigits.length) {
if (!alreadyLow) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
} else {
availableNumbers = numbersToUse;
}
availableNumbers = [...new Set(availableNumbers)];
const randomIndex = Math.floor(Math.random() * availableNumbers.length);
result += `${availableNumbers[randomIndex]}`;
alreadyHigh = !alreadyHigh ? availableNumbers[randomIndex] > minDigits[i] : true;
alreadyLow = !alreadyLow ? availableNumbers[randomIndex] < maxDigits[i] : true;
equal = equal ? availableNumbers[randomIndex] === maxDigits[i] : false;
}
return parseInt(result, 10);
};

Smallest Common Multiple [Javascript Challenge]

Question: Find the smallest common multiple of the provided parameters that can be evenly divided by both, as well as by all sequential numbers in the range between these parameters.
The range will be an array of two numbers that will not necessarily be in numerical order.
For example, if given 1 and 3, find the smallest common multiple of both 1 and 3 that is also evenly divisible by all numbers between 1 and 3, i.e. divisible by 1, 2 and 3. The answer here would be 6.
function smallestCommons(arr) {
var max=Math.max(...arr);
var min=Math.min(...arr);
var flag = 0;
var i = min;
while(true)
{for(var j=min;j<=max;j++)
{if(i%j!=0)
{flag=1;
break;}
}
if(flag==0)
{flag=5;
break;
}
i++;
}
console.log(i);
}
smallestCommons([1,5]);
For somereason my solution seems to go crazy and go into infinite looping. Although if I initialize var i to 60 (which is the desired output for this specific case i.e.[1,5]) the solution seems to be fine. Any fixes or guesses?
#Kevin has given a pretty good explanation of why it's not working. Your loop will only stop if flag is 0. But once it has been set to 1, you never reset it to 0.
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var flag = 0;
var i = min;
while (true) {
for (var j = min; j <= max; j++) {
if (i % j != 0) {
flag = 1;
break;
}
}
if (flag == 0) {
return i; // Return that common value
}
flag = 0; // Reset the flag
i++;
}
}
console.log(smallestCommons([1, 5]));
And here is an alternative way:
function smallestCommons(arr) {
const min = Math.min(...arr),
max = Math.max(...arr),
range = createRange(min, max);
let current = max;
while (true) {
const isFullyDivisible = range.every(n => current % n === 0);
if (isFullyDivisible) {
return current;
}
current++;
}
}
function createRange(min, max) {
return new Array(max - min + 1).fill(null).map((_, i) => min + i);
}
console.log(smallestCommons([1, 3])); // 6
console.log(smallestCommons([5, 1])); // 60
console.log(smallestCommons([1, 10])); // 2520
I did figure out the solution, thanks to the two programming geeks in the main comments sections.
function smallestCommons(arr) {
var max=Math.max(...arr);
var min=Math.min(...arr);
var flag = 0;
var count = 0;
var i = 1;
while(1){
for(var j=min;j<=max;j++)
{if(i%j!=0)
{flag=1;
break;}
if(j==max){
flag=0;
}
}
if(flag==0){
break;
}
i++;
}
console.log(i);
}
smallestCommons([10,2]);

Fill an array with distanced random integers

I need an array to be filled with random integers
Those integers should be very distinct from each other i.e. must at least be 20 units of separation between each items
This is what i have tried so far :
var all = [];
var i = 0;
randomDiff();
function randomDiff() {
var num1 = randomNumber(10, 290); //chose a first random num in the range...
all[0] = num1; //...put it in first index of array
do // until you have 12 items...
{
var temp = randomNumber(10, 290); //...you pick a temporary num
var j;
for (j = 0; j < all.length; j++) // for each item already in the array
{
if ((temp < all[i] - 10) || (temp > all[i] + 10)) // if the temporary num is different enough from others members...
{
all.push(temp); //then you can store it
i++; //increment until....
console.log(all[i]);
}
}
}
while (i < 11) // ...it is filled with 12 items in array
}
////////////Radom in int range function///////////////////////////////////////
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
but always unsuccessful, including infinite loops...
Have a look on something like this:
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
const LIST_SIZE = 20;
const DISTANCE = 10;
const STOP_AFTER_ATTEMPT = 2000;
const randomList = [];
let attempt = 0;
while(randomList.length < LIST_SIZE && attempt < STOP_AFTER_ATTEMPT) {
const num = randomNumber(10, 290);
const numberExistsWithSmallerDistance = randomList.some(r => Math.abs(r - num) < DISTANCE)
if (!numberExistsWithSmallerDistance) {
randomList.push(num);
}
attempt++;
}
if (randomList.length === LIST_SIZE) {
console.log(randomList);
} else {
console.log("Failed to create array with distnct values after ", attempt, " tries");
}
Here's a solution that will always work, as long as you allow enough room in the range/separation/count you choose. And it's way more efficient than a while loop. It doesn't just keep trying until it gets it right, it actually does the math to make sure it's right the first time.
This comes at the cost of tending to lean towards certain numbers more than others (like from + (i * separation)), so take note of that.
function getSeparatedRadomInts(from, through, separation, count) {
if(through < from) return getSeparatedRadomInts(through, from, separation, count);
if(count == 0) return [];
if(separation == 0) return !!console.log("Please allow enough room in the range/separation/count you choose.");
//pick values from pool of numbers evenly stepped apart by units of separation... adding 1 to from and through if from is 0 so we can divide properly
var smallFrom = Math.ceil((from || 1) / separation);
var smallThrough = Math.floor((through + (from == 0)) / separation);
var picks = randoSequence(smallFrom, smallThrough).slice(-count).sort((a, b) => a - b);
if(picks.length < count) return !!console.log("Please allow enough room in the range/separation/count you choose.");
for (var i = 0; i < picks.length; i++) picks[i] *= separation;
//go through each pick and randomize with any wiggle room between the numbers above/below it... adding 1 to from and through if from is 0
for (var i = 0; i < picks.length; i++) {
var lowerBound = picks[i - 1] + separation || from || 1;
var upperBound = picks[i + 1] - separation || (through + (from == 0));
picks[i] = rando(lowerBound, upperBound);
}
//subtract 1 from all picks in cases where from is 0 to compensate for adding 1 earlier
for (var i = 0; i < picks.length; i++) if(from == 0) picks[i] = picks[i] - 1;
return picks;
}
console.log(getSeparatedRadomInts(10, 290, 20, 12));
<script src="https://randojs.com/1.0.0.js"></script>
To be clear, from is the minimum range value, through is the maximum range value, separation is the minimum each number must be apart from each other (a separation of 20 could result in [10, 30, 50, 70], for example), and count is how many values you want to pick.
I used randojs in this code to simplify the randomness and make it easier to read, so if you want to use this code, just remember to paste this in the head of your HTML document:
<script src="https://randojs.com/1.0.0.js"></script>

I need to create an infinite loop

For my purpose I need to create loop where one variable is looping in this way:
0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1...
It's look simple but more than hour I wonder how to do it.
My purpose is moving the star in this way
*....
.*...
..*..
...*.
....*
...*.
..*..
.*...
*....
*....
.*...
..*..
...*.
....*
Write that loop as a generator (function *... yield) and then consume it when you need it (for...of). Of course, the consuming code must provide some termination condition.
function* bounce(min, max) {
while (1) {
for (let i = min; i < max; i++)
yield i;
for (let i = max; i > min; i--)
yield i;
}
}
STEPS = 10
for(let x of bounce(0, 4)) {
console.log(x)
if (--STEPS === 0) break;
}
You can use the following code to generate the number pattern that you require. However, you wont be able to run it infinitely since it will crash the browser.
If you want to test, I have added instructions for making the loop infinite.
For you requirement, a larger value for rep variable will be enough.
let min = 0; // Start/min value
let max = 4; // Max value
let dir = 1; // Count direction (+1/-1)
let counter = min; // Your counter variable
let rep = 24; // Remove this line and change condition inside while to true for infinite loop
do {
console.log(counter);
dir = counter===max?-1:counter===min?1:dir;
counter+=dir;
} while (rep-->0); // Change this expression to true for infinite loop
You can use setTimeout or setInterval for doing that:
let number = 0;
let increment = 1;
const from = 0;
const to = 4;
const starDiv = document.getElementById("star");
function printStar(number) {
const text = [0, 1, 2, 3, 4].map(
i => (i === number) ? '*' : '-'
).join('');
starDiv.innerText = text;
}
function loop() {
printStar(number);
number += increment;
if (number == to) {
increment = -1;
} else if (number == from) {
increment = 1;
}
}
const time = 10; // 10 millisecond between step
setInterval(loop, time);
<div id="star">
</div>
You could have a simple counter and then use modulo 8 to get iterations.
let x = (i += direction) % 8;
let y = x > 4 ? 8 - x : x;
This example even prints the ascii art ;)
let i = -1;
let direction = +1;
const out = [
"*....",
".*...",
"..*..",
"...*.",
"....*",
"...*.",
"..*..",
".*...",
"*....",
];
setInterval(function() {
let x = (i += direction) % 8;
let y = x > 4 ? 8 - x : x;
window.document.write(y + " " + out[x] + "<br>");
}, 1000);
(function(min,max,max_loops)
{
for(var loop = 1; loop <= max_loops; loop++, [min,max] = [-max,-min])
{
for(num = min; num < max + (loop == max_loops); num++)
{
console.log(".".repeat(Math.abs(num)) + "*" + ".".repeat(Math.max(Math.abs(max),Math.abs(min)) - Math.abs(num)))
}
}
})(0,4,3)
But since you need an infinite loop, using generator should be more suitable.

Dungeons and Dragons - Ability scores generation

I'm trying to create an array variable containing 6 numbers from 3 to 18, generated the way we generate the ability scores for D&D 5th edition.
For those who are not familiar with the game, the concept is to roll 6 die, and add up the 3 highest results, in order to get an ability score between 3 and 18.
My problem is that even tho it is supposed to have a range between 3-18, it sometimes generates a score of 0, and never really seems to go higher than 14...
Also, if I try to do a do/while loop until the result is higher than 17, just to check out if it is possible, I get some scores of 24 and even 34... So actually, what am I doing wrong? I tried a lot of things, and still it doesn't work... if anyone could help me out, I'd be so grateful!
Here is my code for the moment:
function generation() {
var abilities = [0,0,0,0,0,0];
var i, k, c, n, p;
//for each ability (there is 6)
for (c = 0; c <= 5; c++){
var scores = [0,0,0,0,0,0]
var nb = [-1,-2,-3]
var diffMax = 0;
var iDiff = 0;
var diff = 0;
//roll 6 die
for (i = 0; i <= 5; i++){
scores[i] = Math.ceil(Math.random() * 6);
}
//for each die rolled
for (k = 0; k <= 5; k++){
//compare to each score slot (there is 3)
for (n = 0; n <= 2; n++){
//determine difference
diff = scores[k] - nb[n];
//if the difference is higher than the previously determined difference
if (diff >= diffMax){
//note the difference and the position
iDiff = n;
diffMax = diff;
}
}
//replace the lowest score slot by the result if this result is higher than the score slot
if (diffMax >= 0){
nb[iDiff] = scores[k];
}
}
//add up each score slot
for (p = 0; p <= 2; p++){
abilities[c] = abilities[c] + nb[p];
}
}
return abilities;
}
From prior comments:
let rolls = [];
let min = 1;
let max = 6;
let numrolls = 6;
for ( let i = 0; i < numrolls; i++ ) {
// Probably put this in a util function
rolls.push ( Math.floor ( Math.random () * ( max - min + 1 ) ) + min );
}
rolls = rolls.sort ( ( a, b ) => { return a < b; } );
let result = rolls
.splice ( 0, 3 )
.reduce ( ( a, b ) => { return a + b; } );
console.log ( result );
You can accomplish what you're after like this:
function sumOfThreeDice() {
rolls = [0, 0, 0, 0, 0, 0].map((x) => Math.ceil(Math.random() * 6));
rolls.sort();
sum = rolls[5] + rolls[4] + rolls[3];
return sum;
}
console.log(sumOfThreeDice());
We roll 6 dice, then add up the largest 3 by sorting the array. If you want to do this multiple times to fill up an array, you could do:
[0, 0, 0, 0, 0, 0].map(sumOfThreeDice); // generates 6 D&D ability scores

Categories

Resources