Java Notes
Programming: Hammurabi v0
Description
This program simulates the functioning of an early agricultural society. It is based on the ancient computer game Hammurabi, named after a Babylonian king (See en.wikipedia.org/wiki/Hammurabi) famous for his laws. He also ran a very authoritarian society in which the peasants were allocated fixed rations of food by the state, as in this game.
Goal. The user, who has just become the ruler of a kingdom, wants to make a place in history by having having the largest population of peasants. The simulation lasts five years or until everyone has starved.
Grain is the basic resource. Each year, ask the ruler how to use the grain in storage.
- How many bushels to feed the people.
- How many bushels to use as seed for planting next year's crop.
The remaining grain, if any, is saved for the next year in case of a bad harvest.
Initial Conditions
The Kingdom starts with the following resources: an area of 1000 acres, a population of 100, and with 3000 bushels of grain from the previous harvest.
Food and Population Rules
Each peasant needs a minimum of 20 bushels of grain per year to survive.
Starvation. If the ruler doesn't allocate enough food for everyone, some will starve. The population is then reduced by the number of peasants who starved.
Immigrants if lots of food. If people receive more than 20 bushels per person, immigrants from neighboring kingdoms will be attracted, resulting in a population increase.
Formula. This simple population computation can be made by dividing the total amount of food by the amount needed per person.
k_peasants = food / MIN_GRAIN_TO_SURVIVE
This is inside the simulateOneYear method,
where k_peasants is a static variable representing
the Kingdom's current population, and MIN_GRAIN_TO_SURVIVE
is a constant predefined to be 20.
For example, if the ruler allocates 2400 bushels, this will support a population of 2400 / 20, which is 120. This would become the new population.
Agriculture
Seed for Planting. Not all grain can be used for feeding the people. Some must be used to plant next year's crop. It takes two bushels of grain to plant an acre. To plant everything therefore requires 2 * area bushels of grain.
Harvest. There are variations in the weather each year. The yield varies from 2 to 6 bushels per planted acre. This number is randomly generated each year.
Continue for 5 years or the entire populatin has starved
The main program gets information from the user/ruler on how to allocate the grain each year, simulates one year, and display the results for that year. It should continue in a loop until the end of the simulation time period or the peasants have starved.
The simulateOneYear method, which takes parameters for
how much grain to use to plant the next crop, and how much grain to feed
the population. Extend it to add population.
Keep all input/output in the main method.
Check for legal values, eg, don't allow the ruler to plant more grain than there is.
Copy these files to start your project
In the spirit of iterative programming, here is a working version, but it doesn't implement all features. Some areas that must be extended are marked with "TODO" (ie, things remaining "to do").
Hammurabi first version
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
// File : hammurabi-noop/Hammurabi0.java
// Purpose: Starting point for working on the Hammurabi program.
// Author : Fred Swartz - 2007-05-03 - Placed in public domain.
// TODO : * Prompt for amount to feed peasants.
// * Check for reasonable values (enough grain, ...).
import java.util.*;
public class Hammurabi0 {
//=============================================================== constants
private static final int MIN_GRAIN_TO_SURVIVE = 20;
private static final int MAX_LAND_FARMABLE_PER_PERSON = 15;
private static final int SEED_REQUIRED_PER_ACRE = 2;
private static final Scanner in = new Scanner(System.in);
//=============================================================== variables
// Everything prefixed with "k_" is part of the status of a Kingdom.
// All "k_" variables should be part of a Kingdom class, but....
private static int k_grain = 3000; // Bushels of grain in storage.
private static int k_area = 1000; // Area of kingdom in acres. Note that
// k_area isn't used yet, but will be if
// you add a check for the total amount
// of land that can be planted.
private static int k_year = 0; // Years since founding of kingdom.
private static int k_harvest = 0; // Last harvest in bushels.
private static int k_peasants = 100; // Number of peasants.
//================================================================== main
public static void main(String[] args) {
//... Run the simulation for 5 years or until everyone starves.
while (k_peasants > 0 && k_year <= 5) {
displayStatus(); // Show status of kingdom every year.
int food = promptForFood(); // How much grain should be use for food?
int seeds = promptForSeeds(); // How much grain should be used for planting?
simulateOneYear(food, seeds); // Simulate effect of feeding and planting.
k_year++; // Another year has passed.
}
//... End of simulation. Show status.
if (k_peasants == 0) {
System.out.println("Everyone starved!!!!");
} else {
System.out.println("Congratuations, you survived for 5 years!");
}
displayStatus();
}
//========================================================== displayStatus
public static void displayStatus() {
System.out.println(" Kingdom status at year " + k_year
+ ": last harvest = " + k_harvest
+ "\nTotal grain = " + k_grain
+ "\nPeasants = " + k_peasants);
}
//========================================================== promptForFood
private static int promptForFood() {
//TODO: Ask the ruler how much to feed the people.
return 0;
}
//========================================================= promptForSeeds
private static int promptForSeeds() {
//.. Ask the ruler how much grain should be used for seed.
System.out.println("Exalted Ruler, how many bushels should be planted?");
return in.nextInt();
//... TODO: Check if not enough grain for this request, Reprompt.
}
//========================================================= simulateOneYear
private static void simulateOneYear(int food, int seed) {
//... Calculate new population.based on food.
k_peasants = food / MIN_GRAIN_TO_SURVIVE;
k_grain -= food; // Reduce grain by amount used for seed.
//... Calculate new harvest
// 1. How many acres can be planted with seed.
// 2. The yield per acre is random (2-6)
// 3. Harvest is yield * area planted.
int acresPlanted = seed / SEED_REQUIRED_PER_ACRE;
k_grain -= seed; // Reduce grain by amount used for seed.
// TODO: Check that there are enough people and there is
// enough land to actually plant that number of acres.
int yieldPerAcre = 2 + (int)(5 * Math.random()); // Number from 2 to 6
k_harvest = yieldPerAcre * acresPlanted;
//... Compute new amount of grain after the harvest.
k_grain += k_harvest; // New amount of grain in storage.
}
}
|
Misc info
- Name. Please change the name from Hammurabi to something else. You can also change the basic elements of the game, as long as it remains a one-player game trying to rule a civilization.
- One player. Do not try to make this into a two-player game where there are multiple kingdoms. A two-player game would best be done using multiple kingdom objects, which you don't know how to use yet. If you try to build two kingdoms on this static structure it turn into an ugly mess. The Object-Oriented approach to this would be a simple way to make multiple kingdomes.
- Cooperating. If you want to pair up with someone else on this program, that's fine, but I'll expect a more extensive final program. You should try to keep from stepping on each other's code by writing separate methods.
Extra credit possibilities
This above game omits some interesting aspects. After you have the simple version of the program running as described above, you might want to make it more "realistic" by adding some of the following features.
- Better interface. Don't hesitate to make the interface better, use JOptionPane, better output, ...
- Buying and selling land. Land can be bought from the neighboring kingdoms (or sold back to them) for 20 bushels per acre. The yearly plan that the ruler makes should therefore include how much land to buy/sell in addition to the food and seed allocations. Allowing land to be added is the only way to get the population to really grow.
- Farming limits. The amount of land that one peasant can farm should be limited to 15 acres. If the population drops, it may not be possible to farm all land.
- Revolt. If more than 45% of the population starves, there is a revolt which overthrows the ruler, and the game ends.
- Soldiers. My wife's first reaction was to ask about the soldiers. They could play an important role, but exactly what will be left up to you (eg, suppress revolts, capture land, etc). But perhaps they must be fed better than the peasants.
- Random events
- Rats. Each year, rats eat a random amount from 0-10% of your grain
- Plague. There is a 15% chance each year of a plague. If that happens, half the population dies.