Simulation
Introduction
One particular type of program that lends itself well to using objects is simulation programs. A simulation is a program that models some kind of process or system over time. Simulation programs are very important to many other disciplines.
Some examples of areas that use computer simulation:
- Astronomical events.
- Particle physics.
- Cell reproduction.
- Chemical reactions.
- Spread of disease.
- Weather prediction.
- Traffic patterns.
- Crowd modelling.
- Artificial intelligence.
- Most video games.
Simulations are done by keeping track of several objects, and how they change over time. The objects can possibly interact with each other or outside influences.
Example: Disease Simulation
As an example of how we could do a simulation on multiple objects, consider the problem of studying a disease outbreak. The general idea is we can keep track of a large number of virtual people, as they move about. Some people will start out sick, and can pass the disease to those they are near.
Below is a simple program which does just such a simulation. There are a number of parameters which control the simulation as it runs. They are grouped in a class so they can be changed in one place:
// a class which just contains some numbers grouped together
class SimulationParameters {
static final int POPULATION = 200;
static final int MOVE_AMOUNT = 2;
static final int HEAL_DAYS = 10;
static final int INITIAL_SICK = 10;
static final double INFECT_DISTANCE = 2.5;
}
To keep track of whether someone is sick or not, we can use an enumeration:
// represents whether a given person is healthy or sick
enum State {
HEALTHY,
INFECTED
};
We then can make a Person class for modeling one person in this simulation. They have variables which store their sate and position, and functions which modify them:
class Person {
// variables used in simulating the person
private State state;
private int days_til_healed;
private double x, y;
// construct a healthy person, randomly positioned in space
Person() {
state = State.HEALTHY;
Random generator = new Random();
x = generator.nextInt(100);
y = generator.nextInt(100);
}
// move the person randomly
void move() {
Random generator = new Random();
// getr a random number between 0 and 1
double val = generator.nextDouble();
// multiply by twice the move amount - this gets us a value between
// negative move amount, and positive move amount
val = val * 2.0 * SimulationParameters.MOVE_AMOUNT;
val = val - SimulationParameters.MOVE_AMOUNT;
// move in the x direction by this much
x += val;
// do the same thing for y
double val2 = generator.nextDouble();
val2 = val2 * 2.0 * SimulationParameters.MOVE_AMOUNT;
val2 = val2 - SimulationParameters.MOVE_AMOUNT;
y += val2;
// don't let them go off the edges
if (x > 100) {
x = 100;
}
if (y > 100) {
y = 100;
}
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
}
// called after each step in the simulation, if this person is sick,
// is it time for them to get better yet?
void checkHeal() {
if (days_til_healed == 0) {
state = State.HEALTHY;
} else {
days_til_healed--;
}
}
// set this person as infected
void setInfected() {
state = State.INFECTED;
days_til_healed = SimulationParameters.HEAL_DAYS;
}
// return the state of this person
boolean isInfected() {
return state == State.INFECTED;
}
// check if this person has been infected by another person
void checkInfected(Person others[]) {
// loop through each other person
for (int i = 0; i < SimulationParameters.POPULATION; i++) {
// find the euclidean distance between them
double distance = Math.sqrt((x - others[i].x) * (x - others[i].x)
+ (y - others[i].y) * (y - others[i].y));
// if they are too close
if (distance < SimulationParameters.INFECT_DISTANCE) {
// if they're sick and we are not, we are now sick too :(
if (state == State.HEALTHY && others[i].state == State.INFECTED) {
setInfected();
}
}
}
}
}
Once we have a class to keep track of an individual person, we can create an array of people, and loop through it, performing the simulation over time:
// the main class which runs the simulation
class DiseaseSimulation {
public static void main(String args[]) {
// make an array of people
Person people[] = new Person[SimulationParameters.POPULATION];
// actually create the people
for (int i = 0; i < SimulationParameters.POPULATION; i++) {
people[i] = new Person();
}
// set the first so many to be sick
for (int i = 0; i < SimulationParameters.INITIAL_SICK; i++) {
people[i].setInfected();
}
Scanner in = new Scanner(System.in);
// keep going until the user says no
boolean cont;
int day = 1;
do {
// go through each person
for (Person p : people) {
// move them
p.move();
// check if they are all better
p.checkHeal();
// check if they are sick
p.checkInfected(people);
}
// count how many people are sick
int sick = 0;
for (Person p : people) {
if (p.isInfected()) {
sick++;
}
}
// print stats
System.out.printf("After %d days, %d people are sick and %d people are well\n",
day, sick, SimulationParameters.POPULATION - sick);
// move to the next day
day++;
// check if we want to continue
System.out.print("Continut (y/n): ");
cont = in.next().charAt(0) == 'y';
} while (cont);
}
}
Some questions we could ask of this simulation:
- Does the disease ever go away? After how many years?
- Does the infection number level off? At what level?
- What factors make the disease more deadly?
- What if people who catch the disease become immune?
- If the disease was fatal, how many would die?