Life as Clay

Learn to Program: English numbers meet the beer song

leave a comment »


This one is quite simple and only took me a few minutes to put together, since it combines the previous entry with the 99 Bottles of Beer on the Wall song. That said, I learned a lesson while doing it, which I guess is the important part.

If you look at the code you’ll see that I use a ‘while’ clause to iterate through the verses. The number decrements at the end of each verse. It works great.

The first time I implemented it, I did it recursively, calling the beersong method on the decremented number at the end of each verse… Wrong! The recursion creates nested method calls and ends up causing a stack overflow due to unnecessary memory usage.

The moral of the story is to only use recursion when necessary. In this case, a simple loop was the best way to tackle the problem.

def english_number number
  ones  = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']
  teens = ['ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'ninteen']
  tens  = ['ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']
  
  readout = ''
  working = number.to_i
  
  # The idea here... create the variable m_count to check if the input number is over def over 
  # one million. If it is, recurse m_count (which will be less than 1000) through the method
  # to generate the number of millions. Then, tack " million " onto the end of it and change 
  # the working number to what it originally was, minus the number of millions. Then create
  # the variable t_count to check the number of thousands in the remainder and repeat the process.
  # Once the remainder is under 1000, we do not recurse again. You can easily expand this for billions
  # and higher numbers by copying the case for millions, creating a new 'billions' variable, then
  # pulling the same trick and tacking " billion " onto the end of the number returned.
  
  if working > 999999999
    puts 'Enter a number under 1 billion.'
    return
  end
  
  # Case for millions
  m_count = working / 1000000
  if m_count >0
    millions = english_number m_count
    readout = readout + millions + ' million'
    working = working - (m_count * 1000000)
    
    if working > 0
      readout = readout + ' '
    end
    
  end
  
  # Case for thousands
  t_count = working / 1000
  if t_count >0
    thousands = english_number t_count
    readout = readout + thousands + ' thousand'
    working = working - (t_count * 1000)
    
    if working > 0
      readout = readout + ' '
    end
    
  end
  
  # Case for hundreds
  h_count = working / 100
  if h_count > 0
    hundreds = ones[h_count - 1]
    readout = readout + hundreds + ' hundred'
    working = working - (h_count * 100)
    
    if working > 0
      readout = readout + ' '
    end
    
  end
  
  # Case for over 20 and less than 100
  if working < 100 and working >= 20
    ten_count = working / 10
    working = working - (ten_count * 10)
    readout = readout + tens[ten_count -1]
    
    if working > 0
      readout = readout + '-'
    end
    
  end
  
  # Case for teens
  if working >= 10 and working < 20
    working = working - 10
    readout = readout + teens[working]
    working = 0
  end
  
  # Case for singles
  if working > 0 and working < 10
    readout = readout + ones[working -1]
  end
  
  if readout == '' and working == 0
    readout = 'zero'
  end
  
  readout
  
end

def beersong number
  
  start = number
  
  while start > 0
  
    sing = english_number(start)
    decrement = english_number(start - 1)
  
    puts
  
    if start == 1
      puts sing + ' bottle of beer on the wall,'
      puts sing + ' bottle of beer...'
    else
      puts sing + ' bottles of beer on the wall,'
      puts sing + ' bottles of beer...'
    end
  
    puts 'take one down,'
    puts 'pass it around,'
  
    if (start - 1) == 1 
      puts decrement + ' bottle of beer on the wall!'
    else
      puts decrement + ' bottles of beer on the wall!'
    end
  
    puts
  
    start -= 1 # Here I originally called beersong recursively and that was wrong. 
  end
  
  return
  
end

puts 'Enter a number: '

number = gets.chomp.to_i

beersong number
Advertisements

Written by Clay

October 14, 2009 at 01:46

Posted in Code, Ruby

Tagged with , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: