package simulator; /* * ContinuousRide.java * Created on Jan 9, 2005 * */ /** * ContinuousRide - This class implements the continuous rides at the amusement * park. These rides may dispatch cars that are empty, but can only dispatch * at most 1 car per minute. Example continuous rides are like the aerial tram. * @author Ping * */ public class ContinuousRide extends Attraction { public static String ATTRACTION_TYPE = "Continuous"; // This constant describes the number of carloads of people in line // before we have to add a car protected final static int NUM_OF_CARLOADS_THRESHOLD = 5; // this is percentage of a sequence of empty cars out of all the cars before // we remove a car. protected final static int PERCENT_OF_EMPTY_CARS = 33; // This stores the number of empty cars launched in a row protected int numOfEmptyCars; /** * @param attractionName * @param entrance * @param exit * @param initialNumOfCars * @param maxNumOfCarsPossible * @param carCapacity * @param rideTime */ public ContinuousRide(String attractionName, Location entrance, Location exit, int initialNumOfCars, int maxNumOfCarsPossible, int carCapacity, int rideTime) { // Note that continuous rides have no loading time, so we pass in 0. super(attractionName, entrance, exit, initialNumOfCars, maxNumOfCarsPossible, carCapacity, rideTime, 0); } /* * This function determines if we should add a car to the ride or not */ protected boolean shouldAddCar() { int threshold = NUM_OF_CARLOADS_THRESHOLD * carCapacity; // we should add a car if our total capacity is less than the number of people waiting // and we haven't reached our full capacity in terms of number of cars return threshold < waitingLine.size() && cars.size() < maxNumOfCarsPossible; } /* * This function determines if we should remove a car from the attraction */ protected boolean shouldRemoveCar() { int numCars = cars.size(); // make it into a percentage, first multiply by 100 so we don't have to deal // with double precision and rounding issues int temp = numOfEmptyCars * 100; temp /= numCars; return temp > PERCENT_OF_EMPTY_CARS && numCars > 1; } /** * This function should be called when the attraction first opens * */ public void openRide() { super.openRide(); numOfEmptyCars = 0; } /** * This function returns the estimated waiting time for this ride. * It does not have to be 100% accurate but should present a rough * estimate as to when someone will get on the ride (assuming he/she * enters the waiting line right now). * * @return int representing the expected number of minutes someone will wait */ public int getEstimatedWaitTime() { if(timeSinceEstimate >= TIME_UNTIL_NEW_ESTIMATES) { timeSinceEstimate = 0; estimatedWaitTime = 0; try { ContinuousRide clone = (ContinuousRide)this.clone(); clone.setSimulationMode(true); // the line not only needs to be empty, but there needs to be // a car available thats not on the ride already while(clone.getLineLength() > 0 || !clone.hasCarAvailable()) { clone.onClockTick(); estimatedWaitTime++; } } catch(CloneNotSupportedException e) { e.printStackTrace(); } } return estimatedWaitTime; } public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * This function must remove customers from the waiting queue and put * them on rides (if there are space available) or remove customer from rides * (if they are done) during each clock tick. * */ public boolean onClockTick() { // since we can only launch 1 car per turn, we should keep track // of whether we have launched a car or not. Car dispatchedCar = null; Customer[] riders; // we could use an iterator here, but we have more control if we do the // loop ourselves since we are adding/removing items from the list for(int i = 0; i < cars.size(); i++) { Car c = cars.get(i); if(c.isCarDone()) { // unload the car c.unloadCustomers(); } if(c.isCarWaiting() && dispatchedCar == null) { riders = extractCustomers(); c.loadCustomers(riders); // this car is ready to be launched, so lets remove it and // put it in at the end. This might always be the first element c.dispatchCar(); if(c.isCarEmpty()) { // we just launchedan empty car, so add one to the sequence numOfEmptyCars++; } else { // we just launched a non-empty car. So the sequence is broken numOfEmptyCars = 0; } // remove it so we can put it at the end dispatchedCar = cars.remove(i); // this is just to prevent the index from moving since the list // has just shrunk so all the elements got "pushed" forward i--; //hasLoadedCar = true; } c.onClockTick(); } if(dispatchedCar != null) { // add the dispatched car back to the end of the list // this is to model reality a little bit to make the conceptual // model a little easier. In reality when a car is dispatched it // really circles around to the back of all the other cars. cars.addLast(dispatchedCar); } updateNumOfCars(); // this will update the stats at the end. return super.onClockTick(); } }