Java Notes
Programming: Hammurabi 0
Description
Your program will simulate 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.
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 will last 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 simplistic idea of the size of the population can be computed by simply dividing the total amount of food by the amount needed per person.
k_peasants = food / FOOD_REQUIRED_PER_PERSON
This is inside the simulateOneYear
method,
where k_peasants
is an instance variable representing
the Kingdom's current population, and FOOD_REQUIRED_PER_PERSON
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.
issues
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. Most notably the population isn't implemented. Some areas that must be extended are marked with "TODO" (ie, things remaining "to do").
Hammurabi first version
This class runs the simulation and provides the user interface. It contains the main method, as well as a couple of other methods.
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 |
// File : hammurabi-noop/Hammurabi0.java // Purpose: Starting point for working on the Hammurabi program. // Author : Fred Swartz - 2006-Dec-06 - Placed in public domain. // TODO : * Prompt for amount to feed peasants. // * Check that there is enough grain to meet requests. // * Also stop simulation if population is 0 (while condition) import java.util.*; public class Hammurabi0 { //=============================================================== constants private final static int MIN_GRAIN_TO_SURVIVE = 20; private final static int MAX_LAND_FARMABLE_PER_PERSON = 15; private final static int SEED_REQUIRED_PER_ACRE = 2; //=============================================================== 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) { Scanner in = new Scanner(System.in); //... Run the simulation for 5 years or until everyone starves. while (k_year <= 5) { //... Display state of the kingdom at beginning of each year. System.out.println(getStatusReport()); //TODO: Ask the ruler how much to feed the people. int food = 0; // Temporary substitute for asking for input. //.. Ask the ruler how much grain should be used for seed. System.out.println("Exalted Ruler, how much of the remaining " + (k_grain - food) + " bushels should be planted?"); int seeds = in.nextInt(); //... TODO: Check if not enough grain for this request, Reprompt. //... Update the food and population of this kingdom. simulateOneYear(food, seeds); } //... Show final state. System.out.println(getStatusReport()); } //========================================================== getStatusReport public static String getStatusReport() { // TODO: Don't forget to add population here too. return " Kingdom status at year " + k_year + ", last harvest = " + k_harvest + ", total grain = " + k_grain; } //========================================================= simulateOneYear public static void simulateOneYear(int food, int seed) { //TODO: Need to calculate new population.based on food. //... Reduce grain stockpile by amount used for food and seed k_grain = k_grain - food - 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; // 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()); k_harvest = yieldPerAcre * acresPlanted; //... Compute new amount of grain in storage. k_grain += k_harvest; // New amount of grain in storage. k_year++; // Another year has passed. } } |
Misc info
- Name. You can change the name from Hammurabi to anything 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 probably don't know how to use yet. If you try to build two kingdoms on this static structure it turn into an ugly mess. Multiple objects of the same class is the elegant solution.
- 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, or perhaps separate classes.
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.
- 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 have to be fed better than the peasants.
- Additional random fluctuations
- 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.