Skip to content
Snippets Groups Projects
Commit 5ae20ac5 authored by Isobel's avatar Isobel
Browse files

isobel's code

parent a5b85d5e
No related branches found
No related tags found
No related merge requests found
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;
}
}
......@@ -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>();
......
......@@ -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;
......
......@@ -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());
......@@ -171,6 +180,13 @@ public class Simulation {
}
}
// TODO - review this
public double getServiceFee(int floor) {
double fee = wModem.forwardCallToAPI_LookupPrice(floor);
return fee;
}
}
private static double calculateDeliveryDelay(MailItem deliveryItem) {
......@@ -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]" );
}
}
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);
}
}
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);
}
}
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!!");
}
}
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.");
}
}
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!");
}
}
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;
}
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++;
}
}
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
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);
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment