Understanding while loops - javascript

I'm new to Javascript, and I'm trying to wrap my head around while loops. I understand their purpose, and I think I understand how they work, but I'm having trouble with them.
I want the while value to repeat itself until two random numbers match each other. Currently, the while loop only runs once, and I need to run it again if I want it to repeat itself.
How can I set this loop up so that it will automatically repeat the if statement until diceRollValue === compGuess? Thanks.
diceRollValue = Math.floor(Math.random()*7);
compGuess = Math.floor(Math.random()*7);
whileValue = true;
while (whileValue) {
if (diceRollValue === compGuess) {
console.log("Computer got it right!")
whileValue = false;
}
else {
console.log("Wrong. Value was "+diceRollValue);
whileValue = false;
}
}

That's because you're only executing the random number generator outside of the while. If you want two fresh numbers they need to be executed within the while statement. Something like the following:
var diceRollValue = Math.floor(Math.random() * 7),
compGuess = Math.floor(Math.random() * 7),
whileValue = true;
while (whileValue){
if (diceRollValue == compGuess){
console.log('Computer got it right!');
whileValue = false; // exit while
} else {
console.log('Wrong. Value was ' + diceRollValue);
diceRollValue = Math.floor(Math.random() * 7); // Grab new number
//whileValue = true; // no need for this; as long as it's true
// we're still within the while statement
}
}
If you wanted to refactor it, you can use break to quit the loop (instead of using a variable) as well:
var diceRollValue = Math.floor(Math.random() * 7),
compGuess = Math.floor(Math.random() * 7);
while (true){
if (diceRollValue == compGuess){
// breaking now prevents the code below from executing
// which is why the "success" message can reside outside of the loop.
break;
}
compGuess = Math.floor(Math.random() * 7);
console.log('Wrong. Value was ' + diceRollValue);
}
console.log('Computer got it right!');

You have two problems, the first is that you are setting whileValue in both the if and the else blocks so the loop will break after one iteration regardless of the values of the random numbers.
Secondly you're generating the guess before the loop so you'd be checking the same values over and over.
So remove whileValue assignment in the else block and move the compGuess assignment into the while loop.

Put the 2 random variables inside the loop.
whileValue = true;
while (whileValue) {
diceRollValue = Math.floor(Math.random()*7);
compGuess = Math.floor(Math.random()*7);
if (diceRollValue === compGuess) {
console.log("Computer got it right!")
whileValue = false;
}
else {
console.log("Wrong. Value was "+diceRollValue);
}
}

Related

How to make a random number appear as many times as I want

So I want a random number (picture) from a code below to appear as much time as I want. In this case I am dealing with pictures. Let' say I want to make a picture named 1.png just to be printed on screen 4 times excatly and then let's say pictures 5.png and 6.png all together to be returned 10 times (it can be 3 times 5.png, 7 times 6.png and other ways we can get to 10) and so on for other examples. How can I do it, since I have no idea at all ?
I hope I explained the right way what I want, and I hope anyone can help, thank you for your help.
function RandomImage() {
return (Math.ceil(Math.random() * 10)).toString() + ".png";
}
If you want to duplicate a string you could use a function like this
function repeat(item, number=1) {
return Array.from({length: number}).fill(item)
}
You can then call it like:
repeat(RandomImage(), 3) // -> ["1.jpeg", "1.jpeg", "1.jpeg"]
You can do this by setting up a datastructure which keeps track of how many times a specific number has already been returned.
For this purpose we can utilize JavaScript's Map object.
So the basic idea is this:
Inside the random number function we generate a random number
Look into the map how many times we already returned that number
In case it matches e.g. 1==10 times we go back to step 1
If there's no match increment the map entry for the given number and ultimately return the number
Here's an example:
let randomNumbers = new Map();
let maxNumbers = 10;
for (let a = 0; a <= maxNumbers; a++) {
randomNumbers.set(a, 0);
}
function RandomImage() {
let failed = false;
let random;
do {
failed = false;
random = Math.ceil(Math.random() * maxNumbers);
switch (random) {
case 1:
if (randomNumbers.get(1) == 4) {
failed = true;
}
break;
case 5:
if (randomNumbers.get(5) + randomNumbers.get(6) == 10) {
failed = true;
}
break;
case 6:
if (randomNumbers.get(5) + randomNumbers.get(6) == 10) {
failed = true;
}
break;
}
}
while (failed);
randomNumbers.set(random, randomNumbers.get(random) + 1);
return random.toString() + ".png";
}
for (let a = 0; a < 50; a++) {
console.log(RandomImage());
}

How can I make a function that repeats till it gets to a result without several requests?

I'm doing a memory game and I need to don't repeat the same picture more than twice, so I made a random number generator that repeats till the number isn't in an array. Doing that makes so many requests, so, when repeating the code, it doesn't work so I can't make the second half of the game. I know that the problem is in that because, when making it return the result without checking if it isn't in the array, everything works (but the images repeat, obviously). So, how can I make a function that gives a random number between two values that isn't in an array? I hope this is easy to understand.
Here the function:
function thingForTest() {
let forTest = randomBetweenBut(1, 8, 0);
if (array.includes(forTest)) {
return thingForTest();
} else {
return forTest;
}
}
Here the entire code:
var array = [];
function randomBetweenBut(num1, num2, but) {
function ifThing(num1, num2, but) {
let result = parseInt(Math.random() * (num2 - num1 + 1), 10) + num1;
if (result != but) {
return result;
} else {
return ifThing(num1, num2, but);
}
}
return ifThing(num1, num2, but);
}
function pictureRandomizer() {
for (let i = 1; i < 17; i++) {
let r1;
let picture = document.createElement("img");
function thingForTest() {
let forTest = randomBetweenBut(1, 8, 0);
if (array.includes(forTest)) {
return thingForTest();
} else {
return forTest;
}
}
array.push(thingForTest());
picture.src = "img/" + array[i - 1] + ".jpg";
let cuadrado = document.getElementById("cuadrado-" + i);
cuadrado.appendChild(picture);
if(i == 16 && r1 == false) {
i = 1;
r1 = true;
} else {
r1 = false;
}
}
}
pictureRandomizer();
You can use a function like this to return a random number between a min and a max, excluding any number passed in the exclusionArray. No recursion needed! It also includes a clause to stop infinite loops when a complete exclusionArray is passed.
Should be noted that since we're rerolling a random function, this could loop infinitely if you got REALLY unlucky, so this may not be the best function if your min, max and exclusionArray length are in the millions; But for most applications this should get the job done.
const getRandomWithExclusion = (min, max, exclusionArray) => {
// if exculsionArray contains all possible integers, return null to avoid infinite loop
if (exclusionArray.length > max - min) return null;
let output = null;
// if the randomly generated number is in the exclusionArray, reroll
while(output === null || exclusionArray.includes(output)) {
// simple random range function
output = Math.round(Math.random() * (max - min) + min);
}
return output;
}
.....

JS for loop not working correctly, trying to loop through an array of variables

I am trying to code the dice game Yahtzee in Javascript for fun. I have a basic interface set up with images of dice. In reference to my problem, a few Yahtzee rules to know would be:
There are 5 dice
After 3 rolls, the player has to pick a points category to score with
Here is the code that is not working:
var die1 = Math.floor((Math.random() * 6) + 1),
die2 = Math.floor((Math.random() * 6) + 1),
die3 = Math.floor((Math.random() * 6) + 1),
die4 = Math.floor((Math.random() * 6) + 1),
die5 = Math.floor((Math.random() * 6) + 1),
dieArray = ["", die1, die2, die3, die4, die5],
optionResult1 = 0;
document.getElementById("option1").onclick = function() {
if (rollCount == 3 & option1 == false) {
for (i=0; i < 5; i++) {
i++;
if (dieArray[i] == 1) {
optionResult1++;
}
if (i = 5) {
option1 = true;
document.getElementById("optionResult1").innerHTML = optionResult1;
console.log("finished");
}
}
console.log(optionResult1);
} else if (rollCount != 3) {
document.getElementById("dialogue").innerHTML = "You cannot pick this yet because you have not rolled 3 times.";
} else if (option1 == true) {
document.getElementById("dialogue").innerHTML = "You cannot pick this because you have already used this category.";
}
}
What should happen (assuming it's the third roll and this points category has not already been chosen previously):
The for loop should go through the dieArray and for each die that is a "one", add 1 to the optionResult1 variable. If there were three "ones" out of five dice, optionResult1 should be "3", etc.
What instead happens is that it usually comes back as 1 less than what it should be. Even if I can see in the console that the array clearly shows three "ones", it will give me "2", or sometimes "0". Is there anything wrong with the code you see? There is obviously other code in the document, but I am fairly certain the problem is within this function. Sorry if this was confusing, it's probably easier to understand if you have played Yahtzee...
I know that I could do the same thing with 5 if statements instead, but I am trying to learn from this and I am fairly confident this SHOULD work, I must just be doing something wrong. Thanks!

What is wrong with this code? Am I going about this the right way?

Okay, so I'm fairly new to programming. I've been learning to code for quite sometime now, but I hadn't really MADE anything. That considered, I'm attempting to make my first project using JavaScript and make a snake game. Unfortunately, I've ran into multiple problems, which obviously is something that comes hand in hand with programming, but I am new and I'm stuck. Can someone help me figure out if I'm coding this in an efficient way. Also, I have a more specific issue. I've added basic movement functionality to the head of my snake, but I can't figure out how to get the rest of it's parts to follow. If someone could explain to me how to do this, that would be incredible. I've worked about two weeks now to try and figure it out and I'm just stumped. I'm using Raphael's JavaScript Library to generate the graphics on an SVG canvas.
/*
Libraries in use:
1. Rapheal
2. jQuery
*/
// This variable is set to an array so that we can add multiple snakeParts to our PrimarySnake.
var snakeParts = [],
// This variable uses Raphael to generate a canvas.
snakeCanvas = Raphael(10, 10, 400, 400),
// This generates a rectangle that fills the canvas.
snakeCanvasBg = snakeCanvas.rect(0,0,400,400),
// This variable is set to an array so that we can use each and every direction that is pressed.
direction = [],
// This variable is set to an array so that we can use the turn coordinates of our first snake part.
turnCoords = [];
// Generates and returns a random number between 0 and 400. This function is used to help generate the goal of our snake at a random location on the canvas.
function getRandNum () {
var rand = Math.round(Math.random()*400);
// This while loop ensures that our snakeGoal never exceeds the coordinates x = 390 or y = 390. If it did, it's parts would be cut from the canvas.
while (rand > 395) {
rand = Math.round(Math.random()*400);
}
// This while loop ensures that our rand variabe will always be divisible by 10, which is used to make sure our snakeGoal and snakePart elements are always rendered in coordinates divisible by 10.
while (rand % 10 !== 0) {
var randString = rand.toString(),
// This variable stores the whole length of our randString variable.
randStringLength = randString.length,
// This variable stores the last number of our rand as a string character.
subtractionChar = randString.charAt(randStringLength - 1),
// This variable stores the last number of our rand as a integer.
subtractionInt = parseInt(subtractionChar),
// Finally, this line subtracts the last number of our rand from the entirety and then sets that value equal to rand, ensuring that rand is always divisible by 10.
rand = rand - subtractionInt;
}
return rand;
}
// This function is called any time a button is pressed. The jQuery which method allows our code to compare if the key pressed is equal to the keyCode of a designated key.
$(document).keydown(
function (pressedDirection) {
if (pressedDirection.which === 37) {
direction.push("left");
} else if (pressedDirection.which === 38) {
direction.push("up");
} else if (pressedDirection.which === 39) {
direction.push("right");
} else if (pressedDirection.which === 40) {
direction.push("down");
} else if (pressedDirection.which === 32) {
direction.push("stop");
}
if (pressedDirection.which === 37 || pressedDirection.which === 38 || pressedDirection.which === 39 || pressedDirection.which === 40 || pressedDirection.which === 32) {
console.log(direction[direction.length - 1]);
PrimarySnake.addTurnCoords();
PrimarySnake.movePeice();
}
// This prevents our screen from scrolling when an arrow key is
pressedDirection.preventDefault();
}
);
function Snake () {
// This method generates a new peice to the Snake.
this.addPart = function () {
console.log(snakeParts.length);
snakeParts[snakeParts.length] = snakeCanvas.rect(0,0,10,10);
snakeParts[snakeParts.length - 1].attr("fill", "blue");
snakeParts[snakeParts.length - 1].attr("stroke-width", ".25");
}
// This method provides the movement functionality of our Snake.
this.moveDirection = function () {
for (value in snakeParts) {
var currentCoord = [snakeParts[value].attr("x"), snakeParts[value].attr("y")];
// This if-else statement moves the snakePart at the -value- index up, down, left, or right according to the last direction pressed.
if (direction[direction.length - 1] === "up") {
snakeParts[value].attr("y", currentCoord[1] - 10);
} else if (direction[direction.length - 1] === "down") {
snakeParts[value].attr("y", currentCoord[1] + 10);
} else if (direction[direction.length - 1] === "left") {
snakeParts[value].attr("x", currentCoord[0] - 10);
} else if (direction[direction.length - 1] === "right") {
snakeParts[value].attr("x", currentCoord[0] + 10);
}
}
}
this.moveInterval;
// This function makes our moveDirection move our snakePeice every 50 milliseconds.
this.movePeice = function () {
var moveDirection = this.moveDirection;
// clearInterval is used to eliminate any interval previously running, ensuring that our peices only move one direction at a time.
clearInterval(this.moveInterval);
this.moveInterval = setInterval(function(){moveDirection()}, 50);
}
// This function adds an array of coordinates to the turnCoords array.
this.addTurnCoords = function () {
turnCoords.push([snakeParts[0].attr("x"), snakeParts[0].attr("y")]);
}
}
// This generates a new instance of our Snake class.
var PrimarySnake = new Snake();
// This generates a new part on the canvas.
PrimarySnake.addPart();
// This fills our snakeCanvasBg with a grey color, giving us a grey background.
snakeCanvasBg.attr("fill", "#CDCDCD");
Well, your code seems nice, or at least "efficient" as you are calling it.
To make the parts of your snake follow its head, you must iterate through its parts and assign each (n+1) piece the coordinates from (n). To do so, start with the last piece and iterate up to the first one, which movement is defined by the user, like in:
this.moveDirection = function () {
// Move every piece except the head.
for (var i = snakeParts.length - 1; i > 0; i--) {
snakeParts[i].attr("x", snakeParts[i-1].attr("x"));
snakeParts[i].attr("y", snakeParts[i-1].attr("y"));
}
// Now move the head.
if (direction[direction.length - 1] === "up") {
snakeParts[value].attr("y", currentCoord[1] - 10);
} else if (direction[direction.length - 1] === "down") {
snakeParts[value].attr("y", currentCoord[1] + 10);
} else if (direction[direction.length - 1] === "left") {
snakeParts[value].attr("x", currentCoord[0] - 10);
} else if (direction[direction.length - 1] === "right") {
snakeParts[value].attr("x", currentCoord[0] + 10);
}
}
That code may need a bit of work but that's the idea. Hope it helps!

Javascript: generate random numbers in range, avoiding previous two

I'm creating a slider with 6 slides, and I want to randomly move between them, making sure that neither of the previous two slides are shown as the next slide. The functionality doesn't really matter, since what I'm really doing is generating random numbers and keeping track of the previous two. The first slide is always numbered 1, so for the first two iterations that'll be one of the previous numbers that can't be used.
Here's what I have so far, and it works fine for generating the random numbers in the range, but 'caching' the last two values doesn't work reliably:
var rand = Math.floor(Math.random() * 6) + 1;
var prev1 = 1;
var prev2;
function randomSlide() {
// 5 second interval between slides
// Don't show either of previous two slides next
random = setInterval(function() {
prev2 = prev1;
prev1 = rand;
do {
rand = Math.floor(Math.random() * 6) + 1;
} while (rand == prev1 || rand == prev2);
prev1 = rand;
$('#slider').anythingSlider(rand);
//console.log(prev1,prev2);
}, 5000);
}
function firstSlide() {
firstTime = setTimeout(function() {
randomSlide();
}, 5000);
}
firstSlide();
randomSlide();
It's quite simple I think but my brain's getting frazzled trying to parse the values of the two 'cache' variables at the first, and then each subsequent, iteration.
I'm executing a single iteration at the beginning because if randomSlide() executes on load then the first (welcome) slide doesn't get a chance to display.
When you do the prev1 = rand the second time after you've changed the value of rand, you're assigning the new slide's number to it. The next time you enter the loop you do prev2 = prev1, and since prev1 == rand it means that now all three variables prev1, prev2 and rand are the same. Just remove the second prev1 = rand.
Another issue is that you set the interval twice: first you call firstSlide() which executes randomSlide() after a 5 second delay (which sets one interval), then right after you call randomSlide() again which sets another interval.
Here's another (simpler?) approach to getting the result:
<script>
// Return a random number from 1 to 6, exclude
// the last two numbers.
var getRandom = (function() {
var a = [1,2,3,4,5,6];
return function() {
var i = (Math.random() * 4 ) | 0;
a[5] = a.splice(i,1);
return a[5];
}
}());
function writeRandom() {
document.getElementById('d0').innerHTML += getRandom() + '<br>';
}
setInterval(writeRandom, 100)
</script>
<div id="d0"></div>
Not exactly random for the first 2 iterations, but you can fix that by randomising the array when it's initialised. But likely it doesn't matter for a slide show.
It's less code, but the splice part makes it slower in the browsers I tested. My version of the OP is:
var getRandom2 = (function() {
var r0 = r1 = r2 = 1;
return function() {
r0 = r1;
r1 = r2;
do {
r2 = Math.floor(Math.random() * 6) + 1;
} while (r2 == r0 || r2 == r1);
return r1;
}
}());

Categories