In this assignment, you will create a program that uses queues to simulate a busy airport with only one runway, that shares aircraft take-offs and landings, with your program acting as an automated air-traffic controller.
In each unit of time, one plane can land or one plane depart, but not both. Planes arrive ready to land or ready to take off at random times. At any time, there may be an idle runway. An airplane may be landing, or an airplane may be taking off. Also, there may be several planes waiting to land or take off at any time in their respective queues.
You should use two queues, one called arrivalQueue, and the other called departureQueue to hold waiting planes. It is better to keep a plane waiting on the ground than flying overhead, so landing planes get preference. An airplane can take off only if there are no planes waiting to land. Landings and take-offs take a certain period of time, say 10-20 simulated minutes, so the runway is occupied during that period. Use astatic final intconstant to define this flight spacing using a name such as MIN_FLIGHT_SPACING.
You can use loop counters to simulate time increments or if you want to be more realistic, you can use a Java timer with events to simulate elapsed minutes. I used loop counter with each loop iteration counting as one minute. You simulation should run for at least 24 hours or (60 * 24 = 1440 minutes).
When a request is received to land or take off, the simulation must first take care of the first plane waiting to land, if any, and any further airplanes in the arrival queue before allowing a plane to depart.
The simulation will need to be run for many units of time inside a loop or timer. Your program should keep track of interesting statistics related to the problem and report activity and diagnostics in "real-time".
Statistics reported include the number of planes processed, showing takeoffs and landing separately, the average amount of time spent waiting for takeoffs and landings, the number of planes refused service (if any), the percentage of time that the runway is idle, and the number of airplanes left in each queue at the end of the simulation.
The simulation will also make use of the random number generator (Math.Random() method in Java) to provide variations in the arrival of planes into the two queues. You can randomize the number generator so multiple runs of the simulator will produce different results, by seeding it. You can do this by initialing your Random object with a seed like this:
Random r = new Random(System.currentTimeMillis());
The program should prompt the user for the expected rate of arrivals per unit time, as well as the expected number of departures, each of which should be real values greater than 0.0 and less than 1.0, the sum of which should not add up to more than 1.0, which would cause eventual gridlock.
For example, the expected number of arrivals and departures both 0.45 would add up to 0.90, and would provide for a lively simulation, but many canceled arrivals and departures. I picked expected departure and arrivals in the teens, which cause only some not an overwhelming number of cancelations per simulation.
If flights need 10 minutes spacing, for example, then they can arrive or depart approximately every 10 minutes. That works out to be 6 flights per hour or .1 flights per minute, so .1 might be a reasonable expected value. You should experiment with your simulation and see what expected values actually gives the best operational efficiency without not too many cancellations due to overloaded queues. However, if you space your frequencies too far apart, your simulation will have few or no overloaded queues, which is less interesting and from an airport operations standpoint less optimal. You should try different parameters to see how they affect your simulation.
Your program should report sufficient information while the program is running for users to know what the simulation is doing by reporting with print statements showing the arrival and deparature of flights as well as cancellations and diversions.
Arrivals and departures should be random over time and threfore for this simulation, you will want to have the program determine a
random
integer giving the number of planes arriving for landing (or for take-off) in a given time unit, and below we will see how to do this, using what's called a Poisson distribution.
Poisson Distributions
The time that any single airplane enters the system is independent of all other planes. A model is known to generate independent random estimations over time or space in statistics, is called a Poisson distribution.
The Poisson distribution is a distribution of probabilities of something occurring within a given interval of time (or area, volume). In our case, it is a probability P(X) number of arrivals or departures within a period of time, per minute in our case, making arrivals and departures enter the simulation randomly.
In order to use the distribution, we need to a function to pick expected average flight frequencies, that is, the average number of planes arriving or departing in one unit of time.
For example, if one plane arrives per four units of time, the expected value is 0.25. There may be times when several planes arrive in the same time unit, and other times where no planes arrive for several or more time units, but on average over many trials, our estimate is that the average expected value is for instance 0.25. This number is just an example.
Here is a short implementation of Poisson distribution, which your program can use to generate these values.
// mean is user-predicted frequency (arrival or departure per unit of time, e.g. per minute). Example numbers
// might be .14 deparatures/minute, .16 arrivals
public int getPoissonRandom(double mean) {
// Math.RandomSeed(num) // See a good way to seed your randomizer in the discussion above
Random r = new Random();
double L = Math.exp(-mean);
int x = 0;
double p = 1.0;
do {
p = p * r.nextDouble();
x++;
} while (p > L);
return x - 1;
}
This method will return a number: 0,1,2,3,... for how many flights arrive/depart per time period,
giving us a nice random distribution.
`
Here is a video about the Poisson distribution that I found very intuitive if you are interested in learning more.
You should run your program at least three different times to see a variety of results with a minimum of 500-time units per simulation, and a different random seed each time for each test run. Again, also try different input values to see how it affects your simulation.
In my testing, for example, I used two for loops (one for arrivals, one for departures) for a total of 720 x 2 = 1440 iterations, which conveniently is the number of minutes per day, 720 arrivals, and 720 departures. This works out nicely to 24 hours of data since there are 1440 minutes per day. Because sometimes you get zeros and because of random spacing between flights, and limited queue sizes, therfore flights do not almost appear every minute and a fair number may be diverted or canceled, but with 1440 potential flights there is plenty of activity with this setup. Feel free to try other configurations.
Here is my main driver method and an example processArrival method. You will have to code a similar processDeparture method.
public static void main(String[] args) {
double meanArrivalFreq = 0.0;
double meanDepartureFreq = 0.0;
AirTrafficControlSim sim = new AirTrafficControlSim();
Scanner scanner = new Scanner(System.in);
System.out.println("Enter mean departure frequency (0.0 < df=""> 1.0): ");
if (scanner.hasNextDouble())
meanDepartureFreq = scanner.nextDouble();
System.out.println("Enter mean arrival frequency 0.0 < af=""> 1.0): ");
if (scanner.hasNextDouble())
meanArrivalFreq = scanner.nextDouble();
// Each i in the loop represents a minute, 720 x 2 = 1440 minutes in 24 hours
for (int i = 0; i
sim.processArrival(meanArrivalFreq);
sim.processDeparture(meanDepartureFreq);
}
// Print out statistics calculated from the simulation.
sim.printSimSummaryStatistics();
}
void processArrival(double meanArrivalFreq) {
int count = 0;
timerCounter++;
timeInterval++;
if ((count = getPoissonRandom(meanArrivalFreq)) > 0)
addToArrivalQueue(count);
if (timerCounter >= 10) {
if (arrivalQueue.size() > 0) {
removeFromArrivalQueue();
timerCounter = 0;
}
}
}
// processDeparture is basically the same as above. YOu will need to write processDeparture
Note: Again, you should not add flights to the queues unless there are less than 5 flights in the queue already.
Record the output of your simulation at each time unit, showing planes (denote each newly arriving plane with a number, starting from 1 and incrementing as subsequent planes enter either queue). I used an airline code, e.g. "AA" plus the number or "AA1", and a different airline code for arrivals, e.g. "UA". You will want to keep a flightNumberCounter to keep track of your flights: "AA" + flightNumberCounter.
Remember that only one plane can land or depart at a time, but that several planes may wish to enter the takeoff or landing queue in one time-unit, and that there can be a maximum of five planes waiting to land or take off at any given time.
Additional planes wanting to enter a queue beyond five will be told to try again later (denied service).Planes in the air beyond five should be directed to another airport. planes on the ground over five should be denied service due to air traffic control.
Choose a type of Queue to use. Make your Queue of type
The Java Collections library has a number of queue types to choose from (LinkedList, ArrayBlockingQueue, PriorityQueue, ArrayDeque, and others). Queue is an interface and there are various library classes that implement the Queue interface. For various reasons, I choseArrayDeque:(Links to an external site.)
ArrayDeque arrivalQueue = new ArrayDeque<>();
ArrayDeque departureQueue = new ArrayDeque<>();
You could also use a LinkedList as follows:
Queue namesQueue =
new
LinkedList<>();
The class
It is easier to manage this project if you set up a Flight class. Mine looks like this
enum FlightType {Arrival, Departure};
class Flight {
String flightNumber;
FlightType flightType;
int minuteInQueue;
int minuteOutQueue;
// constructor
public Flight(String flightNumber, FlightType flightType) {
this.flightNumber = flightNumber;
this.flightType = flightType;
}
public String toString() {
return flightType + ": " + flightNumber;
}
// "minute" that flight entered the queue
public void setMinuteInQueue(int minute) {
this.minuteInQueue = minute;
}
// "minute" that flight exits the queue
// difference is time in queue
public void setMinuteOutQueue(int minute) {
this.minuteOutQueue = minute;
}
public int timeInQueue() {
return minuteOutQueue - minuteInQueue;
}
}
The flight class contains a flightNumber and FlightType. Two other attributes are provided for statistical purposes. The minuteInQueue tracks the minute integer when a flight is added to a queue and minuteOutQueue is the minute integer the flight is removed from a queue. The difference gives us the amount of time the flight was in the queue in minutes.
Converting minute timeInterval to Hours: Minutes
The flight class contains a flightNumber and FlightType. Two other attributes are provided for statistical purposes. The minuteInQueue tracks the minute integer, when a flight is added to a queue and minuteOutQueue, is the minute the flight is removed from a queue. The difference gives us the amount of time the flight was in the queue.
You may want to convert your elapsed minutes into a more interesting format that looks like a time hours and minutes (HH:mm). This is easy:
timeInterval/60 + ":" + String.format("%02d",timeInterval % 60)
The above will convert a timeInterval into a format of: HH:mm, which makes for
nicer simulation output.
Statistical Data
It is a good idea, and required, to keep copies of the flights in the simulation for statistical purposes.after they are removed from the simulation. I named these as follows:
ArrayList arrivalStatistics = new ArrayList<>();
ArrayList departureStatistics = new ArrayList<>();
When adding a flight to a queue, do the following to track the time the flight entered a queue.
departureFlight.setMinuteInQueue(timeInterval);
departureQueue.add(departureFlight);
When removing a flight from its queue, add the flight to the ArrayList for saving flight statistical data as follows:
Flight departureFlight = departureQueue.removeFirst(); // remove top item from queue
departureFlight.setMinuteOutQueue(timeInterval); // set time flight leaves the queue
departureStatistics.add(departureFlight); // Save flight in departureStatistics queue.
// Do the same for the arrival queue.
Now it is pretty easy to get the timeInQueue for the list used for calculating averages by adding up and averaging a flight type using the following method:
fight.timeInQueue()
Sample Simulation Output File
AirTrafficControlSimulation.pdf
Actions
Submission Guidelines
Turn in a properly written, indented, and commented program that runs the airport simulation as described above, using two queues of five elements each, and the results of three runs of the simulation, as well a the statistical summary data described above.
Copy the output console data from the IntelliJ console. Also, include computer-readable Java source code file(s).