Keeping it Small and Simple

2007.12.06

A simple vocabulary tester in Ruby

Filed under: Ruby Programming — Lorenzo E. Danielsson @ 13:01

One of the things I love about programming is that you can quickly put together a little tool to help you out with something. For example, if you are studying a foreign language you would have to memorize a lot of vocabulary. You could put together a quick and dirty vocabulary trainer in almost no time at all.

I am going to show you how you can evolve a very simple vocabulary trainer. At the end, you should have a little program that you can actually use. But there is a lot more you could decide to do with it. I will list some ideas for exercises at the end of the post.

First of all, we need to store some terms that we will test ourselves on. We want a few English words (at least in our example, feel free to use any other language), mapped to their corresponding translations into the language under study (Ga in this example). A simple way to do this is to use a Hash. Let’s put together a simple test program just to make sure we’ve understood how to use the Hash.


 1 #! /usr/bin/ruby -w
 2
 3 # Store some words and their translations in a hash and output them.
 4 # Author: Lorenzo E. Danielsson
 5
 6 words = {
 7   Monday => Ju,
 8   Tuesday => Jufɔ,
 9   Wednesday => Shɔ,
10   Thursday => Soo,
11   Friday => Sohaa,
12   Saturday => Hɔɔ,
13   Sunday => Hɔgbaa
14 }
15
16 words.each { |word, trans|
17   puts "#{word} is called #{trans}"
18 }

So far so good. Now we have a program that prints out words in English and their translations into Ga. Actually, couldn’t we be a bit more friendly and specify the language that we are translating to. And while we’re at it, since we intend to turn the program into a quiz, wouldn’t it be nice if we could shuffle the words around a bit so that we don’t always get asked the questions in the same order? Well, we can:


 1 #! /usr/bin/ruby -w
 2
 3 # Store some words and their translations in a hash and output them.
 4 # Author: Lorenzo E. Danielsson
 5
 6 lang = "Ga"
 7 words = {
 8   Monday => Ju,
 9   Tuesday => Jufɔ,
10   Wednesday => Shɔ,
11   Thursday => Soo,
12   Friday => Sohaa,
13   Saturday => Hɔɔ,
14   Sunday => Hɔgbaa
15 }
16
17 words.keys.sort_by { rand }.each { |key|
18   puts "#{key} is called #{words[key]} in #{lang}"
19 }
20

Good, now we are ready to solve the original task. What we need to do is ask the user for the translation of each word, capture their input and compare it to what is stored in the Hash. That could look something like this:


 1 #! /usr/bin/ruby -w
 2
 3 # A simple vocabulary tester.
 4 # Author: Lorenzo E. Danielsson
 5
 6 lang = "Ga"
 7 words = {
 8   Monday => Ju,
 9   Tuesday => Jufɔ,
10   Wednesday => Shɔ,
11   Thursday => Soo,
12   Friday => Sohaa,
13   Saturday => Hɔɔ,
14   Sunday => Hɔgbaa
15 }
16             
17 words.keys.sort_by { rand }.each { |key|
18   print "What is #{key} called in #{lang}? "
19   puts gets.chomp == words[key] ? "Correct" : "Incorrect"
20 }
21

There we go! We now have a program that tests our knowledge of the weekdays in Ga. Of course, we may want to keep a track of how many answers we got right as well. Let’s add a counter.


 1 #! /usr/bin/ruby -w
 2
 3 # A simple vocabulary tester.
 4 # Author: Lorenzo E. Danielsson
 5
 6 lang = "Ga"
 7 words = {
 8   Monday => Ju,
 9   Tuesday => Jufɔ,
10   Wednesday => Shɔ,
11   Thursday => Soo,
12   Friday => Sohaa,
13   Saturday => Hɔɔ,
14   Sunday => Hɔgbaa
15 }
16             
17 score = 0
18 words.keys.sort_by { rand }.each { |key|
19   print "What is #{key} called in #{lang}? "
20   if gets.chomp == words[key]
21     puts "Correct"
22     score += 1
23   else
24     puts "Incorrect"
25   end
26 }
27
28 puts "Score: #{score}/#{words.length}"

With this latest version we can see how well we did in the end. But come to think of it, wouldn’t it be cool if the program “remembered” our mistakes and kept asking us those questions again and again until we got them right? Not a problem. Of course, that means that our score-keeping mechanism becomes rather pointless (look in the exercises for an example of an alternative way of providing some statistics at the end).


 1 #! /usr/bin/ruby -w
 2
 3 # A simple vocabulary tester.
 4 # Author: Lorenzo E. Danielsson
 5
 6 lang = "Ga"
 7 words = {
 8   Monday => Ju,
 9   Tuesday => Jufɔ,
10   Wednesday => Shɔ,
11   Thursday => Soo,
12   Friday => Sohaa,
13   Saturday => Hɔɔ,
14   Sunday => Hɔgbaa
15 }
16             
17 score = 0
18 until words.empty?
19   words.keys.sort_by { rand }.each { |key|
20     print "What is #{key} called in #{lang}? "
21     if gets.chomp == words[key]
22       puts "Correct"
23       words.delete(key)
24     end
25   }
26 end
27
28 puts "Done"

The latest version keeps looping as long as there are words in the hash. Each time the user gets a word right, it is removed from the hash.

Okay, I’m done. What? Why no fancy GUI? Why not extract the words from a dictionary file? Why not a web-based application? Er.. sorry, but no, not this time. But look at the exercises below.

I hope I have been able to demonstrate how simple it can be to write programs if you take it step by step. It sometimes amazes me how many of my students try to write an entire program without testing. I always break a problem into small, easily manageble tasks. After I complete a task, I test to make sure the program works up to that point.

Exercises

If you feel like a little extra practice you can go through some of these exercises. I have tried to vary the level of complexity so that some will be a little more challenging than others. Feel free to post your solutions. If you would like me to take a look at your code and send you feedback, you can mail me at danielsson dot lorenzo at geemale dot com (I think you can figure the ‘geemale’ part out).

1. The last version of the program doesn’t give the user any indication of how well they did. If we had score like we previously did, we would always end up with 7/7, unless we use some form of scoring that changes each time we have iterated over the hash. Another alternative is to keep a track of how many guesses it took the user to guess each word. You would then need A hash that holds the words and the number of tries the user required. You would also need a counter that increases every time the until loop has completed a cycle. At the end of the program, output print all the words in the word list and how many tries the user needed.

2. Make the program be able to ask the user to translate in both directions (Ga to English as well as English to Ga). Let the program ask the user at the beginning which language he wants to practice translating to.

3. In order to shuffle the hash elements around, I used words.keys.sort_by { rand }. See if you can add a Hash#shuffle method that moves hash elements around randomly. Then use Hash#shuffle instead of Hash#keys.sort_by { rand }.

4. Turn the program into OO. Decide what “things” make up the program and how these things function. Abstract the things into classes an the functionality of each thing into methods.

5. Extend the program to be able to read some form of “dictionary” file. I suggest you keep it simple to begin with. You could have a file that looks something like the following:
Monday: Ju
Tuesday: Jufɔ

Once you have that working you could create something more complex, like an XML file. You could even let the file contain meta-information, such as languages, the “type” of words it contains (weekdays in our example) and so on.

6. Extend the program in the previous exercise to also allow you to manage your word list. The program should present a menu to the user giving options like “add words to list”, “quiz” and “exit”. Make sure the new words are added to the file. By now, the program is growing in complexity to a point where you really should sit down and plan the application a bit before coding.

7. If you know any GUI toolkit, such as Gtk, Qt or Tk, write a GUI version of the program.

8. Go crazy. Write a multi-user web based version of the vocubulary tester that stores word lists in a database, allows individual users to put together their own tests and keeps historical statistics for each user. Make it handle multiple languages.

9. [ Add your own exercise 😉 ]

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

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

Create a free website or blog at WordPress.com.

%d bloggers like this: