0

JS newbie here looking for some advice. I've been working through the Head First JavaScript Programming book and it showed me how to log the '99 Bottles of Beer on the Wall' song to the console. Here is the original code:

var word = "bottles";
var count = 99;
while (count > 0) {
    console.log(count + " " + word + " of beer on the wall");
    console.log(count + " " + word + " of beer,");
    console.log("Take one down, pass it around,");
    count = count - 1;
    if (count > 0) {
        console.log(count + " " + word + " of beer on the wall.");
    } else {
        console.log("No more " + word + " of beer on the wall.");
    }
}

Without giving an answer, it suggests that the code is okay but not 100% right, and asks if you can find the flaw and fix it. After looking in the console, I discovered that the while loop doesn't take into consideration that the word "bottles" needs to change to "bottle" once you get down to one bottle of beer in the song. I've added some if statements to the loop to make the var word change to "bottle" when needed. The code appears to work correctly now:

var word = "bottles";
var count = 99;
while (count > 0) {
  if (count == 1){
    var word = "bottle"
  }
    console.log(count + " " + word + " of beer on the wall");
    console.log(count + " " + word + " of beer,");
    console.log("Take one down, pass it around,");
    count = count - 1;
    if (count > 0) {
      if (count == 1){
        var word = "bottle"
      }
        console.log(count + " " + word + " of beer on the wall.");
    } else {
      if (count < 1){
        var word = "bottles"
      }
        console.log("No more " + word + " of beer on the wall.");
    }
}

My question is this - is there a better, or more succinct way to do this than my attempt? I have a feeling my attempt is a bit messy. I know that you can use a For loop for this, but the example used a While loop, so I'd like to stick with that, if possible.

Many thanks!

Simon Revill
  • 117
  • 1
  • 13

7 Answers7

1

You can tidy up your logic a bit by replacing those bulky if else statements with concise ternary expressions:

while (count > 0) {
    var bottle = count == 1 ? "bottle" : "bottles";
    console.log(count + " " + word + " of beer on the wall");
    console.log(count + " " + word + " of beer,");
    console.log("Take one down, pass it around,");
    --count;
    var bottle = count == 1 ? "bottle" : "bottles";
    console.log(count + " " + word + " of beer on the wall.");
}

This makes a grammatical assumption that the phrase 0 bottles of beer on the wall is correct and is what we want to use. This sounds right to me, but I guess technically both 0 or 1 bottle should be singular.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • I see you're using a ternary operator. I know about that (kind of) but I haven't full learned about it yet. I will make a note of this - thanks so much for taking the time to answer my question. – Simon Revill Feb 07 '18 at 11:41
0

Since you want to stick close to the example I'll point out only that you could skip

if (count < 1){
    var word = "bottles"
  }

if you change

 if (count == 1){
    var word = "bottle"
  }

into

if (count == 1){
    word = "bottle"
  }

and place the var declaration here:

while (count > 0) {
    var word = "bottles";

There's plenty of other things you could shorten too but that might make it a bit more difficult.

Asgeirr
  • 82
  • 10
0

A possibility is to just extract the entire bottle word stuff into a separate function. that way, you merely need to change anything from the original code

var count = 99;
while (count > 0) {
    console.log(count + " " + getBottleWord(count) + " of beer on the wall");
    console.log(count + " " + getBottleWord(count) + " of beer,");
    console.log("Take one down, pass it around,");
    count = count - 1;
    if (count > 0) {
        console.log(count + " " + getBottleWord(count) + " of beer on the wall.");
    } else {
        console.log("No more " + getBottleWord(count) + " of beer on the wall.");
    }
}

function getBottleWord(count) {
    return count === 1 ? "bottle" : "bottles";
}
Nicolas Gehlert
  • 2,626
  • 18
  • 39
0

Well, you could rework the if-else statements into something more succint, like:

var word = "bottles";
var count = 99;
while (count > 0) {
    console.log(count + " " + word + " of beer on the wall");
    console.log(count + " " + word + " of beer,");
    console.log("Take one down, pass it around,");
    count = count - 1;
    if (count > 1) {
        console.log(count + " " + count + " of beer on the wall.");
    } else if(count == 1) {
        console.log(count + " bottle of beer on the wall."); 
    } else {
        console.log("No more " + word + " of beer on the wall.");
    }
}

But the part worth pointing in your question is: BEWARE of the multiple var word = "bottles" sentences, and, in general, use of the var keyword and its caveats, especially in regards to its scope. For example, consider the difference between var and let and their respective scopes.

cosh
  • 470
  • 1
  • 4
  • 15
  • Thanks. I did consider just writing " bottle of beer on the wall." Guess I just wanted to see if I could modify the variable as well. Also like you said, I think the use of the let variable would be more suitable here. – Simon Revill Feb 07 '18 at 18:48
0
// Instead of var you can start using 'const' for variables that will not be changed
// and 'let' for variables that will be changed.
let word = "bottles";
let count = 99;
while (count > 0) {
    if (count == 1){
        // No need to recall 'var' here, you are reassigning an existing var not creating a new one.
        // Can just do:
        // word = "bottle"
        word = "bottle"
    }
    /* As of ES6 You can use string templets here:
     *
     * console.log(`${count} ${word} of beer on the wall`);
     * console.log(`${count} ${word} of beer,`);
     * console.log("Take one down, pass it around,");
     */
    console.log(count + " " + word + " of beer on the wall");
    console.log(count + " " + word + " of beer,");
    console.log("Take one down, pass it around,");

    count = count - 1;
    /* For the word changing, you can lose some code by not actually changing the string,
     * That way you will not need to reassign it back to plural again when the count is 0
     * To take the 'bottles' string without the final plural 's' character use:
     * word.slice(0,-1);
     */
    if (count > 0) {
      if (count == 1){
        console.log(count + " " + word.slice(0, -1) + " of beer on the wall.");
      }
    } else {
        // now you can lost this if statment.
        console.log("No more " + word + " of beer on the wall.");
    }
}
CodeAt30
  • 874
  • 6
  • 17
0

You could use recursion to call the same function with less bottles until you get to 0 count

const pluralize = (i, word) => word + (i > 1 ? 's': '')
  
const bottles = count => {
  console.log(`${count} ${pluralize(count, 'bottle')} of beer on the wall.`)
  console.log(`${count} ${pluralize(count, 'bottle')} of beer.`)
  console.log(`Take one down, pass it around`)
  if (count > 1) {
    console.log(`${count - 1} ${pluralize(count - 1, 'bottle')} of beer on the wall.`)
    bottles(count - 1) // recursively call the bottles function with one less bottle
  }
  else {
    console.log(`No more bottles of beer on the wall.`)
  }
}

bottles(12)
synthet1c
  • 6,152
  • 2
  • 24
  • 39
  • Great, thanks. I'm still new, not quite there yet with functions, but I'll be sure to look back at this suggestion once I'm more familiar. – Simon Revill Feb 07 '18 at 18:49
  • recursion can seem mind bending, but it's just calling the same function again and again with different arguments until to don't meet some condition. If you're just starting it might take you a year or two to get to recursion. enjoy the adventure into programming. – synthet1c Feb 08 '18 at 07:19
-1

I did it this way:

var word="bottles";
var count=99;
while (count>1) {
    console.log(count + " " + word + " of beer on the wall");
    console.log(count + " " + word + " of beer,");
    console.log("Take one down, pass it around,");
    count=count-1;
    
    if (count>1) {
        console.log(count + " " + word + " of beer on the wall.");
    }
    if (count==1) {
        console.log(count + " bottle" + " of beer on the wall.");
        console.log(count + " bottle" + " of beer on the wall,");
        console.log(count + " bottle" + " of beer");
        console.log("Take one down, pass it around,");
        count=count-1;
    }
    if (count==0) {
        console.log("No more " + word + " of beer on the wall.");
        
    }
}
Ina
  • 1