Package ise.mace.groups

Source Code of ise.mace.groups.PoliticalGroup

package ise.mace.groups;

import ise.mace.agents.PoliticalAgentGroup;
import ise.mace.environment.PublicEnvironmentConnection;
import ise.mace.inputs.LeaveNotification.Reasons;
import ise.mace.models.GroupDataInitialiser;
import ise.mace.models.HuntingTeam;
import ise.mace.models.Tuple;
import ise.mace.participants.AbstractGroupAgent;
import ise.mace.tokens.AgentType;
import ise.mace.tokens.InteractionResult;
import ise.mace.participants.PublicGroupDataModel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.LinkedHashMap;
import java.util.Random;

/**
*
*/
public class PoliticalGroup extends AbstractGroupAgent
{
  private static final long serialVersionUID = 1L;
  //The fee a group must pay to play the game
  private static final double priceToPlay = 100;
  //This constant defines the maximum score a group can attain during this simulation
  private static final double achievementThreshold = 1000;//the goal that any group is trying to achieve (it can be thought as the group's progression to a new age)
  //The greediness level of this group
  private final double greediness;
  //This structure stores the ids of the groups that are currently in need and the amount they request
  private static Map<String, Double> inNeed = new HashMap<String, Double>();
  //Stores all the requests that have been accepted
  private static Map<String, HashMap<String, Tuple<Double, Double>>> loanRequestsAccepted = new HashMap<String, HashMap<String, Tuple<Double, Double>>>();
  //The elements of this structure is a signal to a group that someone has repaid for the loan
  private static Map<String, List<Tuple<String, Double>>> loanRepayments = new HashMap<String, List<Tuple<String, Double>>>();
  //The following structures store the loans given and taken by this group along with the information for that loan
  private Map<String, List<Tuple<Double, Double>>> loansGiven = new HashMap<String, List<Tuple<Double, Double>>>();
  private Map<String, List<Tuple<Double, Double>>> loansTaken = new HashMap<String, List<Tuple<Double, Double>>>();
  private Map<String, List<Tuple<Double, Double>>> loansTakenHist = new HashMap<String, List<Tuple<Double, Double>>>();
  //This structures provide public access to some information about this group
  private static Map<String, Map<String, List<Tuple<Double, Double>>>> publicLoansGiven = new HashMap<String, Map<String, List<Tuple<Double, Double>>>>();
  private static Map<String, Map<String, List<Tuple<Double, Double>>>> publicLoansTaken = new HashMap<String, Map<String, List<Tuple<Double, Double>>>>();
  private static Map<String, Double> publicGreediness = new HashMap<String, Double>();

  @Deprecated
  public PoliticalGroup()
  {
    super();
    this.greediness = 0; // Placeholder; dervivied at run time
  }

  public PoliticalGroup(GroupDataInitialiser dm)
  {
    super(dm);
    this.greediness = this.uniformRand();
  }

  @Override
  protected void onActivate()
  {
    this.setGroupStrategy(AgentType.R); //ADDED The0

  }

  @Override
  protected boolean respondToJoinRequest(String playerID)
  {


    if (getDataModel().getMemberList().isEmpty())
    {
      //if empty then 'playerID' created the group so there is no need to compute a heuristic
      return true;
    }
    else if (getDataModel().getMemberList().size() == 1)
    {
      //if there is only one member then 'playerID' was invited and wants to accept the invitation
      //so there is no need to compute a heuristic
      return true;
    }
    else if (getConn().getAgentById(playerID) == null) //ADDED THE0
    {
      //agent does not exist so invitation is denied
      return false;
    }
    else if (this.getId().equals(PoliticalAgentGroup.special))
    { //exception for the Special group
      return true;
    }
    else
    {
      double maxDistance = Math.sqrt(2);
      int numKnownTrustValues = 0;
      double trustSum = 0;

      //Retieve the trust value between requester and the group
      for (String trustor : this.getDataModel().getMemberList())
      {
        if (getConn().getAgentById(trustor).getTrust(playerID) != null)
        {
          trustSum += getConn().getAgentById(trustor).getTrust(playerID);
          numKnownTrustValues++;
        }
      }

      //Calculate the vector distance between these two agents socio-economic beliefs
      double economic = getConn().getAgentById(playerID).getEconomicBelief() - getDataModel().getCurrentEconomicPoisition();//change in X
      double social = getConn().getAgentById(playerID).getSocialBelief() - getDataModel().getEstimatedSocialLocation();//change in Y
      double vectorDistance = Math.sqrt(Math.pow(economic, 2) + Math.pow(social,
              2));

      //The longer the distance the lower the esFaction is. Therefore, agents close to group's beliefs have
      //higher probability of joining this group
      double esFaction = 1 - (vectorDistance / maxDistance);

      double heuristicValue;
      if (numKnownTrustValues != 0)
      {
        //The actual heuristic value is calculated. The politics is more important for compatibility than
        //trust when a group decides on the request, but trust does contribute signicantly
        heuristicValue = 0.4 * (trustSum / numKnownTrustValues) + 0.6 * esFaction;
      }
      else
      {
        heuristicValue = 0.6 * esFaction;
      }

      if (heuristicValue > 0.5)
      {
        //agent can join, so update economic beliefs
        double size = this.getDataModel().getMemberList().size();
        economic = 0;
        for (String members : getDataModel().getMemberList())
        {
          if (getConn().getAgentById(members) != null) //GIVES PROBLEMS
            economic += getConn().getAgentById(members).getEconomicBelief();
        }
        economic += getConn().getAgentById(playerID).getEconomicBelief();
        economic = economic / (size + 1);
        setEconomicPosition(economic);
        return true;
      }
      else
      {
        return false;
      }
    }
  }
  private Comparator<String> c = new Comparator<String>()
  {
    private Random r = new Random(0);

    @Override
    public int compare(String o1, String o2)
    {
      return (r.nextBoolean() ? -1 : 1);
    }
  };

  @Override
  public List<HuntingTeam> selectTeams()
  {
    ArrayList<HuntingTeam> teams = new ArrayList<HuntingTeam>();
    List<String> members = new ArrayList<String>(getDataModel().getMemberList());
    Collections.sort(members, c);


    int agents = members.size();
    for (int i = 0; i < agents; i += 2)
    {
      int ubound = (i + 2 >= agents) ? agents : i + 2;
      teams.add(new HuntingTeam(members.subList(i, ubound)));
    }

    return teams;
  }

  @Override
  protected void onMemberLeave(String playerID, Reasons reason)
  {
    if (this.getId().equals(PoliticalAgentGroup.special))
    {
      //do nothing
    }
    else
    {
      //update economic belief of the group when the agent leaves the group
      double size = this.getDataModel().getMemberList().size();
      double economic = 0;
      for (String members : this.getDataModel().getMemberList())
      {
        economic += getConn().getAgentById(members).getEconomicBelief();
      }
      economic = economic / (size);
      this.setEconomicPosition(economic);
    }
  }

  @Override
  protected void beforeNewRound()
  {
    if (getDataModel().getMemberList().size() != 1)
    {
      List<String> newPanel = updatePanel();
      this.setPanel(newPanel);
    }
    this.setGroupStrategy(decideGroupStrategy());

    //If a group in need has died then we have to remove it from the set.
    if (!getConn().getGroups().containsAll(inNeed.keySet()))
    {
      Set<String> available = getConn().getGroups();
      Iterator<String> i = inNeed.keySet().iterator();
      while (i.hasNext())
      {
        String member = i.next();
        if (!available.contains(member))
        {
          i.remove();
        }
      }
    }

    //Here we check the economic status of a group
    theMoneyIsOK(getDataModel().getCurrentReservedFood());

    //We update the group panel
    if (getDataModel().getMemberList().size() != 1)
    {
      List<String> newPanel = updatePanel();
      this.setPanel(newPanel);
    }

    //We update the group's greediness. For now it is constant
    publicGreediness.put(this.getId(), greediness);
  }

  /**
   * This method updates the panel for this group. The panel is the set of leaders in this group
   * The size of the panel depends on the social position of the group. If it is at the very top
   * it has a single leader (dictator). If it is at the bottom then every member belongs to the panel (anarchism).
   * @param none
   * @return The new panel members.
   */
  private List<String> updatePanel()
  {

    double groupSocialPosition;
    int population, panelSize;

    //STEP 1:Find the size of the panel. It is the proportion of the total population that
    // can be in the panel. It is calculated using the social position of the group.
    population = getDataModel().getMemberList().size();
    groupSocialPosition = getDataModel().getEstimatedSocialLocation();

    //Round to the closest integer
    panelSize = (int)Math.round(population * groupSocialPosition);
    if (panelSize == 0) //The group is on the very top of the axis. Dictatorship
    {
      //Force panelSize to be at least one (dictator)
      panelSize = 1;
    }
    //STEP 1 END

    //STEP 2: Get the average trust of each agent in the group
    List< Tuple<String, Double>> panelCandidates = new LinkedList< Tuple<String, Double>>();

    List<String> groupMembers = getDataModel().getMemberList();

    for (String candidate : groupMembers)
    {
      double sum = 0;
      int numKnownTrustValues = 0;
      for (String member : groupMembers)
      {
        if ((getConn().getAgentById(member).getTrust(candidate) != null) && (!member.equals(
                candidate)))
        {
          sum += getConn().getAgentById(member).getTrust(candidate);
          numKnownTrustValues++;
        }
      }

      Tuple<String, Double> tuple;
      if (numKnownTrustValues != 0)
      {
        tuple = new Tuple<String, Double>(candidate, sum / numKnownTrustValues);
        panelCandidates.add(tuple);
      }
    }
    //STEP 2 END

    //STEP 3: Sort the agents in descending order of trust values
    Collections.sort(panelCandidates, d);
    //STEP 3 END

    //STEP 4: Populate the panel list with the most trusted agents in the group (i.e. the leaders)
    //Note that eventhough an agent is a candidate its trust must be above a threshold to become member of the panel.
    //The threshold is the social position. If the group is highly authoritarian then anyone with a trust value
    //above zero can become a leader. In libertarian groups panel formations are rare since a relatively high trust value
    //must be achieved! Also the threshold acts as a warning for current panel members. If their trust falls
    //below this threshold due to bad decisions they will be ousted in the next round.
    List<String> newPanel = new LinkedList<String>();
    if (!panelCandidates.isEmpty() && (panelCandidates.size() >= panelSize))//Panel is not empty and we have enough candidates to select leaders
    {
      for (int i = 0; i < panelSize; i++)
      {
        if (panelCandidates.get(i).getValue() >= groupSocialPosition)
        {
          newPanel.add(panelCandidates.get(i).getKey());
        }
      }
    }
    //STEP 4 END

    return newPanel;
  }
  private Comparator< Tuple<String, Double>> d = new Comparator< Tuple<String, Double>>()
  {
    @Override
    public int compare(Tuple<String, Double> o1, Tuple<String, Double> o2)
    {
      Double v1 = o1.getValue();
      Double v2 = o2.getValue();
      return (v1 > v2 ? -1 : 1);
    }
  };
   
  /**
   * A political group can play the stag hunt game with another group. The panel must make a decision regarding
   * their strategy. Important considerations for the decision is the social belief and the preferred strategy of
   * the group and the panel.
   * @param none
   * @return The group's chosen strategy
   */
  @Override
  protected AgentType decideGroupStrategy()
  {
    //Check if this group has leader/leaders. If leaders have not emerge yet then no decision at all
    List<String> currentPanel = getDataModel().getPanel();
    int population = getDataModel().getMemberList().size();

    if (currentPanel.isEmpty() || (population == 1)) return null;

    List<Tuple<AgentType, Double>> followersTypeCounterList = new LinkedList<Tuple<AgentType, Double>>();
    List<Tuple<AgentType, Double>> panelTypeCounterList = new LinkedList<Tuple<AgentType, Double>>();

    //We get lists containing panel's and followers' preferences in strategies in descending order
    followersTypeCounterList = getStrategyPreferences(
            getDataModel().getMemberList());
    panelTypeCounterList = getStrategyPreferences(currentPanel);

    //Calculate the quotum. It is the number of supporters needed to pass a proposal. In this case proposal
    //is the strategy of the group. The quotum is a function of the social belief of the group
    double quotum = (population * getDataModel().getEstimatedSocialLocation()) / population;

    //Start with the most prefereed strategy of the panel (the strategy that the leader/leaders wish to follow
    //If this strategy is supported by a high enough number of followers (quotum) then we pick this strategy
    //Otherwise try the next best strategy. The lower the quotum the less easy is to get your proposal accepted
    //This is the case of dictatorship.
    Iterator<Tuple<AgentType, Double>> i = panelTypeCounterList.iterator();
    while (i.hasNext())
    {
      int n = 0;
      Tuple<AgentType, Double> panelPreference = i.next();
      while (panelPreference.getKey() != followersTypeCounterList.get(n).getKey())
      {
        n++;
      }
      double followerSupport = followersTypeCounterList.get(n).getValue();
      if (followerSupport >= quotum)
      {
        return panelPreference.getKey();
      }
    }
    //If we have reached this statement then we have not found a well suported strategy probably because the
    //quotum is very high (bottom of y axis - anarchism)
    return null;
  }

  /**
   * This is a helper method which returns preferred strategies of a set of agents in descending order
   * @param The set of agents
   * @return A list of preferred strategies in descending order
   */
  private List<Tuple<AgentType, Double>> getStrategyPreferences(
          List<String> agents)
  {

    int population = agents.size();

    Tuple<AgentType, Double> tftTypes = new Tuple<AgentType, Double>(
            AgentType.TFT, 0.0);
    Tuple<AgentType, Double> acTypes = new Tuple<AgentType, Double>(AgentType.AC,
            0.0);
    Tuple<AgentType, Double> adTypes = new Tuple<AgentType, Double>(AgentType.AD,
            0.0);
    Tuple<AgentType, Double> rTypes = new Tuple<AgentType, Double>(AgentType.R,
            0.0);

    //Count types in agents list
    for (String agentID : agents)
    {
      switch (getConn().getAgentById(agentID).getAgentType())
      {
        case AC:
          double oldCountAC = acTypes.getValue();
          acTypes.setValue(oldCountAC + 1);
          break;
        case AD:
          double oldCountAD = adTypes.getValue();
          adTypes.setValue(oldCountAD + 1);
          break;
        case TFT:
          double oldCountTFT = tftTypes.getValue();
          tftTypes.setValue(oldCountTFT + 1);
          break;
        case R:
          double oldCountR = rTypes.getValue();
          rTypes.setValue(oldCountR + 1);
          break;
      }
    }

    //Find the average of each type
    acTypes.setValue(acTypes.getValue() / population);
    adTypes.setValue(adTypes.getValue() / population);
    tftTypes.setValue(tftTypes.getValue() / population);
    rTypes.setValue(rTypes.getValue() / population);

    List< Tuple<AgentType, Double>> preferencesRatioList = new LinkedList<Tuple<AgentType, Double>>();

    //Add the ratios to the list
    preferencesRatioList.add(acTypes);
    preferencesRatioList.add(adTypes);
    preferencesRatioList.add(tftTypes);
    preferencesRatioList.add(rTypes);

    //Sort the preferred startegies in descending order
    Collections.sort(preferencesRatioList, preferencesComparator);

    return preferencesRatioList;
  }
  private Comparator< Tuple<AgentType, Double>> preferencesComparator = new Comparator< Tuple<AgentType, Double>>()
  {
    @Override
    public int compare(Tuple<AgentType, Double> o1, Tuple<AgentType, Double> o2)
    {
      Double v1 = o1.getValue();
      Double v2 = o2.getValue();
      return (v1 > v2 ? -1 : 1);
    }
  };
  private Comparator< Tuple<Double, Double>> loansComparator = new Comparator< Tuple<Double, Double>>()
  {
    @Override
    public int compare(Tuple<Double, Double> o1, Tuple<Double, Double> o2)
    {
      Double v1 = o1.getKey();
      Double v2 = o2.getKey();
      return (v1 > v2 ? -1 : 1);
    }
  };

  /**
   * This method allows a group to spend money for either playing the game or for public service.
   * The group can also repay some of its loans in this function
   * @param none
   * @return The new strategy (if they don't have money to play the sit out) and the new reserve after payments.
   */
  @Override
  protected Tuple<AgentType, Double> makePayments()
  {
    double currentFoodReserve;
    AgentType strategy = getDataModel().getGroupStrategy();

    currentFoodReserve = getDataModel().getCurrentReservedFood();

    if (this.getDataModel().getReservedFoodHistory().size() < 3)
      return new Tuple<AgentType, Double>(strategy, 200.0);

    //Check if the group is in need. If it doesn't then proceed with the payments
    if (!inNeed.containsKey(this.getId()))
    {
      //Spend money for playing the game. The standard fee is defined in the data members
      if (strategy != null)
      {
        //pay, in theory, to join the game among groups
        currentFoodReserve -= priceToPlay;
        if (currentFoodReserve < priceToPlay)//if the theory is way to risky
        {
          currentFoodReserve += priceToPlay;//go back
          strategy = null;//and sit this turn out
        }
      }

      //Check you greediness against a random value. If your greediness is above that value spend.
      //Groups with higher greediness value have higher chances of spending money
      if (this.greediness > this.uniformRand())
      {
        //check how close you are to attaining achievement
        double goalRatio = currentFoodReserve / achievementThreshold;
        double percentDecrease;
        percentDecrease = ((1 - getAverageHappiness(0)) * goalRatio) * currentFoodReserve;
        currentFoodReserve -= percentDecrease;
      }

      //After paying for the game and for public service check if you can repay any of the loans (if there are any)
      if (!loansTaken.isEmpty())
      {
        //Set<String> creditorsSet = loansTaken.keySet();
        //for (String creditorID: creditorsSet)
        Iterator<String> creditors = loansTaken.keySet().iterator();
        while (creditors.hasNext())
        {
          String creditorID = creditors.next();
          double totalAmountPaid = 0;
          //Find the loans taken from this creditor and sort the in descending order
          Collections.sort(loansTaken.get(creditorID), loansComparator);
          //Iterate through the loans from this creditor
          List<Tuple<Double, Double>> loanInfoList = loansTaken.get(creditorID);
          Iterator<Tuple<Double, Double>> i = loanInfoList.iterator();
          while (i.hasNext())
          {
            Tuple<Double, Double> loanInfo = i.next();
            //Calculate the amount to pay (amount *(1+ interest))
            double amountToPay = loanInfo.getKey() * (1 + loanInfo.getValue());
            //If the group has the money then it pays
            if (currentFoodReserve > amountToPay + priceToPlay)
            {
              currentFoodReserve -= amountToPay;
              //We remove this loan since it is paid
              i.remove();
              totalAmountPaid += amountToPay;
            }
          }
          //If that was the only (or the only non repaid) loan taken from this creditor then remove the creditor form the list
          if (loansTaken.get(creditorID).isEmpty()) creditors.remove();

          //If the group has repaid any of the loans prepare a ticket and send it to the creditor
          //in order to process the payment. The ticket contains the id of the debtor and the loan information
          if (totalAmountPaid != 0)
          {
            Tuple<String, Double> paymentReceipt = new Tuple<String, Double>();
            paymentReceipt.set(this.getId(), totalAmountPaid);
            if (!loanRepayments.containsKey(creditorID))
            {
              List<Tuple<String, Double>> existingPayments = new ArrayList<Tuple<String, Double>>();
              existingPayments.add(paymentReceipt);
              loanRepayments.put(creditorID, existingPayments);
            }
            else
            {
              List<Tuple<String, Double>> existingPayments = loanRepayments.get(
                      creditorID);
              existingPayments.add(paymentReceipt);
            }
          }
        }
      }
    }
    else
    {
      strategy = null;
    }
    return new Tuple<AgentType, Double>(strategy, currentFoodReserve);
  }

  /**
   * This method computes the average happiness for this group for a specific turn
   * @param The number of turns ago
   * @return The average happiness of the group at that time
   */
  private double getAverageHappiness(int turnsAgo)
  {
    double average = 0;

    if (!getDataModel().getMemberList().isEmpty())
    {
      Double happiness;
      for (String member : getDataModel().getMemberList())
      {
        if (turnsAgo > 0)
        {
          if (getConn().getAgentById(member).getHappinessHistory().size() > 1)
          {
            happiness = getConn().getAgentById(member).getHappinessHistory().getValue(
                    turnsAgo);
          }
          else
          {
            happiness = 0.0;
          }
          if (happiness != null)//otherwise add nothing
          {
            average += happiness;
          }
        }
        else
        {
          happiness = getConn().getAgentById(member).getCurrentHappiness();
          if (happiness != null)//otherwise add nothing
          {
            average += happiness;
          }
        }
      }
      average = average / getDataModel().getMemberList().size();
    }
    return average;
  }

  /**
   * This method checks if the economic status of the group is good or bad.
   * It is good if they have money to last at least another round and their reserve increases
   * If the group is in trouble a loan is requested based on its needs.
   * @param The current reserve
   * @return Is the group in need?
   */
  private boolean theMoneyIsOK(double mostRecentReserve)
  {
    //is the reserve increasing or decreasing?
    double deltaFoodReserve;
    if (getDataModel().getReservedFoodHistory().size() > 1)
    {
      deltaFoodReserve = mostRecentReserve - getDataModel().getReservedFoodHistory().getValue(
              1);
    }
    else
    {
      deltaFoodReserve = 0;
    }

    //check how close the group is to attaining achievement
    double goalRatio = mostRecentReserve / achievementThreshold;

    //If the group is already in the set of groups in need do nothing.
    //Otherwise check for a sufficient amount of food and an incresing trend in their reserve
    //If both conditions are not met declare this group as "a group in need"
    if (!inNeed.containsKey(this.getId()))
    {
      if ((goalRatio < 0.15) && (deltaFoodReserve < 0))
      {
        //if group is only 15% of the way then the group needs help
        inNeed.put(this.getId(), 150 - mostRecentReserve);
        return false;
      }
      else
      {
        //everything is ok, nobody needs help
        return true;
      }
    }
    else
    {
      //you've been in need for quite a while, it would seem
      return false;
    }
  }

  /**
   * After the group members return from hunting we gather the shared food. Then depending on
   * the financial status of the group we decide the tax rate. We intercept the taxed amount and store
   * it in the reserved food pool. The rest is distributed to the members.
   * Before deciding the tax rate we must update the reserve if the group has received a payment from one of its
   * debtors.
   * @param The shared food for this round
   * @return The new updated shared food and reserve
   */
  @Override
  protected Tuple<Double, Double> updateTaxedPool(double sharedFood)
  {
    double currentFoodReserve;
    currentFoodReserve = getDataModel().getCurrentReservedFood();
    double tax = 0;

    //If this groups has any debtors must check if any of them has paid back
    if (loanRepayments.containsKey(this.getId()))
    {
      List<Tuple<String, Double>> paymentsInfo = new ArrayList<Tuple<String, Double>>();
      paymentsInfo = loanRepayments.get(this.getId());

      Iterator<Tuple<String, Double>> i = paymentsInfo.iterator();
      while (i.hasNext())
      {
        Tuple<String, Double> currentPayment = i.next();
        double amountReceived = currentPayment.getValue();
        //Update the reserve
        currentFoodReserve += amountReceived;
      }
      loanRepayments.remove(this.getId());
    }

    //check how close you are to attaining achievement
    double goalRatio = currentFoodReserve / achievementThreshold;

    if (inNeed.containsKey(this.getId()))
    {
      //the group is in trouble and needs to tax high
      tax = 1 - goalRatio;//since you're far away from your achievement, tax high
    }
    else
    {
      //tax normally
      tax = getAverageHappiness(0) * (1 - goalRatio);
    }

    //The actual taxation happens here
    currentFoodReserve = currentFoodReserve + sharedFood * tax;
    sharedFood = sharedFood - sharedFood * tax;

    Tuple<Double, Double> newSharedAndReserve = new Tuple<Double, Double>();
    newSharedAndReserve.set(sharedFood, currentFoodReserve);

    return newSharedAndReserve;
  }

  /**
   * This method allows this group to interact with other groups. If it is in need, it can check
   * if any of its loan request has been accepted. If the group is not in trouble it can check if there
   * is any group which needs help. If it has enough money it can give them money (food).
   * @param none
   * @return The interaction result and the new updated reserve (if they gave any loans)
   */
  @Override
  protected Tuple<InteractionResult, Double> interactWithOtherGroups()
  {

    double currentFoodReserve = getDataModel().getCurrentReservedFood();
    Tuple<InteractionResult, Double> interactionResult = new Tuple<InteractionResult, Double>();

    //First check if you are in need
    if (inNeed.containsKey(this.getId()))
    {
      //Check if group has managed to recover their economic status to good.
      //Also even if they managed to do so if someone has already givem them a loan then they must pay
      if ((currentFoodReserve > priceToPlay + 50) && (!loanRequestsAccepted.containsKey(
              this.getId())))
      {
        inNeed.remove(this.getId());
        interactionResult.set(InteractionResult.NothingHappened, 0.0);
      }
      else if (loanRequestsAccepted.containsKey(this.getId()))
      {
        //If the request for a loan was granted then store the receipt in your records to help with repayments later (Hopefully..)
        HashMap<String, Tuple<Double, Double>> loanRecord = loanRequestsAccepted.get(
                this.getId());
        Set<String> giverID = loanRecord.keySet();

        Tuple<Double, Double> currentLoanInfo = loanRecord.get(
                giverID.iterator().next());
        if (!loansTaken.containsKey(giverID.iterator().next()))
        {
          List<Tuple<Double, Double>> existingLoans = new ArrayList<Tuple<Double, Double>>();
          existingLoans.add(currentLoanInfo);
          this.loansTaken.put(giverID.iterator().next(), existingLoans);
        }
        else
        {
          List<Tuple<Double, Double>> existingLoans = this.loansTaken.get(
                  giverID.iterator().next());
          existingLoans.add(currentLoanInfo);
        }

        if (!loansTakenHist.containsKey(giverID.iterator().next()))
        {
          List<Tuple<Double, Double>> existingLoans = new ArrayList<Tuple<Double, Double>>();
          existingLoans.add(currentLoanInfo);
          this.loansTakenHist.put(giverID.iterator().next(), existingLoans);
        }
        else
        {
          List<Tuple<Double, Double>> existingLoans = this.loansTakenHist.get(
                  giverID.iterator().next());
          existingLoans.add(currentLoanInfo);
        }

        //Add this loan in the loans taken structure which is publicly accessible
        publicLoansTaken.put(this.getId(), loansTakenHist);

        loanRequestsAccepted.remove(this.getId());
        inNeed.remove(this.getId());
        interactionResult.set(InteractionResult.LoanTaken,
                loanRecord.get(giverID.iterator().next()).getKey());
      }
      else
      {
        //Else if no one has given you money do nothing
        interactionResult.set(InteractionResult.NothingHappened, 0.0);
      }
      return interactionResult;
    }

    //If you are not in need you might want to help another group
    if (!inNeed.isEmpty())
    {
      Map<String, Double> inNeedSorted = new HashMap<String, Double>();
      inNeedSorted = sortHashMap(inNeed);
      for (String groupID : inNeedSorted.keySet())
      {
        //if someone else accepted their requests do nothing!
        if (!loanRequestsAccepted.containsKey(groupID))
        {
          double amountNeeded = inNeed.get(groupID);
          //intrest = 0.5 of loaner's greediness and requesters situation which is neve above 0.15
          double interestRate = 0.05 * greediness + (getConn().getGroupById(
                  groupID).getCurrentReservedFood() / achievementThreshold);

          //For now give a loan if u have the amount needed
          if ((currentFoodReserve - amountNeeded > priceToPlay + 50) && (this.greediness < this.uniformRand()))
          {
            //Create a tuple containing the amount granted and the interest
            Tuple<Double, Double> loanInfo = new Tuple<Double, Double>();
            loanInfo.set(amountNeeded, interestRate);

            //Then store the loan info along with the requester ID in your records
            if (!loansGiven.containsKey(groupID))
            {
              List<Tuple<Double, Double>> existingLoans = new ArrayList<Tuple<Double, Double>>();
              existingLoans.add(loanInfo);
              this.loansGiven.put(groupID, existingLoans);
            }
            else
            {
              List<Tuple<Double, Double>> existingLoans = this.loansGiven.get(
                      groupID);
              existingLoans.add(loanInfo);
            }

            publicLoansGiven.put(this.getId(), loansGiven);

            //Use the same structure to send a receipt to the requester to store it in his records
            HashMap<String, Tuple<Double, Double>> loanRecord = new HashMap<String, Tuple<Double, Double>>();
            loanRecord.put(this.getId(), loanInfo);
            loanRequestsAccepted.put(groupID, loanRecord);
            interactionResult.set(InteractionResult.LoanGiven, amountNeeded);
            return interactionResult;
          }
        }
      }
    }
    interactionResult.set(InteractionResult.NothingHappened, 0.0);
    return interactionResult;
  }

  private HashMap<String, Double> sortHashMap(Map<String, Double> unsorted)
  {
    Map<String, Double> tempMap = new HashMap<String, Double>();
    for (String key : unsorted.keySet())
    {
      tempMap.put(key, unsorted.get(key));
    }

    //make sure to get the data
    List<String> unsortedKeys = new ArrayList<String>(tempMap.keySet());
    List<Double> unsortedValues = new ArrayList<Double>(tempMap.values());

    //make our result ready
    HashMap<String, Double> sortedMap = new LinkedHashMap<String, Double>();

    //put the values in a tree set, they are immediately orderd, then put them in an array
    TreeSet<Double> sortedSet = new TreeSet<Double>(unsortedValues);
    Object[] sortedArray = sortedSet.toArray();

    //sort them in a map
    for (int i = 0; i < sortedArray.length; i++)
    {
      sortedMap.put(unsortedKeys.get(unsortedValues.indexOf(sortedArray[i])),
              (Double)sortedArray[i]);
    }
    return sortedMap;
  }

  public static Map<String, List<Tuple<Double, Double>>> getLoansGiven(
          PublicGroupDataModel dm)
  {
    if (!publicLoansGiven.containsKey(dm.getId()))
    {
      return null;
    }
    else
    {
      return publicLoansGiven.get(dm.getId());
    }
  }

  public static Map<String, List<Tuple<Double, Double>>> getLoansTaken(
          PublicGroupDataModel dm)
  {
    if (!publicLoansTaken.containsKey(dm.getId()))
    {
      return null;
    }
    else
    {
      return publicLoansTaken.get(dm.getId());
    }
  }

  public static Double getGreediness(PublicGroupDataModel dm)
  {
    return publicGreediness.get(dm.getId());
  }
}
TOP

Related Classes of ise.mace.groups.PoliticalGroup

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.