diff --git a/ChargeCalculator.java b/ChargeCalculator.java new file mode 100644 index 0000000000000000000000000000000000000000..80e22faf48a8057320ef4d1626ec5c3107ce53f1 --- /dev/null +++ b/ChargeCalculator.java @@ -0,0 +1,46 @@ +package automail; + +import java.util.Map; + +public class ChargeCalculator { + private static Map<Integer, Double> lastServiceFee; + private double markup; + private double unitPrice; + + public ChargeCalculator(int numFloors, double markup, double unitPrice) { + this.markup = markup; + this.unitPrice = unitPrice; + + // initialise service fees to 0 for all floors + for(int i = 1; i < numFloors + 1; i++) { + lastServiceFee.put(i, 0.0); + } + } + + /** + * Calculates the activity cost for the parameter item + * Activity cost = activity units * unit price + * May be altered to factor in weight or delays in the future + * @param item the mail item whos activity cost is calculated + * */ + private double calculateActivityCost(MailItem item) { + return item.getActivityUnits() * unitPrice; + } + + /** + * Returns the expected cost for an item using the last calculated service fee + * @param item The item whos expected cost is calculated + * */ + public double calculateExpectedCost(MailItem item) { + double cost = calculateActivityCost(item) + lastServiceFee.get(item.getDestFloor()); + + return cost * (1 + markup); + } + + /** + * TODO + * */ + public double calculateCost(MailItem item) { + return 0.0; + } +} diff --git a/src/automail/MailItem.java b/MailItem.java similarity index 61% rename from src/automail/MailItem.java rename to MailItem.java index 23430f39202ca4d8d6fcb217a8b8853bece46c95..6d0022999db751a900b978eddf127c705ec438c8 100644 --- a/src/automail/MailItem.java +++ b/MailItem.java @@ -25,11 +25,17 @@ public class MailItem { /** The service fee looked up at time of delivery*/ private double service_fee; + private Boolean lookupSuccessful; + /** The portion of cost associated with activity units*/ private double activity_cost; /** The total charge for delivering the item*/ private double charge; + // TODO - review + private MailPool mailPool; + // private static ChargeCalculator chargeCalculator = new ChargeCalculator(); + /** * Constructor for a MailItem @@ -37,7 +43,9 @@ public class MailItem { * @param arrival_time the time that the mail arrived * @param weight the weight of this mail item */ - public MailItem(int dest_floor, int arrival_time, int weight){ + + // TODO - review this + public MailItem(int dest_floor, int arrival_time, int weight, MailPool mailPool){ this.destination_floor = dest_floor; this.id = String.valueOf(hashCode()); this.arrival_time = arrival_time; @@ -46,13 +54,40 @@ public class MailItem { /*Initialise activity units and costs to zero*/ this.activity_units = 0; this.service_fee = 0; + this.lookupSuccessful = false; this.activity_cost = 0; this.charge = 0; + + this.mailPool = mailPool; + } + + // TODO - configure charge calculator + public static void setUnitPrice() { + return; } + /** + * Return a string representation of MailItem. Print charge information if charge threshold is set, otherwise preserve + * original output. + * */ @Override public String toString(){ - return String.format("Mail Item:: ID: %6s | Arrival: %4d | Destination: %2d | Weight: %4d", id, arrival_time, destination_floor, weight); + double charge_threshold = mailPool.getChargeThreshold(); + if (charge_threshold == 0) { + return String.format("Mail Item:: ID: %6s | Arrival: %4d | Destination: %2d | Weight: %4d", id, arrival_time, + destination_floor, weight); + } + return String.format("Mail Item:: ID: %6s | Arrival: %4d | Destination: %2d | Weight: %4d | Charge: %.2f | Cost: %.2f | Fee: %.2f | Activity: %.2f", + id, arrival_time, destination_floor, weight, charge, getCost(), service_fee, activity_cost); + } + + /** + * Modified version of the toString() method that includes information related to the charge + * THIS METHOD SHOULD NOT BE CALLED IN THE FINAL VERSION + */ + public String toStringWithCharge(){ + return String.format("Mail Item:: ID: %6s | Arrival: %4d | Destination: %2d | Weight: %4d | Charge: %.2f | Cost: %.2f | Fee: %.2f | Activity: %.2f", + id, arrival_time, destination_floor, weight, charge, getCost(), service_fee, activity_cost); } /** @@ -107,14 +142,15 @@ public class MailItem { return service_fee + activity_cost; } - /** - * Modified version of the toString() method that includes information related to the charge - */ - public String toStringWithCharge(){ - return String.format("Mail Item:: ID: %6s | Arrival: %4d | Destination: %2d | Weight: %4d | Charge: %.2f | Cost: %.2f | Fee: %.2f | Activity: %.2f", - id, arrival_time, destination_floor, weight, charge, getCost(), service_fee, activity_cost); + // TODO - validate fee and update success + public void setServiceFee(double fee) { + this.service_fee = fee; } + // TODO - update statistics + public void updateStats() { + + } static private int count = 0; static private Map<Integer, Integer> hashMap = new TreeMap<Integer, Integer>(); diff --git a/src/automail/Robot.java b/Robot.java similarity index 93% rename from src/automail/Robot.java rename to Robot.java index 7de2c1cd12185484a2939f632315221855fa2a5a..15839d67102019bbfcfadaee721cfc9033734185 100644 --- a/src/automail/Robot.java +++ b/Robot.java @@ -49,6 +49,8 @@ public class Robot { this.mailPool = mailPool; this.receivedDispatch = false; this.deliveryCounter = 0; + + } /** @@ -96,6 +98,12 @@ public class Robot { /*add activity units for the delivery*/ deliveryItem.addActivityUnits(LOOKUP_ACTIVITY_UNITS); + /* set item service fee */ + deliveryItem.setServiceFee(delivery.getServiceFee(current_floor)); + + // TODO - deliveryItem calls charge calculator + // TODO - deliveryItem increment stats in charge calculator deliveryItem.updateStats() + /** Delivery complete, report this to the simulator! */ delivery.deliver(deliveryItem); deliveryItem = null; diff --git a/src/simulation/Simulation.java b/Simulation.java similarity index 85% rename from src/simulation/Simulation.java rename to Simulation.java index 06eab853ed1e577ef6bb758517564022967e6fce..2bedb2580117c487409b186a9d16c3bf2dfff56d 100644 --- a/src/simulation/Simulation.java +++ b/Simulation.java @@ -73,10 +73,13 @@ public class Simulation { * This code section is for running a simulation */ /* Instantiate MailPool and Automail */ - MailPool mailPool = new MailPool(NUM_ROBOTS); + MailPool mailPool = new MailPool(NUM_ROBOTS, CHARGE_THRESHOLD); Automail automail = new Automail(mailPool, new ReportDelivery(), NUM_ROBOTS); MailGenerator mailGenerator = new MailGenerator(MAIL_TO_CREATE, MAIL_MAX_WEIGHT, mailPool, seedMap); + // TODO - something + MailItem.setUnitPrice(); + /** Generate all the mails */ mailGenerator.generateAllMail(); while(MAIL_DELIVERED.size() != mailGenerator.MAIL_TO_CREATE) { @@ -101,6 +104,7 @@ public class Simulation { static private Properties setUpProperties() throws IOException { Properties automailProperties = new Properties(); // Default properties + // TODO - add unit price automailProperties.setProperty("Robots", "Standard"); automailProperties.setProperty("Floors", "10"); automailProperties.setProperty("Mail_to_Create", "80"); @@ -140,6 +144,7 @@ public class Simulation { // Charge Display CHARGE_DISPLAY = Boolean.parseBoolean(automailProperties.getProperty("ChargeDisplay")); System.out.println("#Charge Display: " + CHARGE_DISPLAY); + // TODO - add unit price return automailProperties; } @@ -149,6 +154,10 @@ public class Simulation { /** Confirm the delivery and calculate the total score */ public void deliver(MailItem deliveryItem){ if(!MAIL_DELIVERED.contains(deliveryItem)){ + + // mail item calls charge calculator deliveryItem.getCost() + // getCost () { mailPool. + MAIL_DELIVERED.add(deliveryItem); System.out.printf("T: %3d > Delivered(%4d) [%s]%n", Clock.Time(), MAIL_DELIVERED.size(), deliveryItem.toString()); @@ -170,6 +179,13 @@ public class Simulation { } } } + + // TODO - review this + public double getServiceFee(int floor) { + double fee = wModem.forwardCallToAPI_LookupPrice(floor); + + return fee; + } } @@ -185,5 +201,20 @@ public class Simulation { System.out.println("T: "+Clock.Time()+" | Simulation complete!"); System.out.println("Final Delivery time: "+Clock.Time()); System.out.printf("Delay: %.2f%n", total_delay); + // Print statistics if chargeDisplay is toggled on + if (CHARGE_DISPLAY) { + printStatistics(); + } + } + + /** + * Print statistics - to be called at the end of the mail run if chargeDisplay is toggled on. + */ + public static void printStatistics() { + System.out.println("Number of items delivered: "); + System.out.println("Total billable activity: "); + System.out.println("Total activity cost: "); + System.out.println("Total service cost: "); + System.out.println("Number of lookups: XXX [XXX failed, XXX successful]" ); } } diff --git a/src/automail/Automail.java b/src/automail/Automail.java deleted file mode 100644 index 196cb3533e2f04eb628a76be70f272d80520c64b..0000000000000000000000000000000000000000 --- a/src/automail/Automail.java +++ /dev/null @@ -1,20 +0,0 @@ -package automail; - -import simulation.IMailDelivery; - -public class Automail { - - public Robot[] robots; - public MailPool mailPool; - - public Automail(MailPool mailPool, IMailDelivery delivery, int numRobots) { - /** Initialize the MailPool */ - - this.mailPool = mailPool; - - /** Initialize robots */ - robots = new Robot[numRobots]; - for (int i = 0; i < numRobots; i++) robots[i] = new Robot(delivery, mailPool, i); - } - -} diff --git a/src/automail/MailPool.java b/src/automail/MailPool.java deleted file mode 100644 index 009147cf86df4a832eca3d7ea412dbd93928030e..0000000000000000000000000000000000000000 --- a/src/automail/MailPool.java +++ /dev/null @@ -1,100 +0,0 @@ -package automail; - -import java.util.LinkedList; -import java.util.Comparator; -import java.util.ListIterator; - -import exceptions.ItemTooHeavyException; - -/** - * addToPool is called when there are mail items newly arrived at the building to add to the MailPool or - * if a robot returns with some undelivered items - these are added back to the MailPool. - * The data structure and algorithms used in the MailPool is your choice. - * - */ -public class MailPool { - - private class Item { - int destination; - MailItem mailItem; - // Use stable sort to keep arrival time relative positions - - public Item(MailItem mailItem) { - destination = mailItem.getDestFloor(); - this.mailItem = mailItem; - } - } - - public class ItemComparator implements Comparator<Item> { - @Override - public int compare(Item i1, Item i2) { - int order = 0; - if (i1.destination < i2.destination) { - order = 1; - } else if (i1.destination > i2.destination) { - order = -1; - } - return order; - } - } - - private LinkedList<Item> pool; - private LinkedList<Robot> robots; - - public MailPool(int nrobots){ //does it need a number of robots?????? - // Start empty - pool = new LinkedList<Item>(); - robots = new LinkedList<Robot>(); - } - - /** - * Adds an item to the mail pool - * @param mailItem the mail item being added. - */ - public void addToPool(MailItem mailItem) { - Item item = new Item(mailItem); - pool.add(item); - pool.sort(new ItemComparator()); - } - - - - /** - * load up any waiting robots with mailItems, if any. - */ - public void loadItemsToRobot() throws ItemTooHeavyException { - //List available robots - ListIterator<Robot> i = robots.listIterator(); - while (i.hasNext()) loadItem(i); - } - - //load items to the robot - private void loadItem(ListIterator<Robot> i) throws ItemTooHeavyException { - Robot robot = i.next(); - assert(robot.isEmpty()); - // System.out.printf("P: %3d%n", pool.size()); - ListIterator<Item> j = pool.listIterator(); - if (pool.size() > 0) { - try { - robot.addToHand(j.next().mailItem); // hand first as we want higher priority delivered first - j.remove(); - if (pool.size() > 0) { - robot.addToTube(j.next().mailItem); - j.remove(); - } - robot.dispatch(); // send the robot off if it has any items to deliver - i.remove(); // remove from mailPool queue - } catch (Exception e) { - throw e; - } - } - } - - /** - * @param robot refers to a robot which has arrived back ready for more mailItems to deliver - */ - public void registerWaiting(Robot robot) { // assumes won't be there already - robots.add(robot); - } - -} diff --git a/src/exceptions/ExcessiveDeliveryException.java b/src/exceptions/ExcessiveDeliveryException.java deleted file mode 100644 index db1962e00da4c1b99bc241109346ede6e90bf950..0000000000000000000000000000000000000000 --- a/src/exceptions/ExcessiveDeliveryException.java +++ /dev/null @@ -1,10 +0,0 @@ -package exceptions; - -/** - * An exception thrown when the robot tries to deliver more items than its tube capacity without refilling. - */ -public class ExcessiveDeliveryException extends Throwable { - public ExcessiveDeliveryException(){ - super("Attempting to deliver more than 4 items in a single trip!!"); - } -} diff --git a/src/exceptions/ItemTooHeavyException.java b/src/exceptions/ItemTooHeavyException.java deleted file mode 100644 index 7084c003d059b1b0d96e067dfd9d99584c986180..0000000000000000000000000000000000000000 --- a/src/exceptions/ItemTooHeavyException.java +++ /dev/null @@ -1,10 +0,0 @@ -package exceptions; - -/** - * This exception is thrown when a robot takes a MailItem from its StorageTube which is too heavy for that robot - */ -public class ItemTooHeavyException extends Exception { - public ItemTooHeavyException(){ - super("Item too heavy! Dropped by robot."); - } -} diff --git a/src/exceptions/MailAlreadyDeliveredException.java b/src/exceptions/MailAlreadyDeliveredException.java deleted file mode 100644 index db8b3ec7757883690f3625cfeffa52abdb2b0ac9..0000000000000000000000000000000000000000 --- a/src/exceptions/MailAlreadyDeliveredException.java +++ /dev/null @@ -1,10 +0,0 @@ -package exceptions; - -/** - * An exception thrown when a mail that is already delivered attempts to be delivered again. - */ -public class MailAlreadyDeliveredException extends Throwable { - public MailAlreadyDeliveredException(){ - super("This mail has already been delivered!"); - } -} diff --git a/src/simulation/Building.java b/src/simulation/Building.java deleted file mode 100644 index 8ca4c2052f77523dbac69389a46243a5f6058ccd..0000000000000000000000000000000000000000 --- a/src/simulation/Building.java +++ /dev/null @@ -1,15 +0,0 @@ -package simulation; - -public class Building { - - - /** The number of floors in the building **/ - public static int FLOORS; - - /** Represents the ground floor location */ - public static final int LOWEST_FLOOR = 1; - - /** Represents the mailroom location */ - public static final int MAILROOM_LOCATION = 1; - -} diff --git a/src/simulation/Clock.java b/src/simulation/Clock.java deleted file mode 100644 index 667fe343255fe488e10a62585b06f76edcbd8907..0000000000000000000000000000000000000000 --- a/src/simulation/Clock.java +++ /dev/null @@ -1,18 +0,0 @@ -package simulation; - -public class Clock { - - /** Represents the current time **/ - private static int Time = 0; - - /** The threshold for the latest time for mail to arrive **/ - public static int MAIL_RECEVING_LENGTH; - - public static int Time() { - return Time; - } - - public static void Tick() { - Time++; - } -} diff --git a/src/simulation/IMailDelivery.java b/src/simulation/IMailDelivery.java deleted file mode 100644 index fdcdff78fe87b35794052210295d1bc57e6e2022..0000000000000000000000000000000000000000 --- a/src/simulation/IMailDelivery.java +++ /dev/null @@ -1,16 +0,0 @@ -package simulation; - -import automail.MailItem; - -/** - * a MailDelivery is used by the Robot to deliver mail once it has arrived at the correct location - */ -public interface IMailDelivery { - - /** - * Delivers an item at its floor - * @param mailItem the mail item being delivered. - */ - void deliver(MailItem mailItem); - -} \ No newline at end of file diff --git a/src/simulation/MailGenerator.java b/src/simulation/MailGenerator.java deleted file mode 100644 index 14e3404ea9803204f713d43ec46feb107a02c128..0000000000000000000000000000000000000000 --- a/src/simulation/MailGenerator.java +++ /dev/null @@ -1,135 +0,0 @@ -package simulation; - -import java.util.*; - -import automail.MailItem; -import automail.MailPool; - -/** - * This class generates the mail - */ -public class MailGenerator { - - public final int MAIL_TO_CREATE; - public final int MAIL_MAX_WEIGHT; - - private int mailCreated; - - private final Random random; - /** This seed is used to make the behaviour deterministic */ - - private boolean complete; - private MailPool mailPool; - - private Map<Integer,ArrayList<MailItem>> allMail; - - /** - * Constructor for mail generation - * @param mailToCreate roughly how many mail items to create - * @param mailMaxWeight limits the maximum weight of the mail - * @param mailPool where mail items go on arrival - * @param seed random seed for generating mail - */ - public MailGenerator(int mailToCreate, int mailMaxWeight, MailPool mailPool, HashMap<Boolean,Integer> seed){ - if(seed.containsKey(true)){ - this.random = new Random((long) seed.get(true)); - } - else{ - this.random = new Random(); - } - // Vary arriving mail by +/-20% - MAIL_TO_CREATE = mailToCreate*4/5 + random.nextInt(mailToCreate*2/5); - MAIL_MAX_WEIGHT = mailMaxWeight; - // System.out.println("Num Mail Items: "+MAIL_TO_CREATE); - mailCreated = 0; - complete = false; - allMail = new HashMap<Integer,ArrayList<MailItem>>(); - this.mailPool = mailPool; - } - - /** - * @return a new mail item that needs to be delivered - */ - private MailItem generateMail(){ - MailItem newMailItem; - int destinationFloor = generateDestinationFloor(); - int arrivalTime = generateArrivalTime(); - int weight = generateWeight(); - - newMailItem = new MailItem(destinationFloor,arrivalTime,weight); - return newMailItem; - } - - /** - * @return a destination floor between the ranges of GROUND_FLOOR to FLOOR - */ - private int generateDestinationFloor(){ - return Building.LOWEST_FLOOR + random.nextInt(Building.FLOORS); - } - - /** - * @return a random weight - */ - private int generateWeight(){ - final double mean = 200.0; // grams for normal item - final double stddev = 1000.0; // grams - double base = random.nextGaussian(); - if (base < 0) base = -base; - int weight = (int) (mean + base * stddev); - return weight > MAIL_MAX_WEIGHT ? MAIL_MAX_WEIGHT : weight; - } - - /** - * @return a random arrival time before the last delivery time - */ - private int generateArrivalTime(){ - return 1 + random.nextInt(Clock.MAIL_RECEVING_LENGTH); - } - - /** - * This class initializes all mails and sets their corresponding values, - * All generated mails will be saved in allMail - */ - public void generateAllMail(){ - while(!complete){ - MailItem newMail = generateMail(); - int timeToDeliver = newMail.getArrivalTime(); - /** Check if key exists for this time **/ - if(allMail.containsKey(timeToDeliver)){ - /** Add to existing array */ - allMail.get(timeToDeliver).add(newMail); - } - else{ - /** If the key doesn't exist then set a new key along with the array of MailItems to add during - * that time step. - */ - ArrayList<MailItem> newMailList = new ArrayList<MailItem>(); - newMailList.add(newMail); - allMail.put(timeToDeliver,newMailList); - } - /** Mark the mail as created */ - mailCreated++; - - /** Once we have satisfied the amount of mail to create, we're done!*/ - if(mailCreated == MAIL_TO_CREATE){ - complete = true; - } - } - - } - - /** - * Given the clock time, put the generated mails into the mailPool. - * So that the robot will can pick up the mails from the pool. - */ - public void addToMailPool(){ - // Check if there are any mail to create - if(this.allMail.containsKey(Clock.Time())){ - for(MailItem mailItem : allMail.get(Clock.Time())){ - System.out.printf("T: %3d > new addToPool [%s]%n", Clock.Time(), mailItem.toString()); - mailPool.addToPool(mailItem); - } - } - } - -}