Chris Pine Tutorial 99 Bottles of Beer Program

D

danielj

Just a beginner with a question about this:

<i>• "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."</i>

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.
 
D

danielj

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

Todd Benson

Just a beginner with a question about this:

<i>=95 "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."</i>

This is what I came up with:

bottles =3D 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 =3D (bottles-1)

end

Is this ok?

Are there faster or better ways?

Have a look at the #downto method.

hth a little,
Todd
 
R

Ryan Davis

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.
 
J

James Gray

pls use interpolation:

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

is much more idiomatic... cleaner too.

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

James Edward Gray II
 
T

Todd Benson

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
 
M

Michael Fellinger

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'.

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

^ manveru
 
M

Michael Morin

Michael said:
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'.

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 < self ? " " + (self-i).to_english : '')
end
end

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

--
Michael Morin
Guide to Ruby
http://ruby.about.com/
Become an About.com Guide: beaguide.about.com
About.com is part of the New York Times Company
 
M

Matthias Reitinger

Michael said:
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][1] to deduce English numerals. The following program
produces the [full 99 Bottles of Beer lyrics][2] 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

[1]: http://www.deveiate.org/projects/Linguistics/
[2]: http://99-bottles-of-beer.net/lyrics.html
 
M

Michael Morin

Matthias said:
Michael said:
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][1] to deduce English numerals. The following program
produces the [full 99 Bottles of Beer lyrics][2] 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

[1]: http://www.deveiate.org/projects/Linguistics/
[2]: http://99-bottles-of-beer.net/lyrics.html

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.,
# <tt>NumberToWordsFunctions[2]</tt> 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} " + NumberToWordsFunctions[1].call( zero, y )
else
([zero] * 2).join(" ")
end
},

# Triple-digits
proc {|zero,x,y,z|
NumberToWordsFunctions[1].call(zero,x) +
NumberToWordsFunctions[2].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.

--
Michael Morin
Guide to Ruby
http://ruby.about.com/
Become an About.com Guide: beaguide.about.com
About.com is part of the New York Times Company
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,522
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top