The goal of this project is to practice working on linked lists. The guts of this project is provided for you, but it depends on a linked list class which you must write.
Suppose we are interested in dropping 300 19-year-olds onto an isolated island and observing the growth and other trends of the population over the course of 500 years, experimenting with various constraints on how the society they form works. Since time, cost, and ethics prevent us from running these experiments on real people, we will simulate this scenario in a computer program.
We will model the population and the people in the population with a collection of objects. For every "year" of the experiment, certain individuals of the population will give birth to new individuals, certain individuals will get married, and certain individuals will die. In this way the population will change over time (hopefully grow), and these things depend on rates of marriage, birth, and death. (We are assuming only married females give birth, and there is no divorce, though there is the possibility of remarriage if a spouse dies. Also, an individual must have lived a certain number of years before becoming eligible for marriage.)
Make a directory for this project and copy the given code.
cd cs235 mkdir proj7 cd proj7 cp /homes/tvandrun/Public/cs235/proj7/* .
Open Person.java
.
You will see what information we keep on a person.
While a surname is a String, a given name is just
a number serving as a unique identifier.
A person has a birth year used to determine the person's
age, and a person has a reference to a spouse.
Finally, a person has a PersonList
representing the collection of Person
objects which are children of this person.
The PersonList
class is where you will
spend most of your work--only a skeleton is provided for
you.
For now we will observe what it should do by how
the rest of the program uses it.
Open Population.java
.
This is the heart of the program with a very long
main()
method.
First you will see some static variables representing
parameters on population growth.
This is what they mean:
Once you understand the code, you may choose to experiment with modifying these parameters. However, in my own experimentation these where the parameters that worked best. Modifying them to make the population grow faster resulted in the population growing so fast that soon the program slowed down significantly because of all the information to manage. Increasing the death rate to compensate caused the population to die out or grow only very slowly.
You'll also see a collection of surnames stored in an array.
Now inspect the main method.
Skip the part at the beginning about namingPolicy
;
we will come back to that at the end.
The entire population is modeled by a PersonList
.
We populate it initially with 300 people, 5 for each of the
60 available surnames.
Since we are going to start the simulation at year 0,
we give each of them a birth year of -19.
Note that the PersonList
class
has a method add()
.
The big loop represents the years.
First we handle births for that year.
This requires getting a list of all married females.
Notice that the PersonList
class has
a method for finding all such persons, and it returns
them in another, smaller PersonList
.
Then for each iteration of the inner loop (for births),
a random female is chosen from that list;
take note that the PersonList
class
has a method for picking an element at random.
Make sure you can follow all of the code in the "birth" section,
except for the part about how a child's surname is chosen.
Next, the section on marriages.
We use methods in PersonList
to
find all the females and males who are eligible for
getting married this year.
Follow that code carefully.
The section on premature deaths shows that
the PersonList
class must have a remove()
method.
More interesting, though, are the "old age" deaths.
We want to give the list a birth year and have it remove all
Person
s with birth years earlier than that.
However, we also want to update the spouses of all
people that have died so that they now have null spouses
and will appear as single.
To do this, we need the PersonList
to return
all the items it removed---as a separate PersonList
.
Oh, but also, we want to iterate through that list,
and so we would like to turn it into an array.
Hence PersonList
must also have a
toArray()
method.
PersonList
Almost all of your work will be in this class.
You will not need to modify Person
or
PersonNode
,
and you will make only trivial changes to Population
(ie, uncommenting some code that has been commented out).
PersonList
needs no explicit constructor---
head
will be set to null by default
and size
to zero.
Write the following methods:
add()
-- The catch here is
that PersonList
list should act like a
mathematical set.
It should not contain any item more than once.
Hence you should write this method in such a way that
it will add the given item only if it is not already
present in the list.
Also, make sure you maintain the size
variable.
remove()
-- The tricky parts here are,
make sure you consider the cases where the item is
not in the list to begin with, where head
is null,
and where head
contains the item to be removed.
Also, maintain the size
variable.
removeAllAge()
-- This is the hardest method.
Make sure you consider the case where there are several
items in a row that need to be removed.
Moreover, you need to store all the items you're removing in
a new PersonList
and return that list.
Also, maintain the size
variable.
getRandom()
-- Think carefully about
how you can use Math.random()
to retrieve
(but not remove) a random element from the list.
Each element should be equally likely to be chosen.
toArray()
-- Make an array, fill it
with the items in the list, and return it.
Hint: How do you know how big to make the array?
MarriedFemales()
,
marriableFemales()
, and marriableMales()
--
These are grouped together because they are very similar.
In fact, you'll feel like you are writing pretty much the
same method three times.
That should make you feel like there is a better way to do this.
Come back next semester and see how better abstractions can
make writing similar operations like these easier.
Warning: One of the most important concepts
to grasp in all of this is the difference between a
Person
and a PersonNode
.
A Person
object may exist in more than on list a the
same time, but a PersonNode
cannot
(similarly, several PersonNode
s could contain
references to the same Person
).
Make sure this is clear before you try to write the methods
listed above.
Ask for help if it is not.
When you think you have things written right and it all compiles, run the program:
java Population
You will notice the program slowing down near the end. Even with all the randomization, you will almost certainly end up with statistics at the end reading between 78% and 80% of adults being married, a population of between 12000 and 22000, and about 2.4 children for each person having children. Here's a typescript of the output of my solution at this point. If your numbers are different from these, there is probably something wrong.
Uncomment the section at the end and run your program again. This will report on the size of the population for each surname and give a breakdown of the male/female split for each surname. Currently, children are given surnames in the "patriarchal" manner-- each child gets his or her father's surname. You'll notice that while most surnames that are still in use after 500 years have pretty even gender splits, a fair number of surnames will have died off.
Marilyn Vos Savant has proposed that male children should take their father's surname and female children should take their mother's (premarital) surname (see http://www.parade.com/articles/editions/2007/edition_11-25-2007/Ask_Marilyn). Apart from whatever other societal value that might have, for our interest it would have the effect of reducing the number of surnames that die out. Under the patriarchal system, a surname may die out not only if it fails to reproduce at all, but also if it merely reproduces only females.
A downside to Vos Savant's proposal is that it could lead to some surnames becoming lopsided in terms of gender balance. If a surname produced more females than males in one generation, it would be likely to produces an even greater percentage of females in the following generation. Eventually some surnames would be exclusively or almost exclusively male, others exclusively or almost exclusively female.
In our simulation, a child's surname is determined by an object
that implements the NamingPolicy
interface.
Study that interface and the Patriacharl
class
that implements it.
Then uncomment the code at the beginning of the
main
method that parses the args
array and write two more classes that implement
NamingPolicy
:
Savant
, which follows Vos Savant's proposal, and
AntiSavant
, which does, the opposite, giving
male children their mother's surname, and female children
their father's surname.
The run the program several times experimenting
with these policies.
The -S
flag with run Vos Savant's proposal,
and -AS
will run the third option.
Does the third option keep the number of dead surnames
low while also preserving gender balance?
Propose another interesting experiment and (after approval) implement it.
Cat PersonList
and the classes you
wrote.
Run the program with each policy.
DUE: Wednesday, Nov 11, at 5:00 PM.