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;
}
}
}