import java.lang.Comparable; import java.util.Comparator; import java.util.Collection; import java.util.Collections; import java.util.ArrayList; import java.util.Set; import java.util.TreeSet; import java.util.Map; import java.util.TreeMap; public class ThemApples { final static Collection<PackingStats> results = new ArrayList<PackingStats>(); public static void compete(String[] args) { final int numCartons = args.length > 0 ? Integer.parseInt(args[0]) : 5; final double low = args.length > 1 ? Double.parseDouble(args[1]) : Math.random(); final double high = args.length > 2 ? Double.parseDouble(args[2]) : Math.random(); final PackingContest contest = new PackingContest(numCartons, low, high); int rounds = args.length > 3 ? Integer.parseInt(args[3]) : 1; while (rounds-- > 0) { for (ApplePackerFranchise packer : Knuth.shuffle(Northwest.applePackers)) { packer.initialize(); ThemApples.results.add(contest.testPacker(packer)); } } } public static void main(String[] args) { final String[] highMixLowVol = {"10", "0.33", "0.66", "6"}; final String[] highMixHighVol = {"100", "0.33", "0.66", "6"}; final String[] lowMixHighVol1 = {"100", "0.0", "1.0", "4"}; final String[] lowMixHighVol2 = {"100", "0.0", "0.0", "4"}; final String[] lowMixHighVol3 = {"100", "0.0", "1.0", "4"}; if (args.length > 0) compete(args); else { compete(highMixLowVol); compete(highMixHighVol); compete(lowMixHighVol1); compete(lowMixHighVol2); compete(lowMixHighVol3); } OrderedStats[] rankings = Judge.evaluate(ThemApples.results); Announcer.printOverallRanking(Judge.combine(rankings)); Announcer.printRankings(rankings, 10); Announcer.printResults(ThemApples.results); } }
/**************/ /* Interfaces */ /**************/ interface Stuff { public abstract double volume(); public abstract double weight(); } interface UnitPriced extends Stuff { public abstract double unitPrice(); } interface Ageable { public abstract long age(); public abstract long ageAsOf(long time); } interface Valuable { public abstract double value(); } interface Fillable<T extends Stuff> { public boolean add(T stuff); public boolean remove(T stuff); public double remainingSpace(); public boolean isFull(); } interface Closeable { public abstract boolean close(); public abstract boolean isOpen(); public abstract boolean isClosed(); } interface AppleCustomer { public abstract boolean receive(Collection<BagOfApples> bags); } interface ApplePackerFranchise extends AppleCustomer { public abstract String parentCompany(); public abstract String businessName(); public abstract void initialize(); public abstract Collection<AppleCarton> pack(Collection<AppleCarton> cartons); }
/***************************************/ /* Functions and Functional Interfaces */ /***************************************/ interface Test { public abstract boolean pass(int result); } interface FoodAttr<V extends Comparable<V>> { public abstract V get(Foodstuff item); } interface FoodAttrD { public abstract Double get(Foodstuff item); } class Lamb { // Lambda Functions public static final Test lt = (compareToResult) -> compareToResult < 0; public static final Test gt = (compareToResult) -> compareToResult > 0; public static final FoodAttr<Long> age = (item) -> item.age(); public static final FoodAttr<Double> wgt = (item) -> item.weight(); public static final FoodAttr<Double> vol = (item) -> item.volume(); public static final FoodAttr<Double> val = (item) -> item.value(); public static final FoodAttrD ageD = (item) -> ((Long) item.age()).doubleValue(); public static final FoodAttrD wgtD = (item) -> item.weight(); public static final FoodAttrD volD = (item) -> item.volume(); public static final FoodAttrD valD = (item) -> item.value(); } class Knuth { public static <T> T[] shuffle(T[] array) { final int n = array.length, k = n - 1; for (int i = 0; i < k; i++) { final Double d = Math.random() * (n - i); final int j = i + d.intValue(); final T tmp = array[i]; array[i] = array[j]; array[j] = tmp; } return array; } } class Doubles { public static int compare(Double lhs, Double rhs, int nanVal) { Boolean lhsIsNaN = lhs.isNaN(), rhsIsNaN = rhs.isNaN(); if (lhsIsNaN && rhsIsNaN) return 0; else if (lhsIsNaN) return nanVal; else if (rhsIsNaN) return -1 * nanVal; else return lhs.compareTo(rhs); } }
class Get // Utility Functions { public static <F extends Foodstuff, V extends Comparable<V>> double sum(Collection<F> items, FoodAttrD attribute) { double total = 0; for (F item : items) total += attribute.get(item); return total; } public static <F extends Foodstuff, V extends Comparable<V>> double avg(Collection<F> items, FoodAttrD attribute) { return Get.sum(items, attribute) / items.size(); } public static <F extends Foodstuff, V extends Comparable<V>> F most(Collection<F> items, FoodAttr<V> attribute, Test test) { F selectedItem = null; V selectedValue = null; for (F item : items) { V value = attribute.get(item); if (selectedValue == null || test.pass(value.compareTo(selectedValue))) { selectedValue = value; selectedItem = item; } } return selectedItem; } public static <F extends Foodstuff, V extends Comparable<V>> Collection<F> all(Collection<F> items, FoodAttrD attribute, Test test, Double val) { Collection<F> selectedEdibleItems = new ArrayList<F>(); for (F item : items) if (test.pass(attribute.get(item).compareTo(val))) selectedEdibleItems.add(item); return selectedEdibleItems; } public static <F extends Foodstuff, V extends Comparable<V>> F one(Collection<F> items, FoodAttrD attribute, Test test, Double val) { Collection<F> selectedEdibleItems = new ArrayList<F>(); for (F item : items) if (test.pass(attribute.get(item).compareTo(val))) return item; return null; } }
/********************/ /* Food For Thought */ /********************/ abstract class Foodstuff implements Ageable, Valuable, UnitPriced { private final long createTime = System.nanoTime(); private final double weight, volume; protected Foodstuff(double weight, double volume) { this.weight = weight; this.volume = volume; } public long ageAsOf(long time) { return time - this.createTime; } public long age() { return ageAsOf(System.nanoTime()); } public double weight() { return this.weight; } public double volume() { return this.volume; } public double value() { return this.weight * this.unitPrice(); } public abstract double unitPrice(); } class BagOfApples extends Foodstuff { private final Variety variety; private final Grower grower; private final int lot; public BagOfApples(Grower grower, Variety variety, double wgt, int lot) { super(wgt, wgt / AppleAttributes.bulkDensity(variety)); this.variety = variety; this.grower = grower; this.lot = lot; } public double unitPrice() { return Market.price(variety); } public Variety variety() { return this.variety; } public Grower grower() { return this.grower; } public int lot() { return this.lot; } public String toString() { return "grower: " + this.grower().toString() + "\nvariety: " + this.variety().toString() + "\nlot: " + this.lot() + "\nweight: " + this.weight() + "\nvolume: " + this.volume() + "\nvalue: " + this.value() + "\nage: " + this.age() + "\n"; } }
/********************/ /* A Lot To Chew On */ /********************/ class EdibleItems<F extends Foodstuff> { private final Collection<F> items = new ArrayList<F>(); public int count() { return items.size(); } public boolean add(F item) { return items.add(item); } public boolean remove(F item) { return items.remove(item); } public double sumAge() { return Get.sum(items, Lamb.ageD); } public double sumWgt() { return Get.sum(items, Lamb.wgtD); } public double sumVol() { return Get.sum(items, Lamb.volD); } public double sumVal() { return Get.sum(items, Lamb.valD); } public double avgAge() { return Get.avg(items, Lamb.ageD); } public double avgWgt() { return Get.avg(items, Lamb.wgtD); } public double avgVol() { return Get.avg(items, Lamb.volD); } public double avgVal() { return Get.avg(items, Lamb.valD); } public F oneMinAge() { return Get.most(items, Lamb.age, Lamb.lt); } public F oneMaxAge() { return Get.most(items, Lamb.age, Lamb.gt); } public F oneMinWgt() { return Get.most(items, Lamb.wgt, Lamb.lt); } public F oneMaxWgt() { return Get.most(items, Lamb.wgt, Lamb.gt); } public F oneMinVol() { return Get.most(items, Lamb.vol, Lamb.lt); } public F oneMaxVol() { return Get.most(items, Lamb.vol, Lamb.gt); } public F oneMinVal() { return Get.most(items, Lamb.val, Lamb.lt); } public F oneMaxVal() { return Get.most(items, Lamb.val, Lamb.gt); } public F oneAgeLt(Double d) { return Get.one(items, Lamb.ageD, Lamb.lt, d); } public F oneAgeGt(Double d) { return Get.one(items, Lamb.ageD, Lamb.gt, d); } public F oneAgtLt(Double d) { return Get.one(items, Lamb.wgtD, Lamb.lt, d); } public F oneWgtGt(Double d) { return Get.one(items, Lamb.wgtD, Lamb.gt, d); } public F oneVolLt(Double d) { return Get.one(items, Lamb.volD, Lamb.lt, d); } public F oneVolGt(Double d) { return Get.one(items, Lamb.volD, Lamb.gt, d); } public F oneValLt(Double d) { return Get.one(items, Lamb.valD, Lamb.lt, d); } public F oneValGt(Double d) { return Get.one(items, Lamb.valD, Lamb.gt, d); } public Collection<F> allAgeLt(Double d) { return Get.all(items, Lamb.ageD, Lamb.lt, d); } public Collection<F> allAgeGt(Double d) { return Get.all(items, Lamb.ageD, Lamb.gt, d); } public Collection<F> allWgtLt(Double d) { return Get.all(items, Lamb.wgtD, Lamb.lt, d); } public Collection<F> allWgtGt(Double d) { return Get.all(items, Lamb.wgtD, Lamb.gt, d); } public Collection<F> allVolLt(Double d) { return Get.all(items, Lamb.volD, Lamb.lt, d); } public Collection<F> allVolGt(Double d) { return Get.all(items, Lamb.volD, Lamb.gt, d); } public Collection<F> allValLt(Double d) { return Get.all(items, Lamb.valD, Lamb.lt, d); } public Collection<F> allValGt(Double d) { return Get.all(items, Lamb.valD, Lamb.gt, d); } public Collection<F> all() { return Get.all(items, Lamb.ageD, Lamb.gt, 0.0); } }
/****************************/ /* Contained Pieces of Food */ /****************************/ class ContainedEdibleItems<F extends Foodstuff> extends EdibleItems<F> implements Fillable<F> { private final double size; private double spaceRemaining; public ContainedEdibleItems(double spaceLimit) { this.size = this.spaceRemaining = spaceLimit; } public boolean add(F item) { double itemVolume = item.volume(); if (this.spaceRemaining > itemVolume) { if (super.add(item)) { this.spaceRemaining -= itemVolume; return true; } } return false; } public boolean remove(F item) { if (super.remove(item)) { this.spaceRemaining += item.volume(); return true; } return false; } public double size() { return this.size; } public double remainingSpace() { return this.spaceRemaining; } public boolean isFull() { return this.spaceRemaining <= 0; } } class AppleInventory extends ContainedEdibleItems<BagOfApples> { public AppleInventory(double storageSpace) { super(storageSpace); } public void print() { for (BagOfApples bag : this.all()) System.out.println(bag); } }
/****************/ /* Food Cartons */ /****************/ class FoodCarton<F extends Foodstuff> extends ContainedEdibleItems<F> implements Closeable { private double length, width, height; private boolean opened = true; public FoodCarton(double l, double w, double h) { super(l * w * h); this.length = l; this.width = w; this.height = h; } public boolean close() { return !(this.opened = false); } public boolean isOpen() { return this.opened; } public boolean isClosed() { return !this.opened; } public boolean add(F item) { return this.opened ? super.add(item) : false; } public boolean remove(F item) { return this.opened ? super.remove(item) : false; } public final double length() { return this.length; } public final double width() { return this.width; } public final double height() { return this.height; } } class AppleCarton extends FoodCarton<BagOfApples> { public AppleCarton(int l, int w, int h) { super(l, w, h); } public void printContents() { for (BagOfApples bag : this.all()) System.out.println(bag); } public String toString() { if (this.count() == 0) return "Empty carton."; return "\nOldest Bag: " + this.oneMaxAge().age() + "\n Total Wgt: " + this.sumWgt() + "\n Total Val: " + this.sumVal() + "\n Total Age: " + this.sumAge() + "\n"; } } class SmallFootprintAppleCarton extends AppleCarton { public SmallFootprintAppleCarton() { super(4, 2, 3); } } class MediumFootprintAppleCarton extends AppleCarton { public MediumFootprintAppleCarton() { super(3, 3, 3); } } class LargeFootprintAppleCarton extends AppleCarton { public LargeFootprintAppleCarton() { super(4, 3, 3); } }
/*****************/ /* Apple Science */ /*****************/ enum Variety { GALA("Gala"), RED_DELICIOUS("Red Delicious"), HONEY_CRISP("Honey Crisp"); private String name; Variety(String name) { this.name = name; } public String toString() { return this.name; } } class AppleAttributes { private static final double PACKING_EFFICIENCY = 0.64; private static final double density(Variety variety) { switch(variety) { case GALA: return 0.92; case RED_DELICIOUS: return 0.94; case HONEY_CRISP: return 0.95; default: return 0.93; } } public static double bulkDensity(Variety variety) { return density(variety) * PACKING_EFFICIENCY; } } /*******************/ /* Apple Economics */ /*******************/ class Market { public static double price(Variety variety) { switch(variety) { case GALA: return 1.2; case RED_DELICIOUS: return 0.9; case HONEY_CRISP: return 1.3; default: return 0.8; } } }
/*****************/ /* Apple Growers */ /*****************/ class GrowersAssociation { private static int[][] lotIds = new int[Grower.values().length][Variety.values().length]; private static Collection<LotOfApples> lots = new ArrayList<LotOfApples>(); private static LotOfApples currentLot; public static int nextLot(Grower grower, Variety variety) { int lotId = ++lotIds[grower.ordinal()][variety.ordinal()]; currentLot = new LotOfApples(grower, variety, lotId); return lotId; } public static boolean register(BagOfApples bag) { return currentLot.id() == bag.lot() && currentLot.grower() == bag.grower() && currentLot.variety() == bag.variety() ? currentLot.add(bag) : false; } } class LotOfApples { private final int lotId; private final Grower grower; private final Variety variety; private final Collection<BagOfApples> bags = new ArrayList<BagOfApples>(); public LotOfApples(Grower grower, Variety variety, int id) { this.grower = grower; this.variety = variety; this.lotId = id; } public boolean add(BagOfApples bag) { return this.bags.add(bag); } public boolean contains(BagOfApples bag) { return this.bags.contains(bag); } public Grower grower() { return this.grower; } public Variety variety() { return this.variety; } public int id() { return this.lotId; } }
enum Grower { APPLE_BEES ("Apple Bees", 4.0, 8.0, Variety.HONEY_CRISP, Variety.GALA, 500L, 10000.0), RANDOM_REDS ("Random Reds", Math.E, Math.PI, Variety.RED_DELICIOUS, Variety.RED_DELICIOUS, 100L, 20000.0), FRIENDLY_FRUITS ("Friendly Fruits", 2.0, 6.0, Variety.GALA, Variety.RED_DELICIOUS, 300L, 15000.0); private String name; private long leadTime; private double minBagWgt, bagWgtRange, wgtLimit; private Variety var1, var2; Grower(String name, Double min, Double max, Variety primary, Variety secondary, long leadTime, double wgtLimit) { this.name = name; this.minBagWgt = min; this.bagWgtRange = Math.abs(max - min); this.var1 = primary; this.var2 = secondary; this.leadTime = leadTime; this.wgtLimit = wgtLimit; } private Variety whichVariety() { return Math.random() < 0.7 ? var1 : var2; } public boolean fillOrder(AppleCustomer customer, double requestedWgt) { final Long whenRequested = System.nanoTime(); final Grower grower = this; final Variety variety = this.whichVariety(); final int lotId = GrowersAssociation.nextLot(this, variety); final Collection<BagOfApples> themApples = new ArrayList<BagOfApples>(); double totalWgt = 0.0; while (totalWgt < requestedWgt && totalWgt < wgtLimit) { Double bagWgt = this.minBagWgt + (Math.random() * this.bagWgtRange); BagOfApples bag = new BagOfApples(grower, variety, bagWgt, lotId); if (!GrowersAssociation.register(bag)) return false; if (!themApples.add(bag)) return false; totalWgt += bagWgt; } while (System.nanoTime() - whenRequested < this.leadTime); return customer.receive(themApples); // How do you like themApples? } public double wgtLimit() { return this.wgtLimit; } public String toString() { return this.name; } }
/*******************/ /* Packing Contest */ /*******************/ class PackingContest { private int numCartons; private double low, high; public PackingContest(int numCartons, double low, double high) { this.numCartons = numCartons; this.low = low; this.high = high; } public PackingStats testPacker(ApplePackerFranchise contestent) { return new PackingStats(contestent, getCartons()); } private Collection<AppleCarton> getCartons() { Collection<AppleCarton> cartons = new ArrayList<AppleCarton>(); for (int i = 0; i < numCartons; i++) { AppleCarton carton; double d = Math.random(); if (d < low) carton = new SmallFootprintAppleCarton(); else if (d < high) carton = new MediumFootprintAppleCarton(); else carton = new LargeFootprintAppleCarton(); cartons.add(carton); } return cartons; } }
class PackingStats { private final ApplePackerFranchise franchise; private final long packTime; private int cartonCount, bagCount; private double sumWgt, sumAge, sumVal, sumVol, sumSize, maxAge; public PackingStats(PackingStats stats) { this.franchise = stats.franchise; this.packTime = stats.packTime; this.cartonCount = stats.cartonCount; this.bagCount = stats.bagCount; this.sumWgt = stats.sumWgt; this.sumAge = stats.sumAge; this.sumVal = stats.sumVal; this.sumVol = stats.sumVol; this.sumSize = stats.sumSize; this.maxAge = stats.maxAge; } public PackingStats(ApplePackerFranchise p, Collection<AppleCarton> cartons) { this.franchise = p; this.cartonCount = cartons.size(); long beginTime = System.nanoTime(); p.pack(cartons); this.packTime = System.nanoTime() - beginTime; for (AppleCarton c : cartons) { if (c.count() == 0) continue; double max = c.oneMaxAge().age(); if (max > this.maxAge) this.maxAge = max; this.sumWgt += c.sumWgt(); this.sumAge += c.sumAge(); this.sumVal += c.sumVal(); this.sumVol += c.sumVol(); this.sumSize += c.size(); this.bagCount += c.count(); } } public String parentCompany() { return this.franchise.parentCompany(); } public String businessName() { return this.franchise.businessName(); } public Double packTimeSec() { return this.packTime / 1E9; } public Double maxAgeSec() { return this.maxAge / 1E9; } public Double avgAgeSec() { return this.sumAge / 1E9 / this.bagCount; } public Double wgtVolRatio() { return this.sumWgt / this.sumVol; } public Double wgtEfficiency() { return this.wgtVolRatio() / this.volEfficiency(); } public Double volEfficiency() { return this.sumVol / this.sumSize; } public Double valEfficiency() { return this.sumVal / this.sumSize; } public Integer cartonCount() { return this.cartonCount; } public Integer bagCount() { return this.bagCount; } }
class OrderedStats { private final String description; private final Set<PackingStats> rankedStats = new TreeSet<PackingStats>(); public OrderedStats(String desc) { this.description = desc; } public boolean add(ComparablePackingStats stats) { return rankedStats.add(stats); } public Collection<Map.Entry<String, Integer>> parentCompanyRanking() { Map<String, Integer> parentScores = new TreeMap<String, Integer>(); int place = 0; for (PackingStats stats : this.rankedStats){ place++; String parentCompany = stats.parentCompany(); Integer newScore = parentScores.containsKey(parentCompany) ? parentScores.get(parentCompany) + place : place; parentScores.put(parentCompany, newScore); } ArrayList<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(); for (Map.Entry<String, Integer> entry : parentScores.entrySet()) list.add(entry); Collections.sort(list, EntryComparator.THE_COMPARATOR); return list; } public String parentCompanyRankingAsString() { String s = this.description + "\n\nParent Co. Ranking\n\n"; int i = 0; for (Map.Entry<String, Integer> entry : this.parentCompanyRanking()) s += ++i + ". " + entry.getKey() + " (" + entry.getValue() + ")\n"; return s; } public String franchiseRankingAsString(int topN) { String s = "Top " + topN + " Individual Franchise Scores\n\n"; int i = 0; for (PackingStats stats : this.rankedStats) { s += (++i + ". " + stats.toString()); if (topN > 0 && i >= topN) break; } return s; } }
class EntryComparator implements Comparator<Map.Entry<String, Integer>> { public static final EntryComparator THE_COMPARATOR = new EntryComparator(); protected EntryComparator() {} public int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) { return a.getValue().compareTo(b.getValue()); } } abstract class ComparablePackingStats extends PackingStats implements Comparable<PackingStats> { public ComparablePackingStats(PackingStats stats) { super(stats); } public String toString() { return this.parentCompany() + ": " + this.businessName() + " (" + this.keyValue() + ")\n"; } public abstract String keyValue(); } class StatsComparableByTime extends ComparablePackingStats { public StatsComparableByTime(PackingStats stats) { super(stats); } public int compareTo(PackingStats other) { return this.packTimeSec().compareTo(other.packTimeSec()); } public String keyValue() { return this.packTimeSec().toString(); } } class StatsComparableByAge extends ComparablePackingStats { public StatsComparableByAge(PackingStats stats) { super(stats); } public int compareTo(PackingStats other) { return Doubles.compare(this.avgAgeSec(), other.avgAgeSec(), 1); } public String keyValue() { return this.avgAgeSec().toString(); } } class StatsComparableByWgt extends ComparablePackingStats { public StatsComparableByWgt(PackingStats stats) { super(stats); } public int compareTo(PackingStats other) { return Doubles.compare(this.wgtEfficiency(), other.wgtEfficiency(), 1); } public String keyValue() { return this.wgtEfficiency().toString(); } } class StatsComparableByVal extends ComparablePackingStats { public StatsComparableByVal(PackingStats stats) { super(stats); } public int compareTo(PackingStats other) { return -1 * Doubles.compare(this.valEfficiency(), other.valEfficiency(), -1); } public String keyValue() { return this.valEfficiency().toString(); } } class StatsComparableByVol extends ComparablePackingStats { public StatsComparableByVol(PackingStats stats) { super(stats); } public int compareTo(PackingStats other) { return -1 * Doubles.compare(this.volEfficiency(), other.volEfficiency(), -1); } public String keyValue() { return this.volEfficiency().toString(); } }
class Judge { private static OrderedStats statsSortedByTime = new OrderedStats("PACK TIME COMPETITION"), statsSortedByAge = new OrderedStats("AVG AGE COMPETITION"), statsSortedByWgt = new OrderedStats("WGT EFFICIENCY COMPETITION"), statsSortedByVal = new OrderedStats("VAL EFFICIENCY COMPETITION"), statsSortedByVol = new OrderedStats("VOL EFFICIENCY COMPETITION"); public static OrderedStats[] evaluate(Collection<PackingStats> stats) { for (PackingStats s : stats) { statsSortedByTime.add(new StatsComparableByTime(s)); statsSortedByAge.add(new StatsComparableByAge(s)); statsSortedByWgt.add(new StatsComparableByWgt(s)); statsSortedByVal.add(new StatsComparableByVal(s)); statsSortedByVol.add(new StatsComparableByVol(s)); } OrderedStats[] results = { statsSortedByTime, statsSortedByAge, statsSortedByWgt, statsSortedByVal, statsSortedByVol }; return results; } public static Collection<Map.Entry<String, Integer>> combine(OrderedStats[] rankings) { Collection<Map.Entry<String, Integer>> overallRanking = null, currentRanking; for (OrderedStats ranking : rankings) { currentRanking = ranking.parentCompanyRanking(); if (overallRanking == null) { overallRanking = currentRanking; continue; } for (Map.Entry<String, Integer> entry : currentRanking) { String key = entry.getKey(); Integer val = entry.getValue(); for (Map.Entry<String, Integer> e : overallRanking) { if (e.getKey().equals(key)) e.setValue(e.getValue() + val); } } } ArrayList<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(); for (Map.Entry<String, Integer> entry : overallRanking) list.add(entry); Collections.sort(list, EntryComparator.THE_COMPARATOR); return list; } }
class Announcer { public static void printResults(Collection<PackingStats> results) { System.out.println("PACKING STATISTICS\n"); for (PackingStats stats : results) System.out.println(" Business Name: " + stats.businessName() + "\n Carton Count: " + stats.cartonCount() + "\n Bag Count: " + stats.bagCount() + "\n Pack Time: " + stats.packTimeSec() + " sec" + "\n Avg Age of Bag: " + stats.avgAgeSec() + " sec" + "\n Max Age of Bag: " + stats.maxAgeSec() + " sec" + "\n Vol Efficiency: " + stats.volEfficiency() * 100 + " %" + "\n Val Efficiency: " + stats.valEfficiency() * 100 + " cents / unit vol" + "\n Wgt Efficiency: " + stats.wgtEfficiency() + " wgt units / unit vol\n"); } public static void printRankings(OrderedStats[] rankings, int topN) { for (OrderedStats ranking : rankings) { System.out.println(ranking.parentCompanyRankingAsString()); System.out.println(ranking.franchiseRankingAsString(topN)); } } public static void printOverallRanking(Collection<Map.Entry<String, Integer>> entries) { System.out.println("OVERALL COMPETITION\n"); int i = 0; for (Map.Entry<String, Integer> entry : entries) System.out.println(++i + ". " + entry.getKey() + " (" + entry.getValue() + ")"); System.out.println(); } }
/****************************/ /* Authorized Apple Packers */ /****************************/ abstract class ApplePacker implements ApplePackerFranchise { private static double MAX_STORAGE_SPACE = 1000.0; private final String parentCompany; private final String businessName; protected final AppleInventory inventory; protected final Collection<Grower> preferredSuppliers; public ApplePacker(String parentCompany, String businessName, double storageSpace) { this.parentCompany = parentCompany; this.businessName = businessName; if (storageSpace > ApplePacker.MAX_STORAGE_SPACE) storageSpace = ApplePacker.MAX_STORAGE_SPACE; this.inventory = new AppleInventory(storageSpace); this.preferredSuppliers = new ArrayList<Grower>(); } public String parentCompany() { return this.parentCompany; } public String businessName() { return this.businessName; } public boolean receive(Collection<BagOfApples> bags) { for (BagOfApples bag : bags) if (!this.inventory.add(bag)) return false; return true; } public abstract void initialize(); public abstract Collection<AppleCarton> pack(Collection<AppleCarton> cartons); protected void restock() { while (inventory.remainingSpace() > 0) for (Grower grower : this.preferredSuppliers) if (!grower.fillOrder(this, grower.wgtLimit()) || inventory.remainingSpace() <= 0) return; } }
/********************/ /* The Model Packer */ /********************/ class ApplePacker0 extends ApplePacker { public ApplePacker0(String parentCo) { this(parentCo, "Johnny Appleseed"); } public ApplePacker0(String parentCo, String businessName) { this(parentCo, businessName, 25); } public ApplePacker0(String parentCo, String businessName, int storageSpace) { super(parentCo, businessName, storageSpace); } public void initialize() { this.preferredSuppliers.add(Grower.RANDOM_REDS); this.restock(); } public Collection<AppleCarton> pack(Collection<AppleCarton> cartons) { for (AppleCarton carton : cartons) { BagOfApples bag = inventory.oneVolLt(carton.remainingSpace()); while (bag != null) { if (!inventory.remove(bag)) return null; if (!carton.add(bag)) return null; bag = inventory.oneVolLt(carton.remainingSpace()); } if (!carton.close()) return null; } return cartons; } }
/**************************/ /* Regional Apple Packers */ /**************************/ class Northwest { public static ApplePackerFranchise[] applePackers = { new ApplePacker0("Big Business", "Johnny In-The-Box, LLC", 500), new ApplePacker0("Big Business", "Johnny In-The-Box, LLC", 500), new ApplePacker0("Big Business", "Johnny In-The-Box, LLC", 500), new ApplePacker0("Big Business", "Johnny In-The-Box, LLC", 500), new ApplePacker0("Big Business", "Johnny In-The-Box, LLC", 500), new ApplePacker0("Small Business", "The Original Johnny Appleseed"), new ApplePacker0("Small Business", "Johnny Appleseed & Son Pack-4-U", 50), new ApplePacker0("Small Business", "Johnny Appleseed & Son Pack-4-U", 50), new ApplePacker0("Small Business", "Johnny Appleseed & Son Pack-4-U", 50), new ApplePacker0("Small Business", "Johnny Appleseed & Son Pack-4-U", 50), new ApplePacker99(1), new ApplePacker99(2), new ApplePacker99(3), new ApplePacker99(4), new ApplePacker99(5) }; }
/*****************/ /* ApplePacker99 */ /*****************/ class ApplePacker99 implements ApplePackerFranchise { private final String parentCo = "ApplePacker99"; private ApplePacker packer; public ApplePacker99(int version) { packer = new ApplePacker99a(this.parentCo, 300); } public String parentCompany() { return packer.parentCompany(); } public String businessName() { return packer.businessName(); } public void initialize() { packer.initialize(); } public boolean receive(Collection<BagOfApples> bags) { return packer.receive(bags); } public Collection<AppleCarton> pack(Collection<AppleCarton> cartons) { return packer.pack(cartons); } private class ApplePacker99a extends ApplePacker { public ApplePacker99a(String parentCo, int inventorySize) { super(parentCo, "ApplePacker99a", inventorySize); this.preferredSuppliers.add(Grower.RANDOM_REDS); } public void initialize() { /* do nothing */ } public Collection<AppleCarton> pack(Collection<AppleCarton> cartons) { for (AppleCarton carton : cartons) { if (this.inventory.count() < 10) this.restock(); BagOfApples bag = inventory.oneVolLt(carton.remainingSpace()); while (bag != null) { if (!inventory.remove(bag)) return null; if (!carton.add(bag)) return null; bag = inventory.oneVolLt(carton.remainingSpace()); } if (!carton.close()) return null; } return cartons; } } }