You are on page 1of 79

Problem Solving with Data

Structures using Java:


A Multimedia Approach

Chapter 17: Discrete Event


Simulation
Chapter Objectives
Story
 Discrete event simulation
• Simulation time != real time
 Key ideas:
• A Queue
• A Queue is a queue, no matter how implemented.
• Different kinds of random
• Straightening time
• Inserting it into the right place
• Sorting it afterwards
 Building a discrete event simulation
• Graphics as the representation, not the real thing: The
Model and the View
Imagine the simulation…
 There are three Trucks that bring product from the
Factory.
• On average, they take 3 days to arrive.
• Each truck brings somewhere between 10 and 20
products—all equally likely.
 We’ve got five Distributors who pick up product from the
Factory with orders.
• Usually they want from 5 to 25 products, all equally likely.
 It takes the Distributors an average of 2 days to get back
to the market, and an average of 5 days to deliver the
products.
 Question we might wonder: How much product gets sold
like this?
Don’t use a Continuous
Simulation
 We don’t want to wait that number of days in real time.
 We don’t even care about every day.
• There will certainly be timesteps (days) when nothing
happens of interest.
 We’re dealing with different probability distributions.
• Some uniform, some normally distributed.
 Things can get out of synch
• A Truck may go back to the factory and get more product
before a Distributor gets back.
• A Distributor may have to wait for multiple trucks to fulfill
orders (and other Distributors might end up waiting in line)
We use a Discrete Event
Simulation
 We don’t simulate every moment
continuously.
 We simulate discrete events.
What’s the difference?
No time loop
 In a discrete event simulation: There is
no time loop.
• There are events that are scheduled.
• At each run step, the next scheduled event
with the lowest time gets processed.
• The current time is then that time, the time that that
event is supposed to occur.
 Key: We have to keep the list of
scheduled events sorted (in order)
What’s the difference?
Agents don’t act()
 In a discrete event simulations, agents
don’t act().
• Instead, they wait for events to occur.
• They schedule new events to correspond to
the next thing that they’re going to do.
 Key: Events get scheduled according to
different probabilities.
What’s the difference?
Agents get blocked
 Agents can’t do everything that they want to do.
 If they want product (for example) and there isn’t any,
they get blocked.
• They can’t schedule any new events until they get
unblocked.
 Many agents may get blocked awaiting the same
resource.
• More than one Distributor may be awaiting arrival of Trucks
 Key: We have to keep track of the Distributors waiting in
line (in the queue)
Key Ideas
 Already presented, but now used:
A Queue
• A Queue is a queue, no matter how implemented.
 Different kinds of random
 Straightening time
• Inserting it into the right place
• Sorting it afterwards
Key idea:
Different kinds of random

 We’ve been dealing with uniform random


distributions up until now, but those are
the least likely random distribution in real
life.
 How can we generate some other
distributions, including some that are
more realistic?
• The classic bell-shaped curve
import java.util.*; // Need this for Random

Generating
import java.io.*; // For BufferedWriter

public class GenerateUniform {

a uniform public static void main(String[] args) {


Random rng = new Random(); // Random Number Generator

distribution BufferedWriter output=null; // file for writing

// Try to open the file


try {
// create a writer
output =
new BufferedWriter(new FileWriter("D:/cs1316/uniform.txt"));
} catch (Exception ex) {
System.out.println("Trouble opening the file.");
}
By writing out a // Fill it with 500 numbers between 0.0 and 1.0, uniformly
tab and the distributed
for (int i=0; i < 500; i++){
integer, we don’t try{
have to do the output.write("\t"+rng.nextFloat());
string conversion. output.newLine();
} catch (Exception ex) {
System.out.println("Couldn't write the data!");
System.out.println(ex.getMessage());
}
}
// Close the file
try{
output.close();}
catch (Exception ex)
{System.out.println("Something went wrong closing the file");}
}
}
Generating a Histogram
 Now we have lots of numbers between 0
and 1.
 We want to count the number between
• 0.9 and 1.0,
• 0.8 and 0.9,
• 0.7 and 0.8, and so on.
 We need to count them into bins.
• Great job for a Map!
HistogramGenerator
import java.util.*;
import java.io.*;

/** For a given value


* Class to generate a histogram (like 0.8), we want
* @author Mark Guzdial a count.
* @author Barb Ericson That’s Double-
*/ >Integer map
public class HistogramGenerator {

/** the map to hold the values */


private Map<Double,Integer> valueMap =
new TreeMap<Double,Integer>();
/**
* Method to read a set of values from the inputFile and create
* bins based on the array of keys. This will count the number
* of values in each bin. Any value larger than the last key
* will be put in the last bin.
* @param inputFile the file to read from
* @param an array of key values to use
*/
public void countValuesForKeys(String inputFile, double[] keys) {

BufferedReader reader = null;


String line = null;
double doubleValue = 0.0;
boolean found = false;
int lastIndex = keys.length - 1;

// put the keys in the map using a count of 0


for (int i = 0; i < keys.length; i++) {
valueMap.put(keys[i],0);
}
try {
// open the file
reader = new BufferedReader(new FileReader(inputFile));

// loop reading from the file


while ((line = reader.readLine()) != null) {
doubleValue = Double.parseDouble(line);
found = false;
for (double key : keys) {
if (doubleValue < key) { If the double value we read is less
valueMap.put(key,valueMap.get(key) + 1);
than this key, increment the count
found = true;
at that key
break;
}
}
if (!found) valueMap.put(keys[lastIndex],
valueMap.get(keys[lastIndex]) + 1);
}

// close the file


reader.close();

} catch (Exception ex) {


System.out.println(ex.getMessage());
ex.printStackTrace();
}
}
/**
* Method to read a set of values from the inputFile create even
* bins based on the passed factor. This will count the number
* of values in each bin.
* @param inputFile the file to read from
* @param factor the factor to use to break the values into bins
*/
public void countValues(String inputFile, int factor) {

BufferedReader reader = null;


String line = null;
double doubleValue = 0.0;
double key = 0.0;
int currCount = 0;

try {
// open the file
reader = new BufferedReader(new FileReader(inputFile));
// loop reading from the file
while ((line = reader.readLine()) != null) {
doubleValue = Double.parseDouble(line);
doubleValue = doubleValue * factor;
key = Math.ceil(doubleValue) / (double) factor;
if (valueMap.containsKey(key)) {
currCount = valueMap.get(key);
currCount++;
valueMap.put(key,currCount);
}
else {
valueMap.put(key,1);
}
}

// close the file


reader.close();

} catch (Exception ex) {


System.out.println(ex.getMessage());
ex.printStackTrace();
}

}
Now, write the counts to a file
for graphing
/**
* Method to output the keys and values in the histogram
* to a file
* @param fileName the name of the file to write to
*/
public void writeFile(String fileName) {

BufferedWriter writer = null;


double key = 0;
int value = 0;
Set<Double> keySet = null;
try {

// create the writer


writer = new BufferedWriter(new FileWriter(fileName));

// get the keys and loop through them


keySet = valueMap.keySet();
Iterator<Double> iterator = keySet.iterator();
while (iterator.hasNext()) {
key = iterator.next();
value = valueMap.get(key);
writer.write(key + "\t" + value);
writer.newLine();
}

// close the writer


writer.close();

} catch (Exception ex) {


System.out.println(ex.getMessage());
ex.printStackTrace();
}

}
/**
* Generate the histogram from the uniform data
*/
public static void genUniform() {
Using it HistogramGenerator histGen = new HistogramGenerator();
double[] keyArray = {0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0};
histGen.countValuesForKeys("C:/dsBook/uniform.txt",keyArray);
histGen.writeFile("C:/dsBook/uniformHist.txt");
}

/**
* Method to generate the normal histogram
*/
public static void genNormal() {
HistogramGenerator histGen = new HistogramGenerator();
double[] keyArray = {-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3,
-0.2, -0.1,0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0};
histGen.countValuesForKeys("C:/dsBook/normal.txt",keyArray);
histGen.writeFile("C:/dsBook/normalHist.txt");
}
How do we view a distribution?
A Histogram
Load the values into a Spreadsheet,
Then graph the result

A uniform distribution
A Uniform Distribution
Frequency

70
60
50
40
Frequency
30
20
10
0
2

8
0

1
0.

0.

0.

0.
A Normal
Distribution
// Fill it with 500 numbers between -1.0 and 1.0, normally distributed
for (int i=0; i < 500; i++){
try{
output.write("\t"+rng.nextGaussian());
output.newLine();
} catch (Exception ex) {
System.out.println("Couldn't write the data!");
System.out.println(ex.getMessage());
}
}
Again, in a Spreadsheet
Graphing the normal distribution
Frequency

30
25
20
15 Frequency
10
5 The end aren’t
actually high—
0 the tails go
6 2 8 4 further.
-2 . . . . 0
0.
4
0.
8
1.
2
1.
6 2
-1 -1 -0 -0
How do we shift the distribution
where we want it?
// Fill it with 500 numbers with a mean of 5.0 and a
//larger spread, normally distributed
for (int i=0; i < 500; i++){
try{
output.write("\t"+((range * rng.nextGaussian())+mean));
output.newLine();
} catch (Exception ex) {
System.out.println("Couldn't write the data!");
System.out.println(ex.getMessage());
}
}
Multiply the random nextGaussian()
by the range you want, then add the
mean to shift it where you want it.
A new normal distribution
Frequency

18
16
14
12
10
Frequency
8
6
4
2
0
-2

-1

10
-1.5

-0.5

0.5

1.5

2.5

3.5

4.5

5.5

6.5

7.5

8.5

9.5
Key idea:
Ordering Events by Time
 Straightening time
• Inserting it into the right place
• Sorting it afterwards
 We’ll actually do these in reverse order:
• We’ll add a new event, then sort it.
• Then we’ll insert it into the right place.
public class EventQueueExercisor {
public static void main(String[] args){
// Make an EventQueue

Exercising
EventQueue queue = new EventQueue();

// Now, stuff it full of events, out of order.

an EventQueue SimEvent event = new SimEvent();


event.setTime(5.0);
queue.add(event);

event = new SimEvent();


event.setTime(2.0);
We’re stuffing the EventQueue queue.add(event);
with events whose times are out of
event = new SimEvent();
order. event.setTime(7.0);
queue.add(event);

event = new SimEvent();


event.setTime(0.5);
queue.add(event);

event = new SimEvent();


event.setTime(1.0);
queue.add(event);

// Get the events back, hopefull in order!


for (int i=0; i < 5; i++) {
event = queue.pop();
System.out.println("Popped event
time:"+event.getTime());
}
}
}
If it works right, should look like
this:
Welcome to DrJava.
> java EventQueueExercisor
Popped event time:0.5
Popped event time:1.0
Popped event time:2.0
Popped event time:5.0
Popped event time:7.0
Implementing an EventQueue
import java.util.*;

/**
* EventQueue
* It's called an event "queue," but it's not really.
* Instead, it's a list (could be an array, could be a linked list)
* that always keeps its elements in time sorted order.
* When you get the nextEvent, you KNOW that it's the one
* with the lowest time in the EventQueue
**/
public class EventQueue {
private LinkedList elements;

/// Constructor
public EventQueue(){
elements = new LinkedList();
}
Mostly, it’s a queue
public SimEvent peek(){
return (SimEvent) elements.getFirst();}

public SimEvent pop(){


SimEvent toReturn = this.peek();
elements.removeFirst();
return toReturn;}

public int size(){return elements.size();}

public boolean empty(){return this.size()==0;}


Two options for add()
/**
* Add the event.
* The Queue MUST remain in order, from lowest time to
highest.
**/
public void add(SimEvent myEvent){
// Option one: Add then sort
elements.add(myEvent);
this.sort();
//Option two: Insert into order
//this.insertInOrder(myEvent);
}
There are lots of sorts!
 Lots of ways to keep things in order.
• Some are faster – best are O(n log n)
• Some are slower – they’re always O(n2)
• Some are O(n2) in the worst case, but on
average, they’re better than that.
 We’re going to try an insertion sort
How an insertion sort works
 Consider the event at some position (1..n)
 Compare it to all the events before that
position backwards—towards 0.
• If the comparison event time is LESS THAN the
considered event time, then shift the comparison
event down to make room.
• Wherever we stop, that’s where the considered event
goes.
 Consider the next event…until done
Insertion
Sort
public void sort() {

// For comparing to elements at smaller indices


SimEvent considered = null;
SimEvent compareEvent = null; // Just for use in loop
// Smaller index we're comparing to
int compare;

// Start out assuming that position 0 is "sorted"


// When position==1, compare elements at indices 0 and 1
// When position==2, compare at indices 0, 1, and 2, etc.
for (int position=1; position < elements.size(); position++) {
considered = (SimEvent) elements.get(position);
// Now, we look at "considered" versus the elements
// less than "compare"
compare = position;
// While the considered event is greater than the compared event ,
// it's in the wrong place, so move the elements up one.
compareEvent = (SimEvent) elements.get(compare-1);
while (compareEvent.getTime() >
considered.getTime()) {
elements.set(compare,elements.get(compare-1));
compare = compare-1;
// If we get to the end of the array, stop
if (compare <= 0) {
break;
}
// else get ready for the next time through the loop
else {
compareEvent = (SimEvent) elements.get(compare-1);
}
}
// Wherever we stopped, this is where "considered" belongs
elements.set(compare,considered);
} // for all positions 1 to the end
} // end of sort()
Sorting is expensive
 It takes a lot of time to re-sort the event
queue each time.
 Better option: Put each new event in the
right place as it enters the queue.
Option #2: Put it in the right
place
/**
* Add the event.
* The Queue MUST remain in order, from lowest time to
highest.
**/
public void add(SimEvent myEvent){
// Option one: Add then sort
//elements.add(myEvent);
//this.sort();
//Option two: Insert into order
this.insertInOrder(myEvent);
}
insertInOrder()
/**
* Put thisEvent into elements, assuming
* that it's already in order.
**/
public void insertInOrder(SimEvent thisEvent){
SimEvent comparison = null;

// Have we inserted yet?


boolean inserted = false;
for (int i=0; i < elements.size(); i++){
comparison = (SimEvent) elements.get(i);
// Assume elements from 0..i are less than thisEvent
// If the element time is GREATER, insert here and
// shift the rest down
if (thisEvent.getTime() < comparison.getTime()) {
//Insert it here
inserted = true;
elements.add(i,thisEvent);
break; // We can stop the search loop
}
} // end for

// Did we get through the list without finding something


// greater? Must be greater than any currently there!
if (!inserted) {
// Insert it at the end
elements.addLast(thisEvent);}
}
Option #3: Min-Heap
 So, we don’t really need to sort or insert in order.
 The critical thing is that each pop() gives us the
smallest time.
 A min-heap is a kind of binary tree that is complete
and where the value at each node is less than or
equal to the values stored in the children nodes.
• A complete binary tree has all nodes filled except the last
(bottom/deepest) level, and the bottom is filled left-to-right.
Example Min-Heap

The top value here (the 5) is


guaranteed to be the lowest
value
Adding a “3”

Add 3 to right

But can’t
have 3
below 10!

Final
And can’t have 5
version!
above 3
Java’s PriorityQueue does this!
 The Java class PriorityQueue already
implements a min-heap.
 Our third option is just to use the
PriorityQueue for the EventQueue.
• But now you know what the options are and
how they work.
Finally: A Discrete Event
Simulation
 Now, we can assemble queues, different
kinds of random, and a sorted
EventQueue to create a discrete event
simulation.
Running a DESimulation
Welcome to DrJava.
> FactorySimulation fs = new
FactorySimulation();
> fs.openFrames("D:/temp/");
> fs.run(25.0)
What we see (not much)
The detail tells the story
Time: 1.7078547183397625 Distributor: 0 Arrived at warehouse
Time: 1.7078547183397625 Distributor: 0 is blocking
>>> Timestep: 1
Time: 1.727166341118611 Distributor: 3 Arrived at warehouse
Time: 1.727166341118611 Distributor: 3 is blocking
>>> Timestep: 1
Notice that
Time: 1.8778754913001443 Distributor: 4 Arrived at warehouse
Time: 1.8778754913001443 Distributor: 4 is blocking time 2 never
>>> Timestep: 1 occurs!
Time: 1.889475045031698 Distributor: 2 Arrived at warehouse
Time: 1.889475045031698 Distributor: 2 is blocking
>>> Timestep: 1
Time: 3.064560375192933 Distributor: 1 Arrived at warehouse
Time: 3.064560375192933 Distributor: 1 is blocking
>>> Timestep: 3
Time: 3.444420374970288 Truck: 2 Arrived at warehouse with load 13
Time: 3.444420374970288 Distributor: 0 unblocked!
Time: 3.444420374970288 Distributor: 0 Gathered product for orders of 11
>>> Timestep: 3
Time: 3.8869697922832698 Truck: 0 Arrived at warehouse with load 18
Time: 3.8869697922832698 Distributor: 3 unblocked!
Time: 3.8869697922832698 Distributor: 3 Gathered product for orders of 12
>>> Timestep: 3
What questions we can answer
 How long do distributors wait?
• Subtract the time that they unblock from the time that
they block
 How much product sits in the warehouse?
• At each time a distributor leaves, figure out how much
is left in the warehouse.
 How long does the line get at the warehouse?
• At each block, count the size of the queue.
 Can we move more product by having more
distributors or more trucks?
• Try it!
How DESimulation works
Turtle
LinkedList
-heading * +frames FrameSequence
-XPos
-YPos
+show()
+forward() 1
+replay()
+turn() 1 #agents
+setColor()
Agent -world World
+setPenDown() Simulation
#speed
1 #output
+init() 1 +setPicture()
+getAgents()
+die()
*
#simulation +add() 1
+getClosest()
+remove()
+countInRange() EventQueue
+openFrames()
+act() *
1 +setUp()
*
+openFile() -events +peek()
Queue +run() +add()
+endStep() +pop()
-blocked +lineForFile()
+push() 1 +size()
+closeFile() +empty()
+peek()
+pop() 1 +insertInOrder()
+empty() * +sort()
DEAgent +size()
-blocked Resource
+isBlocked() -amount
+isReady()
+amountAvailable() DESimluation
+validTime()
+consume()
+waitFor() -now
+add()
+unblocked() +getTime() *
+addToList()
+processEvent() +addEvent()
+log()
+run()
FactorySimulation: Extend a few
classes
Turtle
LinkedList
-heading * +frames FrameSequence
-XPos
-YPos
+show()
+forward() 1
+replay()
+turn() 1 #agents
+setColor()
Agent -world World
+setPenDown() Simulation
#speed
1 #output
+init() 1 +setPicture()
+getAgents()
+die()
*
#simulation +add() 1
+getClosest()
+remove()
+countInRange() EventQueue
+openFrames()
+act() *
1 +setUp()
*
Queue +openFile() -events +peek()
+run() +add()
-blocked +endStep() +pop()
+push() +lineForFile()
DEAgent 1 +size()
+peek() * +closeFile() +empty()
-blocked +pop() 1
+insertInOrder()
+isBlocked() +empty()
Resource +sort()
+isReady() +size()
+validTime() -amount
DESimluation
+waitFor() +amountAvailable()
+unblocked() +consume() -now
+processEvent() +add() +getTime() *
+addToList() +addEvent()
+log()
Distributor +run()
Truck -amountOrdered

-load +newOrders() -factory


+timeToDeliver() FactoryProduct
+newLoad() +tripTime()
+tripTime() FactorySimulation
+init() 1
+init() +processEvents()
+processEvents() +isReady() +setUp()
+unblocked() *
+getFactory()
DESimulation: Sets the Stage
 DESimulation calls setUp to create
agents and schedule the first events.
 It provides log for writing things out to
the console and a text file.
 When it run()’s, it processes each event
in the event queue and tells the
corresponding agent to process a
particular message.
What a DESimulation does:
// While we're not yet at the stop time,
// and there are more events to process
while ((now < stopTime) && (!events.empty())) {
topEvent = events.pop();

// Whatever event is next, that time is now As long as there are


now = topEvent.getTime();
// Let the agent now that its event has occurred
events in the queue,
topAgent = topEvent.getAgent(); and we’re not at the
topAgent.processEvent(topEvent.getMessage()); stopTime:

// repaint the world to show the movement Grab an event.


// IF there is a world
if (world != null) {
Make it’s time “now”
world.repaint();} Process the event.
// Do the end of step processing
this.endStep((int) now);
}
What’s an Event (SimEvent)?
/**
* SimulationEvent (SimEvent) -- an event that occurs in a simulation,
* like a truck arriving at a factory, or a salesperson leaving the It’s a time, an
* market
**/
Agent, and an
public class SimEvent{ integer that the
/// Fields /// Agent will
/** When does this event occur? */ understand as a
public double time; message
/** To whom does it occur? Who should be informed when it occurred? */
public DEAgent whom;

/** What is the event? We'll use integers to represent the meaning
* of the event -- the "message" of the event.
* Each agent will know the meaning of the integer for themselves.
**/
public int message;
DEAgent: Process events, block
if needed
 DEAgents define the constants for messages:
What will be the main events for this agent?
 If the agent needs a resource, it asks to see if
it’s available, and if not, it blocks itself.
 It will be told to unblock when it’s ready.
 Agents are responsible for scheduling their
OWN next event!
An Example: A Truck
/**
* Truck -- delivers product from Factory
* to Warehouse.
**/
public class Truck extends DEAgent {

/////// Constants for Messages


public static final int FACTORY_ARRIVE = 0;
public static final int WAREHOUSE_ARRIVE = 1;

////// Fields /////


/**
* Amount of product being carried
**/
public int load;
How Trucks start
/**
* Set up the truck
* Start out at the factory
**/
public void init(Simulation thisSim){
// Do the default init
super.init(thisSim);
this.setPenDown(false); // Pen up The truck gets a load,
this.setBodyColor(Color.green); // Let green deliver!
then schedules itself
// Show the truck at the factory to arrive at the
this.moveTo(30,350); Warehouse.
// Load up at the factory, and set off for the warehouse
load = this.newLoad();
((DESimulation) thisSim).addEvent(
new SimEvent(this,tripTime(),WAREHOUSE_ARRIVE));
}
tripTime() uses the normal
distribution
/** A trip distance averages 3 days */
public double tripTime(){
double delay = randNumGen.nextGaussian()+3;
if (delay < 1)
// Must take at least one day
{return 1.0+((DESimulation) simulation).getTime();}
else {return delay+((DESimulation) simulation).getTime();}
}
newLoad() uses uniform
/** A new load is between 10 and 20 on a
uniform distribution */
public int newLoad(){
return 10+randNumGen.nextInt(11);
}
How a Truck processes Events
/**
* Process an event.
* Default is to do nothing with it.
**/
public void processEvent(int message){
switch(message){
case FACTORY_ARRIVE:
// Show the truck at the factory
((DESimulation) simulation).log(this.getName()+"\t Arrived at factory");
this.moveTo(30,350);
// Load up at the factory, and set off for the warehouse
load = this.newLoad();
((DESimulation) simulation).addEvent(
new SimEvent(this,tripTime(),WAREHOUSE_ARRIVE));
break;
Truck Arriving at the Warehouse
case WAREHOUSE_ARRIVE:
// Show the truck at the warehouse
((DESimulation) simulation).log(this.getName()+"\t Arrived at
warehouse with load \t"+load);
this.moveTo(50,50);
// Unload product -- takes zero time (unrealistic!)
((FactorySimulation) simulation).getFactory().add(load);
load = 0;
// Head back to factory
((DESimulation) simulation).addEvent(
new SimEvent(this,tripTime(),FACTORY_ARRIVE));
break;
}
What Resources do
 They keep track of what amount they have
available (of whatever the resource is).
 They keep a queue of agents that are blocked
on this resource.
 They can add to the resource, or have it
consume(d).
• When more resource comes in, the head of the queue
gets asked if it’s enough. If so, it can unblock.
How Resources alert agents
/**
* Add more produced resource.
* Is there enough to unblock the first
* Agent in the Queue?
**/
public void add(int production) {
amount = amount + production;

if (!blocked.empty()){
// Ask the next Agent in the queue if it can be unblocked
DEAgent topOne = (DEAgent) blocked.peek();
// Is it ready to run given this resource?
if (topOne.isReady(this)) {
// Remove it from the queue
topOne = (DEAgent) blocked.pop();
// And tell it it’s unblocked
topOne.unblocked(this);
}
}
}
An example blocking agent:
Distributor
/**
* Distributor -- takes orders from Market to Warehouse,
* fills them, and returns with product.
**/
public class Distributor extends DEAgent {

/////// Constants for Messages


public static final int MARKET_ARRIVE = 0;
public static final int MARKET_LEAVE = 1;
public static final int WAREHOUSE_ARRIVE = 2;

/** AmountOrdered so-far */


int amountOrdered;
Distributors start in the Market
public void init(Simulation thisSim){
//First, do the normal stuff
super.init(thisSim);
this.setPenDown(false); // Pen up
this.setBodyColor(Color.blue); // Go Blue!

// Show the distributor in the market


this.moveTo(600,460); // At far right
// Get the orders, and set off for the warehouse
amountOrdered = this.newOrders();
((DESimulation) thisSim).addEvent(
new SimEvent(this,tripTime(),WAREHOUSE_ARRIVE));
}
Distributors have 3 events
 Arrive in Market: Schedule how long it’ll
take to deliver.
 Leave Market: Schedule arrive at the
Factory
 Arrive at Warehouse: Is there enough
product available? If not, block and wait
for trucks to bring enough product.
Processing Distributor Events
/**
* Process an event.
* Default is to do nothing with it.
**/
public void processEvent(int message){
switch(message){
case MARKET_ARRIVE:
// Show the distributor at the market, far left
((DESimulation) simulation).log(this.getName()+"\t Arrived at
market");
this.moveTo(210,460);
// Schedule time to deliver
((DESimulation) simulation).addEvent(
new SimEvent(this,timeToDeliver(),MARKET_LEAVE));
break;
Leaving the Market
case MARKET_LEAVE:
// Show the distributor at the market, far right
((DESimulation) simulation).log(this.getName()+"\t
Leaving market");
this.moveTo(600,460);
// Get the orders, and set off for the warehouse
amountOrdered = this.newOrders();
((DESimulation) simulation).addEvent(
new
SimEvent(this,tripTime(),WAREHOUSE_ARRIVE));
break;
Arriving at the Warehouse
case WAREHOUSE_ARRIVE:
// Show the distributor at the warehouse
((DESimulation) simulation).log(this.getName()+"\t Arrived at warehouse");
this.moveTo(600,50);
// Is there enough product available?
FactoryProduct factory = ((FactorySimulation) simulation).getFactory();
if (factory.amountAvailable() >= amountOrdered)
{
// Consume the resource for the orders
factory.consume(amountOrdered); // Zero time to load?
((DESimulation) simulation).log(this.getName()+"\t Gathered product for orders of
\t"+amountOrdered);
// Schedule myself to arrive at the Market
((DESimulation) simulation).addEvent(
new SimEvent(this,tripTime(),MARKET_ARRIVE));
}
else {// We have to wait until more product arrives!
((DESimulation) simulation).log(this.getName()+"\t is blocking");
waitFor(((FactorySimulation) simulation).getFactory());}
break;
Is there enough product?
/** Are we ready to be unlocked? */
public boolean isReady(Resource res) {
// Is the amount in the factory more than our orders?
return ((FactorySimulation) simulation).getFactory().
amountAvailable() >= amountOrdered;}
If so, we’ll be unblocked
/**
* I've been unblocked!
* @param resource the desired resource
**/
public void unblocked(Resource resource){
super.unblocked(resource);

// Consume the resource for the orders


((DESimulation) simulation).log(this.getName()+"\t unblocked!");
((FactoryProduct) resource).consume(amountOrdered); // Zero time to load?
((DESimulation) simulation).log(this.getName()+"\t Gathered product for orders
of \t"+amountOrdered);
// Schedule myself to arrive at the Market
((DESimulation) simulation).addEvent(
new SimEvent(this,tripTime(),MARKET_ARRIVE));
}
The Overall Factory Simulation
/**
* FactorySimulation -- set up the whole simulation,
* including creation of the Trucks and Distributors.
**/
public class FactorySimulation extends DESimulation {

private FactoryProduct factory;

/**
* Accessor for factory
**/
public FactoryProduct getFactory(){return factory;}
Setting up the Factory
Simulation
public void setUp(){
// Let the world be setup
super.setUp();
// Give the world a reasonable background
FileChooser.setMediaPath("D:/cs1316/MediaSources/");
world.setPicture(new Picture(
FileChooser.getMediaPath("EconomyBackground.jpg")));

// Create a factory resource


factory = new FactoryProduct(); //Track factory product

// Create three trucks


Truck myTruck = null;
for (int i=0; i<3; i++){
myTruck = new Truck(world,this);
myTruck.setName("Truck: "+i);}

// Create five Distributors


Distributor sales = null;
for (int i=0; i<5; i++){
sales = new Distributor(world,this);
sales.setName("Distributor: "+i);}
}
A Class that Shouldn’t Exist
/**
* FactoryProduct -- Represents the products
* in the factory, which is the resource that
* the Truck produces and the Distributor
consumes.
**/
public class FactoryProduct extends Resource {
}
The Master Data Structure List:
We use almost everything here!
 Queues: For storing the agents waiting
in line.
 EventQueues: For storing the events
scheduled to occur.
 LinkedList: For storing all the agents.
Thin-line between data and
program
 What happens in a computation is about an
interaction between the program and the
data.
• Sometimes the data ‘tells’ the computer what to
do, like the operations in the branches of the
scene graph.
 Just seeing the source code doesn’t tell you
what’s going to happen.
• Data is important, and data can specify behavior.

You might also like