Chris Pine Tutorial 99 Bottles of Beer Program

Just a beginner with a question about this:

• “99 bottles of beer on the wall…” Write a program which prints
out the lyrics to that beloved classic, that field-trip favorite: “99
Bottles of Beer on the Wall.”

This is what I came up with:

bottles = 100

while bottles > 1

puts (bottles-1).to_s + " Bottles of beer on the wall, " +
(bottles-1).to_s + " Bottles of beer! You take one down, you pass it
around and " + (bottles-2).to_s + " Bottles of beer on the wall!"

bottles = (bottles-1)

end

Is this ok?

Are there faster or better ways?

Thanks.

Also, would there be an easy way to print the words out instead of the
numbers of bottles on the wall?

On Tue, Aug 26, 2008 at 6:30 PM, danielj [email protected]
wrote:

while bottles > 1

Are there faster or better ways?

Have a look at the #downto method.

hth a little,
Todd

On Aug 26, 2008, at 16:30 , danielj wrote:

puts (bottles-1).to_s + " Bottles of beer on the wall, " +

pls use interpolation:

 puts "#{bottles-1} bottles of beer on the wall"

is much more idiomatic… cleaner too.

On Aug 26, 2008, at 7:45 PM, Ryan D. wrote:

On Aug 26, 2008, at 16:30 , danielj wrote:

puts (bottles-1).to_s + " Bottles of beer on the wall, " +

pls use interpolation:

puts “#{bottles-1} bottles of beer on the wall”

is much more idiomatic… cleaner too.

I agree. I really wish Chris P.'s book taught this, but it does not.

James Edward G. II

On Tue, Aug 26, 2008 at 6:30 PM, danielj [email protected]
wrote:

Also, would there be an easy way to print the words out instead of the
numbers of bottles on the wall?

Divide the number by 10 and it will give the prefix (ninety-, eighty-,
etc.) You need a list or hash of some sort, of course. Simple
example…

prefixes = {9 => “ninety-”, 8 => “eighty-”}

…or even better…

prefixes = [“”, “”, “twenty-”, “thirty-”, “forty-”]

…and so on. And then modify the numbers ten through nineteen after
the transformation (you don’t want “one” for “eleven” do you) since
they differ in nomenclature from the others.

You could automagically use suffixes instead of prefixes if the
number, when divided by 10 is 1, but that wouldn’t help you with the
edge cases of ‘ten’, ‘eleven’, and ‘twelve’.

Todd

Todd

Michael F. wrote:

…or even better…

http://p.ramaze.net/1900
my stab at it

^ manveru

I did something slightly different, which works on multiple levels, not
just two. For example, it can go all the way up to 999 without any
extra code.

#!/usr/bin/env ruby

class Fixnum
ENGLISH = {
0 => ‘zero’,
1 => ‘one’,
2 => ‘two’,
3 => ‘three’,
4 => ‘four’,
5 => ‘five’,
6 => ‘six’,
7 => ‘seven’,
8 => ‘eight’,
9 => ‘nine’,

 10 => 'ten',
 11 => 'eleven',
 12 => 'twelve',
 13 => 'thirteen',
 14 => 'fourteen',
 15 => 'fifteen',
 16 => 'sixteen',
 17 => 'seventeen',
 18 => 'eighteen',
 19 => 'ninteen',

 20 => 'twenty',
 30 => 'thirty',
 40 => 'forty',
 50 => 'fifty',
 60 => 'sixty',
 70 => 'seventy',
 80 => 'eighty',
 90 => 'ninety',

 100 => 'one hundred and',
 200 => 'two hundred and',
 300 => 'three hundred and',
 400 => 'four hundred and',
 500 => 'five hundred and',
 600 => 'six hundred and',
 700 => 'seven hundred and',
 800 => 'eight hundred and',
 900 => 'nine hundred and'

}

def to_english
i = ENGLISH.keys.select{|n| n <= self}.max
ENGLISH[i] + (i < self ? " " + (self-i).to_english : ‘’)
end
end

99.downto(1) do|i|
puts “#{i.to_english} bottles of beer on the wall”
end

On Wed, Aug 27, 2008 at 9:57 AM, Todd B. [email protected]
wrote:

…or even better…

prefixes = [“”, “”, “twenty-”, “thirty-”, “forty-”]

…and so on. And then modify the numbers ten through nineteen after
the transformation (you don’t want “one” for “eleven” do you) since
they differ in nomenclature from the others.

You could automagically use suffixes instead of prefixes if the
number, when divided by 10 is 1, but that wouldn’t help you with the
edge cases of ‘ten’, ‘eleven’, and ‘twelve’.

http://p.ramaze.net/1900
my stab at it

^ manveru

Michael M. wrote:

I did something slightly different, which works on multiple levels, not
just two. For example, it can go all the way up to 999 without any
extra code.

[…]

Unfortunately your implemention fails with multiples of 100.

Being the lazy guy I just used the excellent Ruby Lingustics
Framework
to deduce English numerals. The following program
produces the full 99 Bottles of Beer lyrics with numerals:


require ‘Linguistics’
Linguistics::use(:en)

class Fixnum
def bottles
case self
when 0: “no more bottles”
when 1: “one bottle”
else “#{self.en.numwords} bottles”
end
end
end

99.downto(0) do |n|
puts “#{n.bottles.capitalize} of beer on the wall, #{n.bottles} of
beer.”
if n > 0
puts “Take one down and pass it around, #{(n-1).bottles} of beer on
the wall.”
puts
else
puts “Go to the store and buy some more, #{99.bottles} of beer on
the wall.”
end
end

Regards,
Matthias

Hello all, this is what I came up with, works great.

bottles_of_beer = 99
while bottles_of_beer > 1
puts bottles_of_beer.to_s + ’ bottles of beer on the wall, ’ +
bottles_of_beer.to_s + ’ bottles of beer’
bottles_of_beer = bottles_of_beer - 1
puts ‘You take one down, pass it around, ’ + bottles_of_beer.to_s + ’
bottles of beer on the wall.’
puts ‘’
end

puts ‘Everyone passes out quite drunk.’

Matthias R. wrote:

Framework]1 to deduce English numerals. The following program
when 1: “one bottle”
the wall."

So it does. Just drop the “and” from the strings and it’s still
technically correct. Things could be better if I had special cases for
things like that, but I didn’t want to complicate the code.

Nothing lazy about using libraries. Linguistics takes a different
approach though. They have three different procs stored in an array for
the number of digits in the number.

A collection of functions for transforming digits into word

phrases. Indexed by the number of digits being transformed; e.g.,

NumberToWordsFunctions2 is the function for transforming

double-digit numbers.

NumberToWordsFunctions = [
proc {|*args| raise “No digits (#{args.inspect})”},

Single-digits

proc {|zero,x|
(x.nonzero? ? to_units(x) : "#{zero} ")
},

Double-digits

proc {|zero,x,y|
if x.nonzero?
to_tens( x, y )
elsif y.nonzero?
“#{zero} " + NumberToWordsFunctions1.call( zero, y )
else
([zero] * 2).join(” ")
end
},

Triple-digits

proc {|zero,x,y,z|
NumberToWordsFunctions1.call(zero,x) +
NumberToWordsFunctions2.call(zero,y,z)
}
]

That’s quite clever. Each proc calls the previous proc. Mine relied on
recursion and subtraction instead of separating the digits. Doing it
this way gives you an easy way to implement the special cases.

On Tue, Mar 26, 2013 at 2:00 AM, Phil H. [email protected] wrote:

puts ‘Everyone passes out quite drunk.’

def beersong(n=99)
n.downto(1) do |i|
puts <<SONG
#{i} bottles of beer on the wall,
#{i} bottles of beer!
Take one down, pass it around,
#{i > 2 ? i-1 : “no more”} bottles of beer!

SONG
end
puts “… and they all fell down drunk!”
end

On Tue, Mar 26, 2013 at 7:08 AM, tamouse mailing lists
[email protected] wrote:

end

puts ‘Everyone passes out quite drunk.’

def beersong(n=99)
n.downto(1) do |i|
puts <<SONG
#{i} bottles of beer on the wall,
#{i} bottles of beer!
Take one down, pass it around,
#{i > 2 ? i-1 : “no more”} bottles of beer!

AAUGH, off by one:

#{i>1 ? i-1 : “No more”} bottles of beer!

You should, as previously stated, use #downto.
You’re also repeatedly calling to_s. Either use interpolation or just do
bottles_of_beer.to_s! before adding it to other strings.

On Tue, Mar 26, 2013 at 3:11 AM, Joel P. [email protected]
wrote:

You should, as previously stated, use #downto.
You’re also repeatedly calling to_s. Either use interpolation or just do
bottles_of_beer.to_s! before adding it to other strings.

Fixnum#to_s! doesn’t exit.

Who’s thirsty?

Josh C. wrote in post #1103316:

On Tue, Mar 26, 2013 at 3:11 AM, Joel P. [email protected]
wrote:

You should, as previously stated, use #downto.
You’re also repeatedly calling to_s. Either use interpolation or just do
bottles_of_beer.to_s! before adding it to other strings.

Fixnum#to_s! doesn’t exit.

I stand corrected! In that case, “bottles_of_beer =
bottles_of_beer.to_s”
Either way, interpolation looks clearer and neater.

This problem with this and other examples are people are offering
solution and techniques that have not been taught yet. I’m using the
same book, Chris P.'s, Learn to Program.

I feel if offering help, one should offer help based on the knowledge
imparted thus far, even if more complicated than it should be. For
instance with downto, when the challenge is given in the book, that
method hasn’t been talked about or even mentioned in passing. It
shouldn’t be given as a solution for people at that step in the book.
I’m trying to learn as well, and this sort of thing is the hardest when
seeking out help online.

its most interesting because tips demonstrate in ruby how to build
succinct
and penetrating code. good tips are a godsend also coaching creates the
culture.

On Thu, Mar 28, 2013 at 9:33 AM, Phil H. [email protected] wrote:

This problem with this and other examples are people are offering
solution and techniques that have not been taught yet. I’m using the
same book, Chris P.'s, Learn to Program.

One of the big problems with asking questions in an anonymous mailing
list is expecting the people answering to be your teacher. If you’re
really at that level and need that much handholding, take a class, or
find a tutor, but if you shout out a question into a large space where
you know no one and no one knows you, stop complaining about the
answers.