package simulator; /* * CycleRide.java * Created on Jan 8, 2005 * */ /** * CycleRide - This class implements the cycle rides in the amusement park. * On cycle rides, everyone gets on and off at the same time like theater rides. * @author Ping * */ public class CycleRide extends Attraction { public static String ATTRACTION_TYPE = "Cycle"; // this is the number of previous cycles that we need to consider protected final static int LAST_CYCLES = 3; protected final static int EMPTY_CAR_THRESHOLD = 2; // This is to keep track of the number of empty cars in the past X cycles protected int[] numOfEmptyCars = new int[LAST_CYCLES]; /** * @param attractionName * @param entrance * @param exit * @param initialNumOfCars * @param maxNumOfCarsPossible * @param carCapacity * @param rideTime * @param loadingTime */ public CycleRide(String attractionName, Location entrance, Location exit, int initialNumOfCars, int maxNumOfCarsPossible, int carCapacity, int rideTime, int loadingTime) { super(attractionName, entrance, exit, initialNumOfCars, maxNumOfCarsPossible, carCapacity, rideTime, loadingTime); } /* * This function determines if we should add a car to the ride or not */ protected boolean shouldAddCar() { int numOfCars = cars.size(); int capacity = numOfCars * 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 capacity < waitingLine.size() && numOfCars < maxNumOfCarsPossible; } /* * This function determines if we should remove a car from the attraction */ protected boolean shouldRemoveCar() { boolean shouldRemove = true; for(int i : numOfEmptyCars) { // note: i is actually the value in the array, not the index if(i < EMPTY_CAR_THRESHOLD) { // there was a cycle where there are fewer than the threshold number of // empty cars shouldRemove = false; break; } } // we should keep at least 1 car on the ride. return shouldRemove && cars.size() > 1; } /** * This function should be called when the attraction first opens * */ public void openRide() { super.openRide(); // initialize the array to 0's for(int i = 0; i < numOfEmptyCars.length; i++) { numOfEmptyCars[i] = 0; } } /** * Thhis 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() { /* * Note: this function is not implemented in the most efficient way. * But I feel that it matches the mental model most effectively. * I believe this particular way is easier to reason with (IMO) */ if(cars.getFirst().isCarDone()) { // all the cars are done. lets unload them all for(Car c : cars) { c.unloadCustomers(); } } // the ride has finished 1 cycle, so lets see if we should add cars or remove them // its ok to just check the first car since this is a cycle ride, all cars // start and finish at the same time. if(cars.getFirst().isCarWaiting()) { updateNumOfCars(); Customer[] riders; boolean hasCustomers = false; int emptyCars = cars.size(); // since the ride can start with empty cars, we need to // first go through and make sure there are NONE empty cars for(Car c : cars) { riders = extractCustomers(); if(riders.length != 0) { // still have customers emptyCars--; hasCustomers = true; } // as long as there were some customers // we load the car (even if we load it as empty) if(hasCustomers) { c.loadCustomers(riders); } } // record the number of empty cars for this cycle int lastIndex = numOfEmptyCars.length - 1; for(int i = 0; i < lastIndex; i++) { // bump the cycles "forward" such that the most recent cycle // is at the end of the array numOfEmptyCars[i] = numOfEmptyCars[i + 1]; } numOfEmptyCars[lastIndex] = emptyCars; } if(cars.getFirst().isCarReady()) { // all the cars are ready to be launched, so dispatch them all for(Car c : cars) { c.dispatchCar(); } } // just process all the cars for(Car c : cars) { c.onClockTick(); } // this will update the stats at the end. return super.onClockTick(); } /** * 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 { CycleRide clone = (CycleRide)this.clone(); clone.setSimulationMode(true); // Car firstCar = clone.cars.getFirst(); // the line not only needs to be empty, but there needs to be // a car available (if the car has just finished, u can // probably get on then) while(clone.getLineLength() > 0 || !clone.hasCarAvailable()) { clone.onClockTick(); estimatedWaitTime++; } } catch(CloneNotSupportedException e) { e.printStackTrace(); } } return estimatedWaitTime; } public Object clone() throws CloneNotSupportedException { CycleRide clone = (CycleRide)super.clone(); clone.numOfEmptyCars = new int[this.numOfEmptyCars.length]; for(int i = 0; i < clone.numOfEmptyCars.length; i++) { clone.numOfEmptyCars[i] = this.numOfEmptyCars[i]; } return clone; } }