FAQ: Loops - The While Loop

It does. Thank you!:grinning:strong text

added some features:

const cards = ["\u2666", "\u2660", "\u2665", "\u2663"];

let currentCard;
let i=0;
while (currentCard != "\u2660") {
  currentCard = cards[Math.floor(Math.random() * 4)];
  console.log(currentCard);
  i++;
}
if (i===1){
    console.log("wow you soo lucky, you picked \u2660 right away");
} else {
  console.log("it took "+i+" times for you to pick spade");
}


7 Likes

For consistency, why not,

console.log(`it took ${i} tries for you to pick \u2660.`);

?

5 Likes

what’s the difference between condition while(!(currentCard === ‘spade’)) and while(currentCard != ‘spade’) ?
Thanks!

Very little difference, on the whole. They are both comparisons that yield the same outcome.

not (condition)

will be true if condition is false

 a !== b

will be true if a does not equal b.

I ran the code and got a tick on the box, and was allowed to continue, however my code is wrong. It takes a very long time to load (it did eventually load so I’m not sure if it’s an infinite loop). It also keeps logging to console even after it finds ‘spade’. Here is my code:
const cards = [‘diamond’, ‘spade’, ‘heart’, ‘club’];

// Write your code below
let currentCard=;

while (currentCard[0]!=‘spade’){
currentCard = cards[Math.floor(Math.random()*4)]
console.log(currentCard);
}

Edit: Ok, I fixed it. I made currentCard an array unnecessarily. Not sure exactly what was happening in code though. I guess it was setting, for eg. ‘diamond’ as a string array, rather than the string to check against. This is my fixed code:
const cards = [‘diamond’, ‘spade’, ‘heart’, ‘club’];

// Write your code below
let currentCard;
while (currentCard!=‘spade’){
let tempNum=Math.floor(Math.random()*4)
console.log(tempNum);
currentCard = cards[tempNum]
console.log(currentCard);
}

Hello, @ajax5863680087, and welcome to the forums.

This is worth exploring. First you assigned an empty array to currentCard, so in the first iteration of the while loop, the expression currentCard[0] != 'spade') evaluates to true, and the code inside the loop’s { } is executed. The first line of code inside that block reassigns a value to currentCard.
Whereas, currentCard previously pointed to an empty array, it now points to an element of the cards array that was assigned using a randomly generated index. Let’s say it was assigned 'spade'.
console.log(currentCard) would print spade to the console, and control is passed back to the while condition. The value assigned to currentCard is 'spade', so currentCard[0] is 's'. 's' is not equal to 'spade', so we continue the process over, and over, and over… forever.

4 posts were split to a new topic: These exact values will be copied in currentCard, or?

Ciao,
I’m starting to get confused. What’s the main difference between “for” and "while loop?

Thanks.

I tried adding to the code with the following:

const cards = [‘diamonds’, ‘spades’, ‘hearts’, ‘clubs’];
const cardNum = [2, 3, 4, 5, 6, 7, 8, 9, 10, ‘Jack’, ‘Queen’, ‘King’, ‘Ace’]

// Write your code below

let currentCardFace;
let currentCardNum;

while (currentCardFace != ‘spades’ && currentCardNum != ‘King’) {
currentCardFace = cards[Math.floor(Math.random() * 4)];
currentCardNum = cardNum[Math.floor(Math.random() * 13)];
console.log('You finally have been dealt the ’ + currentCardNum + ’ of ’ + currentCardFace);
}

My goal was to amend the task so that it would run through all combinations randomly until it reached the King of Spades. Anyone able to tell me what I’m doing wrong?

Segue approach…

 > f = Math.floor
<- ƒ floor() { [native code] }
 > r = Math.random
<- ƒ random() { [native code] }
 > suits = ['diamonds', 'spades', 'hearts', 'clubs']
<- (4) ["diamonds", "spades", "hearts", "clubs"]
 > ranks = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King', 'Ace']
<- (13) [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]
 > suit = ranks.length
<- 13
 > deck = suits.length
<- 4
 > card = f(r() * suit * deck)
<- 11
 > console.log(`${ranks[card % suit]} of ${suits[f(card / suit)]}`)
   King of diamonds
<- undefined
 > 

The deck has four suits and each suit has thirteen ranks.


Breakdown

The funny symbols are,

> : the input prompt of the Chrome JavaScript console. Those lines are commands we feed to the interpreter. They execute immediately.

<- : the response which is sometimes only an echo of the object that was just instanced.

The first couple of lines create alias’ for the two Math modules, floor and random in the interest of less typing and greater simplicity. No magic there.

The next couple of lines declare the two arrays, suits and ranks as global objects. Rather moot as we are at the command line. Everything is global that gets declared here. In a program scenario it would be more meaningful.

After that we measure the length of the two arrays and assign them accordingly.

Next we generate a single random number and coerce it to an integer that falls in the range, suit * deck. Our number will be for 13 ranks and 4 suits,

x = f(r() * suit * deck)
// { x | 0 <= x < suit * deck }

The final step will be to extract the two indices we seek for their respective arrays.

ranks[card % suit]

suits[f(card / suit)]

Notice that the latter makes a call to the floor function.

The purpose of this segue is not to dissuade you from your present goal. Definitely solve that one and make it meaningful to you as a learning experience. Above is one such other that you may or may not understand as a whole. That’s okay. Bookmark it and come back later.

Meanwhile, we could get back to focusing on your program’s approach and solve that. After you take another kick at the can check in with us.

1 Like

And now for a little silliness…

 > getCard = () => {
     return f(r() * suit * deck)
   }
<- () => {
     return f(r() * suit * deck)
   }
 > console.log(card = getCard(), `${ranks[card % suit]} of ${suits[f(card / suit)]}`)
   25 "Ace of spades"
<- undefined
 > 

Or more simply,

 > getCard = () => f(r() * suit * deck)
<- () => f(r() * suit * deck)
 > 
1 Like

I’m struggling to understand the idea that “for” loops fit for conditions with known number of iterations,
while “while” loops are for times when we don’t know how many times we’d have to iterate.
In the exercise it says something like: You don’t know how many bites you’ll need until you’re not hungry, so “bite while you’re hungry”!
But the same thing can go for a “for” loop: “For every bite, if you’re still hungry => bite”!
Explanation welcome!

Hello, @array4442330410.

It’s more a matter of using the best tool for a particular task. How many ways are there to get peas out of a can? You could probably come up with hundreds if you really put your mind to it, but there is a specific tool (or class of tools) especially suited to the task. In most cases, you could factor a loop using either for or while, but typically one is better suited than the other.

If you want to repeat a series of instructions while a specific condition persists, a while loop is probably a good way to go. If you want to repeat a series of instructions a specific number of times even if you don’t know how many times that is like iterating through a data structure (you may not know how many elements there are, but that information is available) then a for or forEach loop may be best.

1 Like

Hi, @midlinder,
Thanks for the reply.
I still don’t get it.
What is it that makes the for loop better for cases when you have a specific number of iterations?

Consider the following examples.

const arr = [...Array(20).keys()] //creates an array [0..19]

let forString = ''
for(let i = 0; i < arr.length; i++) {
  forString += arr[i] * 10 + ' '
}
console.log(forString)

let forEachString = ''
arr.forEach(e => {forEachString += e * 10 + ' '})
console.log(forEachString)

let whileString = ''
let i = 0
while(i < arr.length) {
  whileString += arr[i] * 10 + ' '
  i++
}
console.log(whileString)

All three loops do the same thing. Does it appear that the for loop or the .forEach method are a little better suited to the task of iterating through an array? The while loop works fine, and if you prefer to use while as opposed to for or .forEach, have at it. For the nonsensical task above, I’d use .forEach, but that’s simply my opinion.

2 Likes

You can’t say for every bite if you don’t know what the bites are until you’ve finished looping. Really what you’re saying there is “while you’re still hungry” and then you wrote “for” in front of that but no that doesn’t make sense and you’ll have trouble writing code corresponding to that, but if you do manage then what you’ll have created is a convoluted while-loop.

To illustrate @ionatan’s point, run the following code a few times, then write it using a for loop instead.

const amIHungry = () => [true, true, false, true][Math.floor(Math.random()*4)]
let bites = 0
while(amIHungry()) {
  bites += 1
}

console.log(bites)
1 Like

Being as that is in iterator territory, one might instead choose Array.map

 > [...Array(20).keys()].map(x => String(x * 10)).join(' ')
<- "0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190"
 >
1 Like

And here’s the convoluted while-loop of that:

const amIHungry = () => Math.random() < 0.75

function * bites () {
  while (amIHungry()) {
    yield true
  }
}

let biteCount = 0
for (let _ of bites()) {
  biteCount += 1
}
console.log(biteCount)

…which is just moving the while-loop. One could use this statement instead:

for (INIT; COND; AFTER) STATEMENT

And only use the COND part, but that would be … a while-loop
…which also brings us to that there isn’t just while and for, there are several different statements that begin with the keyword for, that doesn’t mean they’re all the same thing, they’re all separate things, as different as while and for

3 Likes