From: Michael Morin Date: 2008-08-29T02:27:08+09:00 Subject: Re: Chris Pine Tutorial 99 Bottles of Beer Program Matthias Reitinger wrote: > Michael Morin 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][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., # NumberToWordsFunctions[2] 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