A State Capitals Quiz using shell script

Once you have a tool for choosing a line randomly from a file, Displaying Random Text, there's no limit to the type of quiz games you can write. In this instance, I've pulled together a list of the capitals of all 50 states in the United States of America; this script randomly chooses one, shows the state, and asks the user to type in the matching capital.

The Code
#!/bin/sh

# states - A state capital guessing game. Requires the state capitals
# data file at http://www.intuitive.com/wicked/examples/state.capitals.txt.

db="/usr/lib/games/state.capitals.txt"
randomquote="$HOME/bin/randomquote.sh" # Script #76

if [ ! -r $db ] ; then
echo "$0: Can't open $db for reading." >&2
echo "(get http://www.intuitive.com/wicked/examples/state.capitals.txt" >&2
echo "save the file as $db and you're ready to play!)" >&2
exit 1
fi

guesses=0; correct=0; total=0

while [ "$guess" != "quit" ] ; do
thiskey="$($randomquote$db)"

state="$(echo $thiskey | cut -d\ -f1 | sed 's/-/ /g')"
city="$(echo $thiskey | cut -d\ -f2 | sed 's/-/ /g')"
match="$(echo $city | tr '[:upper:]' '[:lower:]')"

guess="??" ; total=$(( $total + 1 )) ;

echo ""
echo "What city is the capital of $state?"

while [ "$guess" != "$match" -a "$guess" != "next" -a "$guess" != "quit" ]
do
echo -n "Answer: "
read guess

if [ "$guess" = "$match" -o "$guess" = "$city" ] ; then
echo ""
echo "*** Absolutely correct! Well done! ***"
correct=$(( $correct + 1 ))
guess=$match
elif [ "$guess" = "next" -o "$guess" = "quit" ] ; then
echo ""
echo "$city is the capital of $state."
else
echo "I'm afraid that's not correct."
fi
done

done

echo "You got $correct out of $total presented."
exit 0

How It Works
For such an entertaining game, states is very simple scripting. The data file contains state/capital pairs, with all spaces in the state and capital names replaced with dashes and the two fields separated by a single space. As a result, extracting the city and state names from the data is easy:

state="$(echo $thiskey | cut -d\ -f1 | sed 's/-/ /g')"
city="$(echo $thiskey | cut -d\ -f2 | sed 's/-/ /g')"


Each guess is compared against both the all-lowercase version of the city name (match) and the actual correctly capitalized city name to see if it's correct. If not, the guess is compared against the two command words next and quit. If either matches, the script shows the answer and either prompts for another state or quits, as appropriate.

Running the Script
This script has no arguments or command flags.

The Results
Ready to quiz yourself on state capitals?

$ states

What city is the capital of Indiana?
Answer: Bloomington
I'm afraid that's not correct.
Answer: Indianapolis

*** Absolutely correct! Well done! ***

What city is the capital of Massachusetts?
Answer: Boston

*** Absolutely correct! Well done! ***

What city is the capital of West Virginia?
Answer: Charleston

*** Absolutely correct! Well done! ***

What city is the capital of Alaska?
Answer: Fairbanks
I'm afraid that's not correct.
Answer: Anchorage
I'm afraid that's not correct.
Answer: Nome
I'm afraid that's not correct.
Answer: Juneau

*** Absolutely correct! Well done! ***

What city is the capital of Oregon?
Answer: quit

Salem is the capital of Oregon.
You got 4 out of 5 presented.


Fortunately, the game tracks only ultimately correct guesses, not how many incorrect guesses you made or whether you popped over to Google to get the correct answer! :-)

Hacking the Script
Probably the greatest weakness in this game is that it's so picky about spelling. A useful modification would be to add some code to allow fuzzy matching, so that the user entry of Juneu might match Juneau, for example. This could be done using a modified Soundex algorithm, in which all vowels are removed and all doubled letters are squished down to a single letter (e.g., Annapolis would transform to npls). This might be too forgiving for your tastes, but the general concept is worth considering.

As with other games, a "hint" function would be useful too. Perhaps it would show the first letter of the correct answer when requested but keep track of how many hints were used as the play proceeded.

Although this game is written around state capitals, it would be quite trivial to modify the script to work with any sort of paired data file. For example, you could create an Italian vocabulary quiz with a slightly different file, or a country/ currency match, or even a politician/political party quiz. Again, as we've seen repeatedly in Unix, writing something that is reasonably general purpose allows it to be reused in useful and occasionally unexpected ways.