Kirk: October 2008 Archives

Another Update to my Mad Lib App

| | Comments (0) | TrackBacks (0)

My previous version of the mad lib app had a few problems. First of all, the story I wrote was terrible, and didn't even use all of the variables entered by the user. Related to that, I made it ask every question exactly three times, even though I didn't need three answers for each one. Furthermore, I wasn't very specific about the user input, and it didn't always work grammatically in my story. I've fixed all of that.


# Mad Lib
# madlib.rb
# Creates a mad lib based on user input

def ask part
input = gets.chomp.upcase
part.push input
end
verb = []
adj = []
obj = []
ly = []
job = []
puts 'Type in one verb, followed by a return:'
ask verb
puts 'Now, type in four adjectives, followed by return after each one:'
ask adj
ask adj
ask adj
ask adj
puts 'Now type in two everyday objects, followed by return after each one:'
ask obj
ask obj
puts 'Type in one adverb that ends in -ly:'
ask ly
puts 'Type in two job titles, such as "worker"'
ask job
ask job

puts 'One very ' +adj[0]+ ' day, a kind ' +job[0]+ ' went up to a ' +adj[1]
puts job[1]+ ' and asked to borrow some money to buy a ' +adj[2]+ ' ' +obj[0]+ ','
puts 'which he needed very badly. The ' +job[0]+ ' told him that he would lend'
puts 'the money only if the ' +job[1]+ ' would agree to ' +verb[0]+ ' a'
puts ly[0]+ ' ' +adj[3]+ ' ' +obj[1]+ '. The ' +job[0]+ ' decided it wasn\'t'
puts 'worth it.'

In my new version, I changed the user inputs to make them more specific. Instead of just asking for nouns, I ask for job titles and objects. Adverbs became an -ly adverb. The only place I see where it might not work out perfectly is if the adjectives start with vowel sounds, because the story has "a" before them, instead of "an." I could write a huge amount of code (probably equal to this entire program, as-is, if not more) just to account for this and automatically change the "a" to "an." I could also just ask people in the question to stick to consonants. But I don't think it really matters. It's a mad lib; "a orange tree" is to be expected.

The other issue is that by removing the code that automatically asks each question three times, I have to repeat the same lines of code for each time I want it asked. There are ways that I could code it so that I could pass it an additional variable—the number of times to ask the question—but my method is so short anyway (ask adj) that I don't think it would actually save any space.

Here is the code when run:


iMac:Ruby kirk$ Ruby madlib.rb
Type in one verb, followed by a return:
open
Now, type in four adjectives, followed by return after each one:
blue
clean
dirty
high
Now type in two everyday objects, followed by return after each one:
cup
phone
Type in one adverb that ends in -ly:
fetchingly
Type in two job titles, such as "worker"
serf
restaurateur
One very BLUE day, a kind SERF went up to a CLEAN
RESTAURATEUR and asked to borrow some money to buy a DIRTY CUP,
which he needed very badly. The SERF told him that he would lend
the money only if the RESTAURATEUR would agree to OPEN a
FETCHINGLY HIGH PHONE. The SERF decided it wasn't
worth it.

Age Quiz

| | Comments (0) | TrackBacks (0)

This is a follow-up to my first Ruby-related post. In that post, I mentioned potential additions to the code; I've since made those, and also cleaned it up a bit:


# Age Quiz
# agequiz.rb
# Asks user his name and when he was born. It then calculates
# the user's age, and offers different comments for kids, old
# people, and everyone else.

puts 'What is your name?'
name = gets.chomp
puts 'What year were you born in?'
year = gets.chomp
puts 'What month were you born in?'
month = gets.chomp
puts 'What day were you born on?'
day = gets.chomp
ageY = ((Time.new - Time.mktime(year,month,day))/31557600).to_i
puts 'Well, ' + name + ', you are ' + ageY.to_s + ' years old.'
if ageY < 18
puts 'Enjoy your youth while it lasts.'
elsif ageY >= 70
puts 'You\'re old. Get off the road.'
elsif
puts 'That means it\'s time to get a job!'
end


In the original code, it took four lines to get the age in years:

birthday = Time.mktime(year,month,day)
now = Time.new
ageSeconds = now - birthday
ageYears = ageSeconds/31557600

The "birthday," "now," and "ageSeconds" variables were completely unnecessary. They made it easier to work out exactly what was happening, but were wasteful. In the new version, it's just:

ageY = ((Time.new - Time.mktime(year,month,day))/31557600).to_i

I can then use this variable in a series of if/elsif statements that returns different results for different ages. I think it's funny.

The only thing that's still a problem is that it accepts only numerical input for the date, and doesn't have any built-in error handling. If someone types "March," instead of "3," it has no idea what to do. The easy solution would be to just tell people in the instructions to use numbers. To make it even easier for people, I could ask them to enter in their date of birth on a single line, using a provided format. Unfortunately, I don't yet know how to extract such an entry as three separate numbers. This first app may get visited yet again.

My Mad Libs Ruby App

| | Comments (0) | TrackBacks (0)

This post is really just so I can say how proud of myself I am. I just finished cleaning up my most advanced app to date, and felt like sharing.

A few days ago, I randomly got the idea to make a Mad Libs Ruby app. I knew that the code would involve a lot of repetition, which would involve the use of methods, but—while I had read about them—I hadn't actually learned how to use them yet. I instead decided to just write it with horribly inefficient code, and then clean it up. It would also serve to illustrate just how much code the final version would save. Here is the original version:


# Mad Lib
# madlib.rb

verb = []
adj = []
noun = []
adv = []
puts 'Type in three verbs, followed by return after each one:'
input = gets.chomp.upcase
verb.push input
input = gets.chomp.upcase
verb.push input
input = gets.chomp.upcase
verb.push input
puts 'Type in three adjectives, followed by return after each one:'
input = gets.chomp.upcase
adj.push input
input = gets.chomp.upcase
adj.push input
input = gets.chomp.upcase
adj.push input
puts 'Type in three nouns, followed by return after each one:'
input = gets.chomp.upcase
noun.push input
input = gets.chomp.upcase
noun.push input
input = gets.chomp.upcase
noun.push input
puts 'Type in three adverbs, followed by return after each one:'
input = gets.chomp.upcase
adv.push input
input = gets.chomp.upcase
adv.push input
input = gets.chomp.upcase
adv.push input
puts 'Thanks! Now I\'d like to tell you a story.'
puts 'One day a very ' + adj[0] + ' ' + noun[0] + ' went walking'
puts 'down the street. It came upon a ' + noun[1] + ' running ' + adv[0]
puts 'after a stranger sight. The ' + noun[0] + ' ' + verb[0] + 'ed a ' + noun[2]
puts 'with a ' + adj[1] + ' ' + noun[0] + '. But that\'s OK'
puts 'because he remembered to ' + verb[1] +'.'


It starts out by creating four empty arrays, for each part of speech. Then it gets ugly. The core part of the code is this:

input = gets.chomp.upcase
verb.push input


It creates the variable "input," then gets it from the user (and also chomps off the return and makes it into all caps, so that they stand out in the final story). It then pushes the input into the array for that part of speech (in this case, "verb"). The problem is that these two lines get repeated exactly the same two more times for each part of speech, and the only difference in the code for each part of speech is a single word, defining which array it goes into. That's twelve repetitions of two lines of code. Here is the new version:

def ask part
3.times do
input = gets.chomp.upcase
part.push input
end
end
verb = []
adj = []
noun = []
adv = []
puts 'Type in three verbs, followed by return after each one:'
ask verb
puts 'Type in three adjectives, followed by return after each one:'
ask adj
puts 'Type in three nouns, followed by return after each one:'
ask noun
puts 'Type in three adverbs, followed by return after each one:'
ask adv
puts 'Thanks! Now I\'d like to tell you a story.'

[The story part is the same as in the original, so I didn't repeat it here]

As you can see, I defined a new method, "ask." It gets the variable "part" (for "part of speech"). Since I ask each question twice, I added that to the definition. The core part of the code is the same as before, except that I use the "part" variable instead. Then for each part of speech, all I need to do is ask, and pass it which part of speech. For each question, six lines becomes two words, and all I added were six lines (two of which are just "end").

Of course, there's also the story itself. It's mostly just a placeholder right now. It doesn't even use all of the words the user inputs. I'll have to work on it. Also, there's one part where I just add an "-ed" on the end of a verb, but that doesn't work out very well for a lot of verbs. Of course, it's kind of amusing to see "RUNed," so maybe I'll keep it.

Here it is when I run it in Terminal:


kirk$ Ruby madlib.rb
Type in three verbs, followed by return after each one:
beat
steal
worship
Type in three adjectives, followed by return after each one:
blue
smelly
smooth
Type in three nouns, followed by return after each one:
desk
floor
shoe
Type in three adverbs, followed by return after each one:
silently
violently
nonchalantly
Thanks! Now I'd like to tell you a story.
One day a very BLUE DESK went walking
down the street. It came upon a FLOOR running SILENTLY
after a stranger sight. The DESK BEATed a SHOE
with a SMELLY DESK. But that's OK
because he remembered to STEAL.