CIT 590 Assignment 2: Hammurabi
Spring 2010, David Matuszek

Purposes of this assignment

General idea of the assignment

Hammurabi is a very old computer game. Your job is to bring it into the 21st century by writing it in Python.

When the game begins, it should print out the following instructions:

Congratulations, you are the newest ruler of ancient Samaria, elected
for a ten year term of office. Your duties are to dispense food, direct
farming, and buy and sell land as needed to support your people. Watch
out for rat infestiations and the plague! Grain is the general currency,
measured in bushels. The following will help you in your decisions:

  * Each person needs at least 20 bushels of grain per year to survive.

  * Each person can farm at most 10 acres of land.

  * It takes 2 bushels of grain to farm an acre of land.

  * The market price for land fluctuates yearly.

Rule wisely and you will be showered with appreciation at the end of
your term. Rule poorly and you will be kicked out of office!

Initially, you will start out with

At the beginning of each year (including the first), print out a summary similar to the following:

O great Hammurabi!
You are in year 1 of your ten year rule.
In the previous year 0 people starved to death.
In the previous year 5 people entered the kingdom.
The population is now 100.
We harvested 3000 bushels at 3 bushels per acre.
Rats destroyed 200 bushels, leaving 2800 bushels in storage.
The city owns 1000 acres of land.
Land is currently worth 19 bushels per acre.

The above summary represents the initial state, at the beginning of the first year--that is, when you first take office, and before you do any of the computations below). So, for example, the previous year (under a different ruler) must have started with 95 people; none starved, and 5 entered the kingdom, so as you enter office you rule 100 people.

At the beginning of each year, ask the player for:

Questions should be asked in this order, and the player does not get a chance to go back and change an earlier answer. A player who is buying land is not allowed to sell land during the same turn (the same year).

At the end, use a method to print out a final summary, and to tell the player how good a job he/she did. I'll leave the details up to you, but the usual evaluation is based on how many people starved, and how many acres per person you end up with.

How to write the program

Programs are best written a little bit at a time, testing after each step to see if what you have written so far is working. To get you started, I recommend the following sequence of steps. Remember to test after each step!

  1. First, write a program that prints out the initial message. (Hint: You can save a lot of typing by using a triple-quoted string.) Make sure that works.
  2. The next thing you will want to print is the yearly message. This is most easily done as a series of print statements, rather than one big one. However, the yearly message is full of numbers (ten of them, in fact), and those numbers change from year to year, so you can't write the print statements just yet. First you have to declare variables to hold each of these numbers, and give them their initial values. Give these variables good, easily recognized names, such as bushels_in_storage, and put them in your hammurabi method.

    Again, test what you have done. Adding the variables to the program should not change what it does, but you can test that the program still compiles and runs.
  3. Print the yearly message. Add only one, or at most a couple, print statements at a time, and test them.
  4. Now it's time to ask the player the four questions listed above. As you do that, accept only valid answers--you can't, for example, buy more land than you can afford, or plant more acres than you have. You should, however, allow the player to feed the people more grain than they need to survive.

    Each of these questions should be asked in a separate method. For each question, do "sanity checking"; that is, test whether the answer is possible (you have enough grain, you have enough people to do the planting etc.), and keep asking until you get a possible value. (For example, O Great Hammurabi, we have only 3415 bushels left!) Test each method as you write it.

  5. Once the above is working, you need to determine the following things. You can write a function for each of them. Write one function at a time, and test each one before going on to the next one. Avoid using global variables--pass arguments into the function, and return a result from the function. You can use the value returned by the function to change the necessary variables.
    If there is a plague
    Each year, there is a 15% chance of a horrible plague. When this happens, half your people die.

    There are a couple of ways you could write this function. You could just return True 15% of the time, and False the other 85% of the time. Or, you could pass in the number of people you have, and return the number who died (or the number you have left). Similar comments apply to the rest of the functions in this list.
    How many people starved
    Each person needs 20 bushels of grain to survive. If you feed them more than this, they are happy, but the grain is still gone. If more than 45% of the people starve, you will be immediately thrown out of office (print a nasty message), and the game ends.
    How many people came to the city
    Nobody will come to the city if people are starving. If everyone is well fed, compute how many people come to the city as: (20 * number of acres you have + amount of grain you have in storage) / (100 * population) + 1.
    How good the harvest is
    Choose a random number between 1 and 8, inclusive. Each acre that was planted with seed will yield this many bushels of grain. (Example: if you planted 50 acres, and your number is 3, you harvest 150 bushels of grain).
    If you have a problem with rats
    There is a 40% chance that you will have a rat infestation. When this happens, rats will eat somewhere between 1/10 and 3/10 of your grain.
    How much land costs (for next year)
    The price of land is random, and ranges from 17 to 23 bushels per acre. The player will need this information in order to buy or sell land.

Do these computations, in this order, each "year". Each computation should be done in a separate method, and none of these methods should read anything or print anything. Each method should return a result, and each result should be saved in an instance variable.

At the end, use a method to print out a final summary, and to tell the player how good a job he/she did. I'll leave the details up to you, but the usual evaluation is based on how many people starved, and how many acres you have gained or lost.

All the required arithmetic in this program should be integer. You do not need floats.

As indicated above, you should first get the simplest possible version of the program running and tested out (that is, leave out things like rats, plagues, and immigration), then add these things one at a time to a working program, testing as you go.

Helpful hints

Random numbers

To get a random number generator, you first need to import random. Do this once, at the top of your program.

To get a new random number in the range a to b, including both endpoints, call random.randint(a, b). For example, to simulate the roll of a die, you could use random.randint(1, 6). To do something that happens p percent of the time, use

    if random.randint(0, 99) < p:
        # do something

Entering integers

Here's a bit of code you can use to safely read an integer, so that the program doesn't crash if the user types in something else by mistake:

    number = None
    while number == None:
        try:
            number = string.atoi(raw_input(message))
        except:
            pass

You can adapt this code to meet your needs. For example, it would be a good idea to make it into a function. To use this code, you need to put the statement import string at the top of your program.

Program structure

I recommend writing the "main" program as a function, and putting it first. Like this:

    import random, string
    
    def hammurabi():
        # the "main" program

    # other functions
This structure makes it easy to test the functions as you write them. Just hit F5, then (in the shell window) try out various calls to the function you have just written. To test the entire program, enter hammurabi().

Due date:

Thursday, January 28, before midnight. Turn in your assignment via Blackboard. Since you will be turning in a single file, there is no need to zip it.