For whatever reason, I thought of a practice problem that we did at Turing today of writing something that will print the song “99 Bottles of Beer”. I think it was a reference someone made to redoing flashcards? I don’t know, it’s not important. Anyway, I went looking for it on my computer because I am pretty sure I could do it better now (at least I hope so), and couldn’t find it, so I redid it to practice loops in Ruby. And then I did it in Go as well, because why not.
I *think* the first time I did it, we made a function. But it seems like there should be an easier way, so here are a couple of ways to do it in ruby, with some thoughts. The easiest thing seemed to be a while loop
bottles = 99
while bottles > 0
puts "#{bottles} bottle#{'s' if bottles != 1} of beer on the wall, #{bottles} bottle#{'s' if bottles != 1} of beer."
bottles -= 1
puts "Take one down and pass it around, #{bottles > 0 ? bottles : 'no more'} bottle#{'s' if bottles != 1} of beer on the wall."
puts
end
puts "No more bottles of beer on the wall, no more bottles of beer."
puts "Go to the store and buy some more, 99 bottles of beer on the wall."
Pretty straight forward, if bottles is greater than 0, it will output the number of bottles with interpolation with a check whether or not it should be bottles (greater than 1) or bottle (singular).
Next, bottles needs to subtract 1, and then it gives you the next line, with a check for whether or not bottles should be singular, or if it is 0 and it should be no more bottles.
And then the while loop makes it repeat until bottles is no longer greater than 0 and then it goes to the end.
This {bottles > 0 ? bottles : 'no more'} is the ternary way of giving you an if/else statement , if the condition bottles > 0 then it will return bottles; otherwise will return 'no more'
If you wanted to use a for loop, it could be like this
for bottles in (99).downto(1)
puts "#{bottles} bottle#{'s' if bottles != 1} of beer on the wall, #{bottles} bottle#{'s' if bottles != 1} of beer."
puts "Take one down and pass it around, #{bottles - 1 > 0 ? bottles - 1 : 'no more'} bottle#{'s' if bottles - 1 != 1} of beer on the wall."
puts
end
puts "No more bottles of beer on the wall, no more bottles of beer."
puts "Go to the store and buy some more, 99 bottles of beer on the wall."
Same basic concept, except it is using for and then going down to 1. The main difference being that you check the condition with while and in the for loop you use a built in ruby method downto to automatically decrease it.
I think that using for and downto is more idiomatic, but please correct me if I’m wrong.
This one uses the each method, but is pretty similar to the previous. I think it might be slightly more idiomatic? It’s more readable (for me)
(99).downto(1).each do |bottles|
puts "#{bottles} bottle#{'s' if bottles != 1} of beer on the wall, #{bottles} bottle#{'s' if bottles != 1} of beer."
puts "Take one down and pass it around, #{bottles - 1 > 0 ? bottles - 1 : 'no more'} bottle#{'s' if bottles - 1 != 1} of beer on the wall."
puts
end
puts "No more bottles of beer on the wall, no more bottles of beer."
puts "Go to the store and buy some more, 99 bottles of beer on the wall."
The main thing I think I didn’t know then but know now is how to comfortably use string interpolation with conditionals.
Anyway, onto Go.
I wanted to practice using switch cases, because I hadn’t used them too often in Ruby, but at BlockFrame used them a lot.
package main
import (
"fmt"
)
func main() {
for bottles := 99; bottles >= 0; bottles-- {
switch bottles {
case 0:
fmt.Println("No more bottles of beer on the wall, no more bottles of beer.")
fmt.Println("Go to the store and buy some more, 99 bottles of beer on the wall.")
case 1:
fmt.Printf("%d bottle of beer on the wall, %d bottle of beer.\n", bottles, bottles)
fmt.Println("Take one down and pass it around, no more bottles of beer on the wall.\n")
default:
fmt.Printf("%d bottles of beer on the wall, %d bottles of beer.\n", bottles, bottles)
fmt.Printf("Take one down and pass it around, %d bottles of beer on the wall.\n\n", bottles-1)
}
}
}
This starts out with a for loop, and bottles is 99. It is going to decrease the value by 1 (that is what bottles-- does) on each iteration. As long as it is greater than or equal to 0, it keeps going.
The switch statement is used to evaluate the value of bottles and match it to different cases. So if bottles are 0, then it goes with case 0, and prints that. If bottles == 1, then it will trigger case 1, and print the singular. Otherwise, it is going to run default, and go about it that way until it gets down to 1. Default tends to be last so it can be a catch-all for anything that doesn’t trigger another case. It is sequential, so the specific cases will be checked first, and then if none of those match, you get the default case.
Here it is written in Go without the switch cases, but I think it’s slightly easier to read with the switch cases
package main
import (
"fmt"
)
func main() {
for bottles := 99; bottles > 0; bottles-- {
if bottles == 1 {
fmt.Printf("%d bottle of beer on the wall, %d bottle of beer.\n", bottles, bottles)
fmt.Println("Take one down and pass it around, no more bottles of beer on the wall.\n")
} else {
fmt.Printf("%d bottles of beer on the wall, %d bottles of beer.\n", bottles, bottles)
if bottles-1 == 1 {
fmt.Printf("Take one down and pass it around, %d bottle of beer on the wall.\n\n", bottles-1)
} else {
fmt.Printf("Take one down and pass it around, %d bottles of beer on the wall.\n\n", bottles-1)
}
}
}
fmt.Println("No more bottles of beer on the wall, no more bottles of beer.")
fmt.Println("Go to the store and buy some more, 99 bottles of beer on the wall.")
}
Well, I should get back to the other things I was supposed to do today, but this was kind of a fun distraction. I hope wordpress doesn’t screw up the indentation in the code blocks, if that happens, let me know!
Leave a Reply