Introduction to Simulations CS1316: Representing Structure and Behavior

advertisement
Introduction to
Simulations
CS1316: Representing
Structure and Behavior
Story




What’s a simulation? Why do we simulate?
•
•
Discrete vs. Continuous
Resources
Building software to be modifiable: Software Engineering
•
Building models out of objecs: aggregation, generalizing and
specializing
Continuous Simulations
•
•
•
•
Predatory-prey: Wolves and Deer
Changing our simulation
Creating hungry wolves
Other options: Hungry deer? Deer sex? Wolf sex?
How do we compare simulations?
•
Creating text files
Simulations

“A simulation is a representation of a system of objects in
a real or fantasy world.
The purpose of creating a computer simulation is to
provide a framework in which to understand the simulated
situation, for example, to understand the behavior of a
waiting line, the workload of clerks, or the timeliness of
service to customers.
A computer simulation makes it possible to collect
statistics about these situations, and to test out new ideas
about their organization.”
•
Adele Goldberg & David Robson, Smalltalk-80: The
Language and Its Implementation (Addison-Wesley, 1989)
Simulations and Objects


Object-oriented programming was invented, in
part, to make simulations easier to build!
The characteristics of objects make them more
like real world objects, e.g.,
•
•
•
Each thing knows some stuff and knows how to do
some stuff.
Objects get things done by asking each other to do
things.
Your internals are private, unless you want to make
them otherwise.
Continuous vs. Discrete
Simulations


Two main kinds of simulations in the
world.
Continuous: Each moment of time is
simulated.
• When every moment counts.

Discrete: Skip to the important moments.
• Want to simulate 100 years?
Resources

Resources are points of coordination in a
simulation.
•



Examples: A cashier, a library book, a parking space
on a ferry, a jelly bean.
Some resources are fixed and others are
produced and consumed.
Some resources are renewable and shared.
Others are coordinated.
•
Example: For a surgeon to do a surgery, the patient
must meet the surgeon at the operating table (the
resource)
When an object has to wait…

What happens if you (or your proxy
object) need a resource and it’s not
available?
• You wait in a queue
• A list that is first-in-first-out (FIFO)
A simulation is an executed
model




Setting up a simulation is a process of
modeling the world (real or fantasy) to be
simulated.
That model is realized in terms of objects.
We want our model to:
•
•
Reflect the world.
Be easy to extend and change.
Some of our modeling techniques:
•
•
Aggregation
Generalization and specialization
Aggregation

Some objects are made up of other
objects.
• Cars have engines
• People have livers and lungs
• These internal things are objects, too!
• Livers don’t directly mess with the innards of lungs!

We call this aggregation
• Putting references to some objects inside of
other objects.
Generalization and
Specialization

There are general and specialized forms of
real world objects.
•
•

Cells are biological objects that have membranes and
a nucleus and mitochondria and…
Blood, lung, and liver cells are all cells but have
specialized functions.
The superclass-subclass relationship is a way
of modeling general forms of objects and
specialized forms of objects
Making it concrete:
Wolves eating deer
Running the simulation
Welcome to DrJava.
> WolfDeerSimulation wds = new WolfDeerSimulation()
> wds.run()
>>> Timestep: 0
Wolves left: 5
Deer left: 20
>>> Timestep: 1
Wolves left: 5
Deer left: 20
<SIGH!> A deer died...
>>> Timestep: 2
Wolves left: 5
Deer left: 19
>>> Timestep: 3
Wolves left: 5
Deer left: 19
<SIGH!> A deer died...
>>> Timestep: 4
Wolves left: 5
Deer left: 18
An Example Simulation

The WolfDeerSimulation is a continuous
simulation.
• Each moment in time is simulated.


It has no resources.
It is a predator-prey simulation
• A common real world (ecological) situation.
• There are parameters to change to explore
under what conditions predators and prey
survive and in what numbers.
The Model of this Simulation
WolfDeerSimulation
Turtle
Knows the list of
wolves and deer
LLNode
KnowsHow to run()
each moment in time
AgentNode
Wolf
Deer
KnowsHow to
act(), and to
find the closest
deer.
KnowsHow to
act() and die
Knows its turtle
(agent)
KnowsHow to
get/set agent, to
remove an agent
Complicated Set of
Relationships in this Model





Wolf and Deer are kinds of Turtle
•
Specializations of Turtle
AgentNode is a kind of LLNode
AgentNodes each have one Turtle (Wolf or
Deer) inside it.
WolfDeerSimulation has two AgentNodes for
the lists of live wolves and deer.
Each Wolf and Deer knows what simulation its
in.
A UML Class Diagram
WolfDeerSimulation
1
-wolves
-deer
+run()
LLNode
-next
+getNext()
+remove()
+count()
+add()
-mySim
1
*-mySim
*
1
-wolves
-deer
AgentNode
1
-myTurtle
+setAgent()
+getAgent()
*
1
-myTurtle
Turtle
*
*
Wolf
+act()
+getClosest()
Deer
+act()
+die()
Unified Modeling Language
(UML)

This is a UML class diagram.
• A graphical notation for describing the
relationships between classes in a model.

UML is a standard that describes several
different kinds of diagrams.
• Collaboration diagrams: How objects work
•
together and how they call on one another.
Sequence diagrams: What the order of events
are in an object system.
A class in a UML class diagram
Name of the
class
Operations
or methods:
What the
instances
know how
WolfDeerSimulation
-wolves
-deer
+run()
Instance variables
or fields: What the
class instances
know
Generalization-specialization
relationships
Turtle
Deer
+act()
+die()
A Deer is a subclass of
Turtle: It’s a
specialization of Turtle
Associations
WolfDeerSimulation
WolfDeerSimulation has two
AgentNodes in it: One to
represent wolves and one to
represent deer.
-wolves
-deer
+run()
*
*
1
-deer
AgentNode
1
-myTurtle
+setAgent()
+getAgent()
-wolves
AgentNodes don’t know their
simulation
A Class Diagram describes the
Model, without the Code
WolfDeerSimulation
1
-wolves
-deer
+run()
LLNode
-next
+getNext()
+remove()
+count()
+add()
-mySim
1
*-mySim
*
1
-wolves
-deer
AgentNode
1
-myTurtle
+setAgent()
+getAgent()
*
1
-myTurtle
Turtle
*
*
Wolf
+act()
+getClosest()
Deer
+act()
+die()
WolfDeerSimulation
public class WolfDeerSimulation {
/* Linked lists for tracking wolves and deer */
Why private?
private AgentNode wolves;
Only the
private AgentNode deer;
simulation should
know its wolves
and deer.
/** Accessors for wolves and deer */
public AgentNode getWolves(){return wolves;}
public AgentNode getDeer(){return deer;}
The main run() method
public void run()
{
World w = new World();
w.setAutoRepaint(false);
// Start the lists
wolves = new AgentNode();
deer = new AgentNode();
// create some deer
int numDeer = 20;
for (int i = 0; i < numDeer; i++)
{
deer.add(new AgentNode(new Deer(w,this)));
}
We want to control
when the world
updates itself.
AgentNodes
contain the
Deer
Head and Rest



Wolves and deer are AgentNodes…but the real content
starts at getNext().
We call this the head of the list.
•
It’s a placeholder.
We call the rest the rest or body of the list.
•
This makes it possible to remove a node, even if it’s the first
one in the list.
wolves
Head
Rest
Rest
Rest
getNext:
getNext:
getNext:
getNext:
Make some wolves
// create some wolves
int numWolves = 5;
for (int i = 0; i < numWolves; i++)
{
wolves.add(new AgentNode(new Wolf(w,this)));
}
Start our simulation loop
// declare a wolf and deer
Wolf currentWolf = null;
Deer currentDeer = null;
AgentNode currentNode = null;
// loop for a set number of timesteps (50 here)
for (int t = 0; t < 50; t++)
{
// loop through all the wolves
currentNode = (AgentNode) wolves.getNext();
while (currentNode != null)
{
currentWolf = (Wolf) currentNode.getAgent();
currentWolf.act();
currentNode = (AgentNode) currentNode.getNext();
}
What’s going on
here?
It’s our AgentNodes
that are in a linked
list. Each one of
them contains
(aggregation!) a
Wolf.
Have to pull the
Wolf out to get it to
act()
Give the deer a chance to act
// loop through all the deer
currentNode = (AgentNode) deer.getNext();
while (currentNode != null)
{
currentDeer = (Deer) currentNode.getAgent();
currentDeer.act();
currentNode = (AgentNode) currentNode.getNext();
}
Same unpackaging going on
here.
Show us what happened
// repaint the world to show the movement
w.repaint();
// Let's figure out where we stand...
System.out.println(">>> Timestep: "+t);
System.out.println("Wolves left: "+wolves.getNext().count());
System.out.println("Deer left: "+deer.getNext().count());
// Wait for one second
//Thread.sleep(1000);
}
}
Does the simulation go too fast?
Make the thread of execution
sleep for 1000 milliseconds
Implementing a Wolf
import java.awt.Color;
import java.util.Random;
import java.util.Iterator;
/**
* Class that represents a wolf. The wolf class
* tracks all the living wolves with a linked list.
*
* @author Barb Ericson ericson@cc.gatech.edu
*/
public class Wolf extends Turtle
{
/////////////// fields //////////////////////
/** class constant for the color */
private static final Color grey = new Color(153,153,153);
A final is something that
won’t change: A
constant. It’s used to
make code more
readable yet easy-tochange.
Private vs. Protected?
Use Protected if your
subclasses will need to
access (new kinds of
wolves?)
/** class constant for probability of NOT turning */
protected static final double PROB_OF_STAY = 1/10;
Constants are
typically all-caps
More Wolf fields
/** class constant for top speed (max num steps can
move in a timestep) */
protected static final int maxSpeed = 60;
maxSpeed should
/** My simulation */
protected WolfDeerSimulation mySim;
probably be all-caps
(or did you want to
make it variable? Do
wolves get slower
as they get hungry?
/** random number generator */
protected static Random randNumGen = new Random();
There is more than one
kind of random. Treating
it as an object makes it
easier to have different
kinds later.
////////////////////////////// Constructors ////////////////////////
Constructors
Remember that a
constructor must
match its superclass,
if you want to use
super(). These are
like the ones in
Turtle.
What’s a
ModelDisplay? The
abstract superclass of
the World.
/**
* Constructor that takes the model display (the original
* position will be randomly assigned)
* @param modelDisplayer thing that displays the model
* @param mySim my simulation
*/
public Wolf (ModelDisplay modelDisplayer,WolfDeerSimulation
thisSim)
{
super(randNumGen.nextInt(modelDisplayer.getWidth()),
randNumGen.nextInt(modelDisplayer.getHeight()),
modelDisplayer);
init(thisSim);
}
/** Constructor that takes the x and y and a model
* display to draw it on
* @param x the starting x position
* @param y the starting y position
* @param modelDisplayer the thing that displays the model
* @param mySim my simulation
*/
public Wolf (int x, int y, ModelDisplay modelDisplayer,
WolfDeerSimulation thisSim)
{
// let the parent constructor handle it
super(x,y,modelDisplayer);
init(thisSim);
}
Using a Random:
PseudoRandom Number Generator
Initialize a Wolf
////////////////// methods ////////////////////////////////////////
/**
* Method to initialize the new wolf object
*/
public void init(WolfDeerSimulation thisSim)
{
// set the color of this wolf
setColor(grey);
// turn some random direction
this.turn(randNumGen.nextInt(360));
// set my simulation
mySim = thisSim;
}
Get an integer
at most 360
Is there a
Deer to eat?
public AgentNode getClosest(double distance,AgentNode list)
{
// get the head of the deer linked list
AgentNode head = list;
AgentNode curr = head;
AgentNode closest = null;
Deer thisDeer;
double closestDistance = 0;
double currDistance = 0;
Walk this through in
English to see that it’s
doing what you think it
should.
// loop through the linked list looking for the closest deer
while (curr != null)
{
thisDeer = (Deer) curr.getAgent();
currDistance = thisDeer.getDistance(
this.getXPos(),this.getYPos());
if (currDistance < distance)
{
if (closest == null || currDistance < closestDistance)
{
closest = curr;
closestDistance = currDistance;
}
}
curr = (AgentNode) curr.getNext();
}
return closest;
|| is “OR”
}
Modeling what a Wolf does
/**
* Method to act during a time step
* pick a random direction and move some random amount up to top speed
*/
public void act()
{
// get the closest deer within some specified distance
AgentNode closeDeer = getClosest(30,
(AgentNode) mySim.getDeer().getNext());
if (closeDeer != null)
{
Deer thisDeer = (Deer) closeDeer.getAgent();
this.moveTo(thisDeer.getXPos(),
thisDeer.getYPos());
thisDeer.die();
}
Why getNext()?
Because we
need the body of
the list, and
that’s after the
head.
getClosest returns an
AgentNode, so we have to get
the Deer out of it with
getAgent()
If can’t eat, then move
else
{
// if the random number is > prob of NOT turning then turn
if (randNumGen.nextFloat() > PROB_OF_STAY)
{
Get an integer
this.turn(randNumGen.nextInt(360));
at most 360, or
}
// go forward some random amount
forward(randNumGen.nextInt(maxSpeed));
}
}
at most
maxSpeed
Deer
import java.awt.Color;
import java.util.Random;
/**
* Class that represents a deer. The deer class
* tracks all living deer with a linked list.
*
* @author Barb Ericson ericson@cc.gatech.edu
*/
public class Deer extends Turtle
{
/////////////// fields //////////////////////
/** class constant for the color */
private static final Color brown = new Color(116,64,35);
/** class constant for probability of NOT turning */
private static final double PROB_OF_STAY = 1/5;
Deer fields (instance variables)
/** class constant for top speed (max num steps
can move in a timestep) */
private static final int maxSpeed = 50;
/** random number generator */
private static Random randNumGen = new
Random();
/** the simulation I'm in */
private WolfDeerSimulation mySim;
////////////////////////////// Constructors ////////////////////////
Deer
Constructors
Nothing new
here…
/**
* Constructor that takes the model display (the original
* position will be randomally assigned
* @param modelDisplayer thing which will display the model
*/
public Deer (ModelDisplay modelDisplayer,WolfDeerSimulation
thisSim)
{
super(randNumGen.nextInt(modelDisplayer.getWidth()),
randNumGen.nextInt(modelDisplayer.getHeight()),
modelDisplayer);
init(thisSim);
}
/** Constructor that takes the x and y and a model
* display to draw it on
* @param x the starting x position
* @param y the starting y position
* @param modelDisplayer the thing that displays the model
*/
public Deer (int x, int y, ModelDisplay modelDisplayer,
WolfDeerSimulation thisSim)
{
// let the parent constructor handle it
super(x,y,modelDisplayer);
init(thisSim);
}
Initializing a Deer
/**
* Method to initialize the new deer object
*/
public void init(WolfDeerSimulation thisSim)
{
// set the color of this deer
setColor(brown);
// turn some random direction
this.turn(randNumGen.nextInt(360));
// know my simulation
mySim = thisSim;
}
Nothing new
here…
What Deer Do
/**
* Method to act during a time step
* pick a random direction and move some random amount up to top speed
*/
public void act()
{
// if the random number is > prob of NOT turning then turn
if (randNumGen.nextFloat() > PROB_OF_STAY)
{
this.turn(randNumGen.nextInt(360));
Nothing new
}
here…
// go forward some random amount
forward(randNumGen.nextInt(maxSpeed));
}
When Deer Die
/**
* Method that handles when a deer dies
*/
public void die()
{
// Leave a mark on the world where I died...
this.setBodyColor(Color.red);
// Remove me from the "live" list
mySim.getDeer().remove(this);
Why don’t we
have to say
getNext() before
the remove()?
// ask the model display to remove this
// Think of this as "ask the viewable world to remove this turtle"
//getModelDisplay().remove(this);
If you want the
System.out.println("<SIGH!> A deer died...");
}
body and its trail
to disappear…
AgentNodes

AgentNodes contain Turtles

It’s a subclass of LLNode
• That’s aggregation
• It’s a specialization of LLNode
AgentNode implementation
/**
* Class to implement a linked list of Turtle-like characters.
* (Maybe "agents"?)
**/
public class AgentNode extends LLNode {
/**
* The Turtle being held
**/
private Turtle myTurtle;
AgentNode constructors
/** Two constructors: One for creating the head of the list
* , with no agent
**/
public AgentNode() {super();}
/**
* One constructor for creating a node with an agent
**/
public AgentNode(Turtle agent){
super();
this.setAgent(agent);
}
AgentNode getter/setter
/**
* Setter for the turtle
**/
public void setAgent(Turtle agent){
myTurtle = agent;
}
/**
* Getter for the turtle
**/
public Turtle getAgent(){return myTurtle;}
AgentNode: Remove node where
Turtle is found
/**
* Remove the node where this turtle is found.
**/
public void remove(Turtle myTurtle) {
// Assume we're calling on the head
AgentNode head = this;
AgentNode current = (AgentNode) this.getNext();
while (current != null) {
if (current.getAgent() == myTurtle)
{// If found the turtle, remove that node
head.remove(current);
}
current = (AgentNode) current.getNext();
}
}
It’s just like other
linked list removes, but
now we’re looking for
the node that contains
the input turtle.
Think about it…

What if AgentNodes contained
Objects?
• Object is a class that is the superclass of all
•
classes (even if not explicitly extended).
AgentNodes that contain Objects could be
general linked lists that contain anything
• Just cast things as you need them as you pull
them out.
Back to the simulation:
What might we change?



Wolves that aren’t always hungry?
Having wolves that chase deer?
Have deer run from wolves?
And how do we look at the results?
We’ll deal with hunger first, then
with comparing, then with
running towards/away.
Creating a Hungry Wolf
/**
* A class that extends the Wolf to have a Hunger level.
* Wolves only eat when they're hungry
**/
public class HungryWolf extends Wolf {
/**
* Number of cycles before I'll eat again
**/
private int satisfied;
/** class constant for number of turns before hungry */
private static final int MAX_SATISFIED = 3;
Need to
match
/**
* Constructor that takes the model display (the original
* position will be randomly assigned)
* @param modelDisplayer thing that displays the model
* @param mySim my simulation
*/
public HungryWolf (ModelDisplay
modelDisplayer,WolfDeerSimulation thisSim)
{
super(modelDisplayer,thisSim);
}
/** Constructor that takes the x and y and a model
* display to draw it on
* @param x the starting x position
* @param y the starting y position
* @param modelDisplayer the thing that displays the model
* @param mySim my simulation
*/
public HungryWolf (int x, int y, ModelDisplay
modelDisplayer,
WolfDeerSimulation thisSim)
{
// let the parent constructor handle it
super(x,y,modelDisplayer,thisSim);
}
Initializing a HungryWolf
/**
* Method to initialize the hungry wolf object
*/
public void init(WolfDeerSimulation thisSim)
{
super.init(thisSim);
satisfied = MAX_SATISFIED;
}
What a HungryWolf does
/**
* Method to act during a time step
* pick a random direction and move some random amount up to top speed
*/
public void act()
{
// Decrease satisfied time, until hungry again
satisfied--;
// get the closest deer within some specified distance
AgentNode closeDeer = getClosest(30,
(AgentNode) mySim.getDeer().getNext());
if (closeDeer != null)
{ // Even if deer close, only eat it if you're hungry.
if (satisfied <= 0)
{Deer thisDeer = (Deer) closeDeer.getAgent();
this.moveTo(thisDeer.getXPos(),
thisDeer.getYPos());
thisDeer.die();
satisfied = MAX_SATISFIED;
}}
If there is a Deer
near, then check if
you’re hungry, and
only then—eat and
get “full”
And if no Deer are near…
else
{
// if the randome number is > prob of turning then turn
if (randNumGen.nextFloat() > PROB_OF_TURN)
{
this.turn(randNumGen.nextInt(360));
}
Nothing new
here…
// go forward some random amount
forward(randNumGen.nextInt(maxSpeed));
}
}
Changing the Simulation to
make HungryWolves (in run())
// create some wolves
int numWolves = 5;
for (int i = 0; i < numWolves; i++)
{
wolves.add(new AgentNode(new
HungryWolf(w,this)));
Everything else just
}
works, because
HungryWolf is a
kind of Wolf
Writing to a Text File




We have to create a stream that allows
us access to a file.
We’re going to want to write strings to it.
We’re going to have to handle things
going wrong—exceptional events like
the filename being wrong or the disk
failing.
Here’s how…
Input and Output Streams java.io


Java handles input and output through
sequential streams of bits
Programs can read from a stream or write to a
stream
Source
or
Destination
Byte Data
Character Data
File
String
100110
Array
Program
Standard Input and Output

We have been using System.out.println to print
output to a PrintStream (standard output).
System.out.println(“First Name: “ + firstName);

There is also a System.err PrintStream that
can be used to write to the standard error
output.
System.err.println(“Error: no file name given”);

You can use System.in to read a byte or bytes
from an InputStream (standard input).
int numGrades = System.in.read();
Chaining Input and Output
Classes

Often input or output
classes are chained
•

Passing one type of
input/output class to the
constructor for another
One common thing is to
chain a processing class
with a data sink class
•
Like a BufferedReader or
BufferedWriter and a
FileReader or FileWriter
new BufferedReader(new
FileReader(fileName));
Exceptions


Exceptions are disruptions in the normal flow of a
program. Exception is short for exceptional event.
The programmer is required to handle checked
exceptions in Java
•

like trying to read from a file that doesn’t exist
Run-time exceptions do not have to be handled by the
programmer
•
•
like trying to invoke a method on a object reference that is
null
Children of RuntimeException
Try and Catch

Use a try & catch clause to catch an exception
try {
code that can cause exceptions
} catch (ExceptionClassName varName) {
code to handle the exception
} catch (ExceptionClassName varName) {
code to handle the exception
}

You can catch several exceptions
•
•
Make the most general one last
All exceptions are children of the class Exception
Try and Catch: If the file isn’t
there…


What if you want to know if a file isn’t found
•
•
That you are trying to read from
If this occurs you might want to use a JFileChooser to
let the user pick the file
You also want to handle any other error
try {
code that can cause the exception
} catch (FileNotFoundException ex) {
code to handle when the file isn’t found
} catch (Exception ex) {
code to handle the exception
}
Catching Exceptions


A catch clause will catch the given Exception class
and any subclasses of it.
So to catch all exceptions use:
You can print the
error message
code that can throw the exception
and the stack
} catch (Exception e) {
trace (the list of all
System.err.println(“Exception: “ + e.getMessage()); currently running
System.err.println(“Stack Trace is:”);
methods)
try {
e.printStackTrace();
}

You can create your own exceptions by subclassing
Exception or a child of Exception.
The optional finally clause

A try and catch statement can have a finally
clause
•
Which will always be executed
• Will happen if no exceptions
• Will happen even if exceptions occur
try {
code that can cause the exception
} catch (FileNotFoundException ex) {
code to handle when the file isn’t found
} finally {
code to always be executed
}
Writing to a File

Use a try-catch clause to catch
exceptions
• Create a buffered writer from a file writer
writer = new BufferedWriter(new
FileWriter(fileName));
• Write the data
writer.write(data);
• Close the buffered writer
• writer.close();
Reading Lines of Character Data

Enclose the code in a try and catch clause
•
•

And you may want to give the user a chance to specify a new
file
Catch Exception to handle all other errors
File names are relative to the current directory
Loop reading lines from the buffered reader until the
line is null
•

•
Create a buffered reader from a file reader for more
efficient reading
•

Catch FileNotFoundException if the file doesn’t exist
Do something with the data
Close the buffered reader
Reading from File Example
BufferedReader reader = null;
String line = null;
// try to read the file
try {
// create the buffered reader
reader = new BufferedReader(new FileReader(fileName));
// loop reading lines till the line is null (end of file)
while ((line = reader.readLine()) != null)
{
// do something with the line
}
// close the buffered reader
reader.close();
} catch (Exception ex) {
// handle exception
}
Adding an Output File to
WolfDeerSimulation
/* A BufferedWriter for writing to */
public BufferedWriter output;
/**
* Constructor to set output to null
**/
public WolfDeerSimulation() {
output = null;
}
Opening the File
/**
* Open the input file and set the BufferedWriter to speak to it.
**/
public void openFile(String filename){
// Try to open the file
try {
// create a writer
output = new BufferedWriter(new FileWriter(filename));
} catch (Exception ex) {
System.out.println("Trouble open the file " + output);
// If any problem, make it null again
output = null;
}
}
Changing the time loop
// Let's figure out where we stand...
System.out.println(">>> Timestep: "+t);
System.out.println("Wolves left: "+wolves.getNext().count());
System.out.println("Deer left: "+deer.getNext().count());
// If we have an open file, write the counts to it
if (output != null) {
// Try it
try{
output.write(wolves.getNext().count()+"\t"+deer.getNext().count());
output.newLine();
} catch (Exception ex) {
System.out.println("Couldn't write the data!");
System.out.println(ex.getMessage());
// Make output null so that we don't keep trying
output = null;
}
}
After the timing loop
// If we have an open file, close it and null the variable
if (output != null){
try{
output.close();}
catch (Exception ex)
{System.out.println("Something went wrong closing the file");}
finally {
// No matter what, mark the file as not-there
output = null;}
}
Running the Simulation with a
File
Welcome to DrJava.
> WolfDeerSimulation wds = new WolfDeerSimulation();
> wds.openFile("D:/cs1316/wds-run1.txt")
> wds.run();
Finding the file in Excel
Adding Labels for the Chart
25
20
15
Wolves
Deer
10
5
0
1
4
7 10 13 16 19 22 25 28 31 34 37 40 43 46 49
Making Wolves and Deer Run

What we do:
•
•
•
•
In Deer, if there is a Wolf within our smelling range,
run in the opposite direction (turn towards, turn 180,
move)
In Wolf, if there is a Deer within our smelling range,
run towards it.
(Stays the same) If the Wolf gets close enough,
gobble up the Deer.
(Stays the same) For both, otherwise, wander
aimlessly.
New constants for Deer
/** class constant for probability of NOT turning */
private static final double PROB_OF_STAY = 1/5;
/** class constant for how far deer can smell */
private static final double SMELL_RANGE = 50;
/** class constant for top speed (max num steps can move
in a timestep) */
private static final int maxSpeed = 30;
Deer-finding
closest Wolf
Strikingly
similar to
Wolf’s for find
Deer, no?
/**
* Method to get the closest wolf within the passed distance
* to this deer. We'll search the input list of the kind
* of objects to compare to.
*/
public AgentNode getClosest(double distance,AgentNode list)
{
// get the head of the deer linked list
AgentNode head = list;
AgentNode curr = head;
AgentNode closest = null;
Wolf thisWolf;
double closestDistance = 0;
double currDistance = 0;
// loop through the linked list looking for the closest deer
while (curr != null)
{
thisWolf = (Wolf) curr.getAgent();
currDistance =
thisWolf.getDistance(this.getXPos(),this.getYPos());
if (currDistance < distance)
{
if (closest == null || currDistance < closestDistance)
{
closest = curr;
closestDistance = currDistance;
}
}
curr = (AgentNode) curr.getNext();
}
return closest;
}
Deer new
act()
/**
* Method to act during a time step
* pick a random direction and move some random amount
up to top speed
*/
public void act()
{
// get the closest wolf within the smell range
AgentNode closeWolf = getClosest(SMELL_RANGE,
(AgentNode)
mySim.getWolves().getNext());
Does this match the
English description
we had a few slides
back?
if (closeWolf != null) {
Wolf thisWolf = (Wolf) closeWolf.getAgent();
// Turn to face the wolf
this.turnToFace(thisWolf);
// Now directly in the opposite direction
this.turn(180);
// How far to run? How about half of max speed??
this.forward((int) (maxSpeed/2));
}
else {
// if the random number is > prob of NOT turning then turn
if (randNumGen.nextFloat() > PROB_OF_STAY)
{
this.turn(randNumGen.nextInt(360));
}
Think about this in
terms of the values
that can be changed
and their relative
values.
// go forward some random amount
forward(randNumGen.nextInt(maxSpeed));
}
}
Wolf Constants
/** class constant for probability of NOT turning */
protected static final double PROB_OF_STAY = 1/10;
/** class constant for top speed (max num steps can move
in a timestep) */
protected static final int maxSpeed = 40;
/** class constant for how far wolf can smell */
private static final double SMELL_RANGE = 50;
/** class constant for how close before wolf can attack */
private static final double ATTACK_RANGE = 30;
How Wolf’s smell deer
/**
* Method to act during a time step
* pick a random direction and move some random amount up to top speed
*/
public void act()
{
// get the closest deer within smelling range
AgentNode closeDeer = getClosest(SMELL_RANGE,
(AgentNode) mySim.getDeer().getNext());
if (closeDeer != null)
{
Deer thisDeer = (Deer) closeDeer.getAgent();
// Turn torward deer
this.turnToFace(thisDeer);
// How much to move? How about minimum of maxSpeed
// or distance to deer?
this.forward((int) Math.min(maxSpeed,
thisDeer.getDistance(this.getXPos(),this.getYPos())));
}
The rest of
normal
Wolf actions
// get the closest deer within the attack distance
closeDeer = getClosest(ATTACK_RANGE,
(AgentNode) mySim.getDeer().getNext());
if (closeDeer != null)
{
Deer thisDeer = (Deer) closeDeer.getAgent();
this.moveTo(thisDeer.getXPos(),
thisDeer.getYPos());
thisDeer.die();
}
else // Otherwise, wander aimlessly
{
// if the randome number is > prob of NOT turning then
turn
if (randNumGen.nextFloat() > PROB_OF_STAY)
{
this.turn(randNumGen.nextInt(360));
}
// go forward some random amount
forward(randNumGen.nextInt(maxSpeed));
} // end else
} // end act()
Changes to
WolfDeerSimulation…NOTHING!


We have the same interface as we used
to have, so nothing changes in
WolfDeerSimulation.
Very powerful idea:
• If changes to a class keep the interface the
same, then all users of the class don’t have
to change at all.
Running the new simulation
Welcome to DrJava.
> WolfDeerSimulation wds = new
WolfDeerSimulation();
> wds.openFile("D:/cs1316/wdschase.txt")
> wds.run();
18
16
14
12
10
Wolves
8
Deer
6
4
2
0
1
4
7 10 13 16 19 22 25 28 31 34 37 40 43 46 49
Explorations

What does the relative speed of Deer and
Wolves matter?
•

What if Deer and Wolves can smell farther
away?
•


Does it matter if Deer go faster? Wolves?
What if one can smell better than the other?
What’s the effect of having more Deer or more
Wolves?
What if HungryWolves could starve (say at -10
satisfaction)? Do more deer live?
Doing More Simulations

How much code would be in common in
every simulation we’d build?
• We already have lots of duplication, e.g.,
getClosest.

Goal: Can we make an Agent/Actor class
and Simulation class that we’d subclass
with very little additional code to create
new simulations?
Download