Java tutorial
/* * Copyright (c) 2014 by Ernesto Carrella * Licensed under MIT license. Basically do what you want with it but cite me and don't sue me. Which is just politeness, really. * See the file "LICENSE" for more information */ package model.utilities.dummies; import agents.HasInventory; import agents.firm.GeographicalFirm; import com.google.common.base.Preconditions; import com.google.common.collect.Multimap; import financial.market.GeographicalMarket; import financial.market.Market; import financial.utilities.Quote; import goods.Good; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleObjectProperty; import model.MacroII; import model.utilities.ActionOrder; import model.utilities.geography.HasLocation; import model.utilities.geography.Location; import model.utilities.logs.LogEvent; import model.utilities.logs.LogLevel; import sim.engine.SimState; import sim.engine.Steppable; import java.util.Collection; import java.util.Collections; import java.util.Comparator; /** * <h4>Description</h4> * <p/> This is supposed to be the final demand of good in the oil pump scenario; * Every day it puts sale quotes it doesn't expect to be filled, at the end of the day it always * <p/> * <p/> * <h4>Notes</h4> * Created with IntelliJ * <p/> * <p/> * <h4>References</h4> * * @author carrknight * @version 2013-10-27 * @see */ public class GeographicalCustomer extends Customer implements HasLocation { private Location location; /** /** * the firm that supplied you the last unit of oil; as a JavaFX property so that I don't have to implement listeners */ private SimpleObjectProperty<GeographicalFirm> lastSupplier; private double distanceExponent = 1; public GeographicalCustomer(MacroII model, int maxPrice, double x, double y, GeographicalMarket market) { super(model, maxPrice, market); location.setxLocation(x); location.setyLocation(y); model.scheduleSoon(ActionOrder.DAWN, new Steppable() { @Override public void step(SimState simState) { if (!GeographicalCustomer.this.isActive()) return; lastSupplier.setValue(null); model.scheduleTomorrow(ActionOrder.DAWN, this); } }); } @Override protected void init() { this.location = new Location(0, 0); lastSupplier = new SimpleObjectProperty<>(); } /** * Chooses which of this firms the customer wants to choose, if any. * @param firmsToChooseFrom The list of available firms * @return The firm chosen, or null if none is chosen */ public GeographicalFirm chooseSupplier(final Multimap<GeographicalFirm, Quote> firmsToChooseFrom) { Preconditions.checkArgument(!firmsToChooseFrom.isEmpty()); handleNewEvent( new LogEvent(this, LogLevel.TRACE, "was given these firms to choose from: {}", firmsToChooseFrom)); //basically we want to find the minimum price+distance GeographicalFirm best = Collections.min(firmsToChooseFrom.keySet(), new Comparator<GeographicalFirm>() { @Override public int compare(GeographicalFirm o1, GeographicalFirm o2) { //price + distance double pricePlusDistance1 = firmsToChooseFrom.get(o1).iterator().next().getPriceQuoted() + distance(GeographicalCustomer.this, o1); assert pricePlusDistance1 >= 0; double pricePlusDistance2 = firmsToChooseFrom.get(o2).iterator().next().getPriceQuoted() + distance(GeographicalCustomer.this, o2); assert pricePlusDistance2 >= 0; return Double.compare(pricePlusDistance1, pricePlusDistance2); } }); assert best != null; //is the minimum price distance okay? final long bestPriceAtSource = firmsToChooseFrom.get(best).iterator().next().getPriceQuoted(); double bestPricePlusDistance = bestPriceAtSource + distance(GeographicalCustomer.this, best); //log it! handleNewEvent( new LogEvent(this, LogLevel.TRACE, "the best firm found was {}, pricing {}, total personal cost {}", best, bestPriceAtSource, bestPricePlusDistance)); if (bestPricePlusDistance <= getMaxPrice()) { handleNewEvent(new LogEvent(this, LogLevel.TRACE, "decided to buy from chosen best")); return best; } else return null; } /** * just an easy way to compute the monetary costs of distance * @param customer * @param seller * @return */ private double distance(HasLocation customer, HasLocation seller) { //for now just pitagorean distance double xDistance = Math.pow(customer.getxLocation() - seller.getxLocation(), 2); double yDistance = Math.pow(customer.getyLocation() - seller.getyLocation(), 2); double distance = Math.pow(Math.sqrt(xDistance + yDistance), distanceExponent); assert distance >= 0; return distance; } @Override public double getxLocation() { return location.getxLocation(); } @Override public DoubleProperty xLocationProperty() { return location.xLocationProperty(); } @Override public void setxLocation(double xLocation) { location.setxLocation(xLocation); } @Override public double getyLocation() { return location.getyLocation(); } @Override public DoubleProperty yLocationProperty() { return location.yLocationProperty(); } @Override public void setyLocation(double yLocation) { location.setyLocation(yLocation); } /** * This method is called when inventory has to increase by 1. The reference to the sender is for accounting purpose only * * @param g what good is delivered? * @param sender who sent it? */ @Override public void receive(Good g, HasInventory sender) { super.receive(g, sender); if (sender != null && g.getType().equals(getMarket().getGoodType()) && sender instanceof GeographicalFirm) lastSupplier.setValue((GeographicalFirm) sender); handleNewEvent(new LogEvent(this, LogLevel.TRACE, "Received {} from {}, consequently my last supplier is {}", g, sender, lastSupplier.get())); } //i override this to call removeAllBuyQuoteByBuyer because it's faster for geographical markets @Override protected void removeAllQuotes(Market market) { final Collection<Quote> quotesRemoved = market.removeAllBuyQuoteByBuyer(this); handleNewEvent(new LogEvent(this, LogLevel.TRACE, "removed {} quotes", quotesRemoved.size())); assert (quotesRemoved.size() <= getDailyDemand()); bidsMade.clear(); } public GeographicalFirm getLastSupplier() { return lastSupplier.get(); } public SimpleObjectProperty<GeographicalFirm> lastSupplierProperty() { return lastSupplier; } public double getDistanceExponent() { return distanceExponent; } public void setDistanceExponent(double distanceExponent) { this.distanceExponent = distanceExponent; } }