General Looping question - javascript

var answer = " ";
var correct = "4";
var question = "What is 2 * 2?";
for(i = 2; i < 5; i++) {
answer = prompt(question, "0");
if (answer == correct) {
alert("Your answer is correct!");
break;
}
}
How many chances would the user have before the break command got executed?

The user would have 3 chances unless they guessed right on the 1st or 2nd chance. Then they would only have 1 or 2 chances respectively.
i = 2 in the first iteration, i = 3 in the next iteration and i = 4 in the last iteration. Before another iteration starts i is set to 5 and the condition fails.

The user will have 3 chances (i=2, i=3 and i=4).

Related

Why is unshift() returning a different value than push() if I am targeting the first element in the former and the last element in the latter?

I have a function for Project Euler #7. Towards the end, I changed the code from primeArray.push(i); to primeArray.unshift(i) and return primeArray[primeArray.length - 1]; to return primeArray[0];. This altered the return. In the former. It returned the correct answer, 104021, while the latter returned 20001, which is not even prime. I do not understand why that is.
function primeFinder(primeTarget) {
//since 2 is the only even prime, putting it here saves us some effort in checking primality by just iterating over the odd numbers
//it also helps the for loop since we are only interested in checking for divisors among previous primes.
let primeArray = [2];
let i = 3;
while (primeArray.length < primeTarget) {
let primeLogger = false;
//We don't need to check for divisibility by 2, so j can equal 1
for (j = 1; j < primeArray.length && primeArray[j] < Math.sqrt(i); j++) {
if (i % primeArray[j] === 0) {
primeLogger = true;
//Since we have found a divisor and changed primeLogger, we can exit the loop
break;
}
}
//Where the break goes to, and also where the for loop goes to once finishes
if (primeLogger === false) {
primeArray.push(i);
}
i += 2;
}
return primeArray[primeArray.length - 1];
}
console.log(primeFinder(10001));
Because primeArray is now in descending order but your loop still searches from start to end; now from biggest towards smaller values. Until it finds something that is >= Math.sqrt(i) which most likely will be the very first check, j=1.
Then it ends the loop with primeLogger === false
so for example, for:
i=9, j=1
primeArray === [7,5,3,2]
primeArray[j] === 5
And since the check 5 < Math.sqrt(9) is false the loop is finished.
Therefore 9 is a prime number and is now added to the start of primeArray.

Why does the following javascript cause Unresponsive Script error?

When trying out the code below as a solution for the Euler Project problem 5. The problem is find the smallest number equally divisible by all numbers from 1 to 20. Every time it is run it presents "Unresponsive Script" window and I need to physically stop the script from running. It seems like something is causing it to hang but I can't quite figure out what. The alert window seems to point to an error with the line the while() starts on but I can't see anything wrong with it.If it looks like it should work I'd appreciate anyone trying it on their machine to see if it works. That way I can eliminate it as a local problem. All suggestions welcome.
var divisible = false;
var n = 2520; // first number divisible by all numbers 1-10
while(divisible === false){ // something wrong here??
n += 2520;
for(var i = 11; i < n; i++) {
if(i % n !== 0){
break;
}
if(i === 20) {
divisible === true;
}
}
}
if(divisible === true){
return console.log("Answer: " +i);
}
Because you break out of your for loop if i % n isn't 0 the very first time. And you never set divisible to true - divisible === true isn't the same as divisible = true
There are several errors in the original code, some pointed out in the answer above. To make it work several fixes are needed.
First, the boolean divisible must be correctly set to true using the assignment operator = inside the for loop instead of === which is used only to check if two values are strictly of the same type AND value.
The next problem is the conditional part of the for loop i < n should be i < 20 because the loop is checking if numbers between 11 and 20 divide evenly into n.The last fix to make the code run correctly is the order of the condition if the first if statement which should read if(n % i !== 0) and not if(i % n !== 0). I think it might be this specific part that caused the code to crash and generate the "Unresponsive Script" alert in the browser.
Here is the fixed code.
var divisible = false;
var n = 2520; // smallest number divisible by all numbers 1-10
while(divisible === false){
n += 2520; // increment n on each new pass
// loop numbers between 11 and 20
for(var i = 11; i <= 20; i++) {
if(n % i !== 0){ // check if i divides equally into n
// if not break out of current loop and start again
break;
}
// if i reaches 20 then all the numbers divided equally into n
if(i === 20) {
// set value of divisible to true to cancel while loop
divisible = true;
}
}
}
// return the last value of n
return console.log("Answer: " +n);

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!

Whats wrong with my code? - dice rolling

I am trying to log to the console a message saying : Gratz! You gained 5 points!' after you rolled two the same numbers after each other.
can someone explain me what is wrong with my code?
<script>
var d1 = Math.floor(Math.random()*6) +1;
var diceRolls = [];
function rollDice() {
var die1 = document.getElementById("die1");
var status = document.getElementById("status");
var d1 = Math.floor(Math.random()*6) +1;
console.log("You rolled "+d1+".");
diceRolls.push(d1);
}
if(diceRolls[diceRolls.length - 1] === d1) {
console.log("You won 5 points!");
}
</script>
The problem with your code is that you're checking outside the function, and the condition is not correct. First you need to make sure that the dice has been rolled at least two times, then you compare the two last values. And as #Bergi noted, you also need to call the function, although I guess you're already doing that. Below is the correct solution:
var diceRolls = [];
var totalDiceRolls = 0;
// you set this to whatever you want the limit to be
var maxDiceRolls = 10;
function rollDice() {
if (++totalDiceRolls > maxDiceRolls)
{
alert(maxDiceRolls + " dice rolls allowed at max!");
return;
}
var die1 = document.getElementById("die1");
var status = document.getElementById("status");
var d1 = Math.floor(Math.random()*6) +1;
console.log("You rolled "+d1+".");
diceRolls.push(d1);
if(diceRolls.length > 1 && diceRolls[diceRolls.length - 2] == d1) {
console.log("You won 5 points!");
}
}
You never loop the result, and you assign d1 with a random number, but do nothing with it.
You need to roll the dice and each time, loop the array to find if 2 numbers are the same, at the moment you don't loop, so there is no way to know if 2 numbers are equals.

Looping over numbers

So this is the question that is given.
You are in a room with a circle of 100 chairs. The chairs are numbered sequentially from 1 to 100.
At some point in time, the person in chair #1 will be asked to leave. The person in chair #2 will be skipped, and the person in chair #3 will be asked to leave. This pattern of skipping one person and asking the next to leave will keep going around the circle until there is one person left, the survivor.
And this is the answer I came up with. I believe this is the right answer, I've done it on paper about 10 times as well and came up with 74 every time.
Is this a trick question or something? Because I'm not sure what to do from here.
Here is the jsfiddle http://jsfiddle.net/cQUaH/
var console = {
log : function(s) {
document.body.innerHTML += s + "<br>";
}
};
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 2;
while(chairArr.length > 1) {
console.log('removing ' + chairArr[j]);
chairArr.splice(j, 1);
j++;
if(j >= chairArr.length) {
console.log('--- Finished pass');
console.log('--- Array state:');
console.log(chairArr);
j = (j == chairArr.length) ? 0 : 1;
}
}
console.log('--- Final result: ' + chairArr);
//result 74
With a minor change in indices, you have the Josephus problem. In the traditional formulation, person 1 kills person 2, 3 kills 4, etc. To convert to that form, kill off person 1, as your problem states, and then renumber people 2-100 by subtracting 1, giving people 1-99.
A good treatment of the Josephus problem, including an account of its origin in the Jewish Revolt of 70-73 CE, is in Concrete Mathematics, 2nd edition, by Graham, Knuth, and Patashnik, Section 1.3. Both Wikipedia and Wolfram MathWorld have articles on the problem, Wikipedia even includes the original description by Josephus in The Jewish War.
The book gives a mildly complicated recursion for the solution, and a simpler algorithm. If the number of people is n, and n = 2^l + m where l is as large as possible, then the answer is 2m+1. So, since 99 = 2^6 + 35, the solution is 2*35 + 1 = 71. But you need to reverse the renumbering, so the real answer is 72.
As far as your programming problem, however, why don't you take as your basic operation Remove the first person in the circle and move the second person to the end. So, with 5 people, [1,2,3,4,5], you remove the first getting [2,3,4,5]and moving the new first element to the end getting [3,4,5,2].
var killAndRotate = function(array) { // say [1,2,3,4,5]
var dead = array.shift(), // dead = 1, array = [2,3,4,5]
skipped = array.shift(); // skipped = 2, array = [3,4,5]
array.push(skipped); // array = [3,4,5,2]
}
And then the main loop becomes:
while (chairArray.length > 1) {
killAndRotate(chairArray);
}
alert(chairArray[0]); // or console.log, or return.
// In turn, array is:
// [1,2,3,4,5]
// [3,4,5,2]
// [5,2,4]
// [4,2]
// [2] and we alert, log, or return 2.
Added
The easy way to find that result for the original Josephus problem is to see that:
If there are 2^l people, then in the first pass all the even-numbered people are killed, so the first person remains alive.
1 2 3 4 5 6 7 8
X X X X
Now there are 2^(l - 1) people. Again, the first person survives:
1 2 3 4 5 6 7 8
X X X X
X X
Repeat the process; the first person survives each pass, and so is the last survivor.
Now, suppose there are m extra people with m < 2^l. Here, l = 3 and m = 5. Kill the first m people to die.
1 2 3 4 5 6 7 8 9 10 11 12 13
X X X X X Y
Now, there are 2^l people left, and person 2 m + 1 = 11 is the first in line. So he survives.
One should also point out that adding a new index variable and splicing can lead to programmer error. Since you only need to remove from the front and add to the back, use the basic methods of arrays.
It seems to me the answer is 72. When you realize that rather than removing numbers you can skip them, the code becomes very short and straight-forward.
var chairArr = [];
for (var i = 1; i <= 100; i++)
chairArr.push(i);
for (i = 1; i < chairArr.length-2; i = i + 2)
chairArr.push(chairArr[i]);
console.log('--- Final result: ' + chairArr[i]);
What have you described here is the Josephus problem, and can be solved using dynamic programming:
function josephus(n, k)
{
if (n == 1) {
return 1;
} else {
return ((josephus(n-1, k) + k - 1) % n) + 1;
}
}
alert(josephus(100, 2));
Source: Wikipedia
The n denotes the number of chairs and k indicates every kth person leaving.
The result here is 73.
Update
Unfortunately, I didn't read the problem properly. The above code solves a slightly different problem; instead of killing off the first person in round one, the second person is killed instead. Being a survivor hinges on details :)
Solving your code problem is rather simple, start with the first person instead of the third in the first round.
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 0;
while (chairArr.length > 1) {
chairArr.splice(j, 1);
j = (j + 1) % n;
}
You don't need an iteration to find the result, there is a formula that can be use to obtain the final chair:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 || (input === 1 ? 0 : input)
}
And for the original Josephus problem, which you kill the even numbers instead, the formula can be simplified:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 + 1
}
The cool thing about the original problem, is that you can work with binary. For example:
100 = 1100100
Take the first '1' and place it to the last:
1001001 = 73

Categories