Package ise.mace.participants

Source Code of ise.mace.participants.AbstractGroupAgent

package ise.mace.participants;

import ise.mace.actions.Death;
import ise.mace.actions.DistributeFood;
import ise.mace.actions.GroupOrder;
import ise.mace.actions.RespondToApplication;
import ise.mace.actions.VoteResult;
import ise.mace.environment.EnvironmentConnection;
import ise.mace.environment.PublicEnvironmentConnection;
import ise.mace.inputs.HuntResult;
import ise.mace.inputs.JoinRequest;
import ise.mace.inputs.LeaveNotification;
import ise.mace.inputs.Proposition;
import ise.mace.inputs.Vote;
import ise.mace.models.GroupDataInitialiser;
import ise.mace.models.HuntingTeam;
import ise.mace.models.Tuple;
import static ise.mace.models.ScaledDouble.scale;
import ise.mace.tokens.AgentType;
import ise.mace.tokens.GroupRegistration;
import ise.mace.tokens.InteractionResult;
import ise.mace.tokens.RegistrationResponse;
import ise.mace.tokens.TurnType;
import ise.mace.tokens.UnregisterRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.simpleframework.xml.Element;
import presage.EnvironmentConnector;
import presage.Input;
import presage.Participant;
import presage.PlayerDataModel;
import presage.environment.messages.ENVRegistrationResponse;

/**
* Abstract Group agent describes form of a group. Implemented as an agent for
* ease of compatibility with presage, since their functionalities overlap a lot
* TODO: Make it clear that the contract calls for a public consturctor with
* one argument that takes in the datamodel.
*/
public abstract class AbstractGroupAgent implements Participant
{
  private static final long serialVersionUID = 1L;
  private final static Logger logger = Logger.getLogger(
          "mace.AbstractGroup");
  /**
   * The DataModel used by this agent.
   */
  @Element
  private GroupDataModel dm;
  /**
   * The authorisation code for use with sexy things like the environment
   */
  private UUID authCode;
  /**
   * Reference to the environment connector, that allows the agent to interact
   * with the environment
   */
  private PublicEnvironmentConnection conn;
  private EnvironmentConnection ec;
  private EnvironmentConnector tmp_ec;
  private Map<String, Double> huntResult;
  private Map<Proposition, Integer> voteResult;
  private static Map<String, Double> previousAmountHunted = new HashMap<String, Double>();

  /**
   *
   * @deprecated
   */
  @Deprecated
  public AbstractGroupAgent()
  {
    super();
  }

  /**
   * Initialises itself with teh group data initialiser, which contains all
   * the necessary information to get a group started
   * @param init
   */
  public AbstractGroupAgent(GroupDataInitialiser init)
  {
    this.dm = GroupDataModel.createNew(init);
    this.dm.random = new Random(this.dm.randomseed);
  }

  /**
   * Gets the ID of the group
   * @return the ID of the group
   */
  @Override
  public String getId()
  {
    return dm.getId();
  }

  /**
   * Gets a list of agent roles within this group
   * @return a list of the agent roles in this group
   */
  @Override
  public ArrayList<String> getRoles()
  {
    return new ArrayList<String>(Arrays.asList(new String[]
            {
              "group"
            }));
  }

  /**
   * Initialises the group
   * @param environmentConnector
   */
  @Override
  public void initialise(EnvironmentConnector environmentConnector)
  {
    tmp_ec = environmentConnector;
    dm.initialise(environmentConnector);
  }

  /**
   * Function called when the group is activated, but has yet to be added to the
   * environment
   */
  @Override
  public final void onActivation()
  {
    GroupRegistration request = new GroupRegistration(dm.getId(),
            dm.getPublicVersion());
    ENVRegistrationResponse r = tmp_ec.register(request);
    this.authCode = r.getAuthCode();
    this.ec = ((RegistrationResponse)r).getEc();
    conn = PublicEnvironmentConnection.getInstance();
    tmp_ec = null;
    onActivate();
  }

  /**
   * function called to say any relevant goodbyes before the group is removed
   * from the simulation
   */
  @Override
  public final void onDeActivation()
  {
    ec.deregister(new UnregisterRequest(dm.getId(), authCode));
  }

  /**
   * Function called upon group execution, where it has access to data concerning
   * other objects in the simulation
   */
  @Override
  public void execute()
  {
    TurnType turn = ec.getCurrentTurnType();

    if (TurnType.firstTurn.equals(turn))
    {
      beforeNewRound();



      clearRoundData();
    }

    switch (turn)
    {
      case GroupSelect:
        // Allow groups to "explore" their surroundings
        doInteractWithOtherGroups();
        break;
      case TeamSelect:
        doTeamSelect();
        break;
      case GoHunt:
        // The panel (if it exists) decides the group's strategy
        doLeadersHunt();
        break;
      case HuntResults:
        doHandleHuntResults();
        break;
      case MakeProposals:
        // Nothing here - agents are proposing and voting
        break;
      case Voting:
        countVotes();
        break;
    }
  }

  /**
   * Data cleaned up to make way for a new round
   */
  private void clearRoundData()
  {

    huntResult = new HashMap<String, Double>();
    voteResult = new HashMap<Proposition, Integer>();
    dm.clearRoundData();
  }

  /**
   * Separates agents in the group into hunting teams
   */
  private void doTeamSelect()
  {

    List<HuntingTeam> teams = selectTeams();
    // TODO: Remove non-group members from teams
    List<String> memberList = this.dm.getMemberList();
    for (HuntingTeam team : teams)
    {
      for (String agent : team.getMembers())
      {
        if (memberList.contains(agent))
        {
          ec.act(new GroupOrder(team, agent), getId(), authCode);
        }
      }
    }
  }

  /**
   * Once the hunters have gathered their winnings, it is processed and
   * distributed here
   */
  private void doHandleHuntResults()
  {
    double shared = 0;

    //The game between groups is played by the special agent which represent a group.
    //The result of that game is added on the shared food amount and distributed back to
    //the followers.
    for (String specialAgent : getConn().getAgents())
    {
      if (getConn().getAgentById(specialAgent).getName().equals(getId()))
      {
        PublicAgentDataModel groupSpecialAgent = getConn().getAgentById(
                specialAgent);
        double specialAgentFoodAmount = groupSpecialAgent.getFoodAmount();
        double extraFood = 0;
        if (previousAmountHunted.get(getId()) != null)
        {
          extraFood = specialAgentFoodAmount - previousAmountHunted.get(getId());
        }

        previousAmountHunted.put(getId(), specialAgentFoodAmount);
        shared += getDataModel().getMemberList().size() * extraFood;
      }

    }

    //Loans simulation addition.In any other simulation tax = 0 always and shared will be the same
    Tuple<Double, Double> updatedSharedAndReserve = updateTaxedPool(shared);
    this.setReservedFood(updatedSharedAndReserve.getValue());
    shared = updatedSharedAndReserve.getKey();
    //Loans simulation addition end


    double taxRate = 1 - dm.getCurrentEconomicPoisition();
    for (Double value : huntResult.values())
    {
      shared += value;
    }

    shared = shared * taxRate / dm.getMemberList().size();

    Map<String, Double> result = new HashMap<String, Double>(huntResult.size());

    for (String agent : huntResult.keySet())
    {
      double value = shared + (1 - taxRate) * huntResult.get(agent);
      result.put(agent, value);
    }

    List<String> informedAgents = new ArrayList<String>();

    for (String agent : result.keySet())
    {
      informedAgents.add(agent);
      ec.act(new DistributeFood(agent, huntResult.get(agent), result.get(agent)),
              getId(), authCode);
    }

    @SuppressWarnings("unchecked")
    List<String> uninformedAgents = new ArrayList<String>(dm.getMemberList());
    uninformedAgents.removeAll(informedAgents);

    for (String agent : uninformedAgents)
    {
      ec.act(new DistributeFood(agent, 0, shared), getId(), authCode);
    }
  }

  private void countVotes()
  {
    dm.setProposals(new HashMap<Proposition, Integer>(voteResult));
    HashMap<String, Proposition> props = new HashMap<String, Proposition>();
    double movement = 0;
    double motionsPassed = 0;

    for (Proposition p : voteResult.keySet())
    {
      if (voteResult.get(p) > 0)
      {
        movement += p.getType().getMovement();
        motionsPassed++;
        logger.log(Level.FINE, "{0}''s {1} proposal was voted in (Vote={2})",
                new Object[]
                {
                  p.getProposer(),
                  p.getType(), voteResult.get(p)
                });
      }
      else
      {
        logger.log(Level.FINE, "{0}''s {1} proposal was not voted in (Vote={2})",
                new Object[]
                {
                  p.getProposer(),
                  p.getType(), voteResult.get(p)
                });
      }
      props.put(p.getProposer(), p);
    }

    // Calculate the groups new position
    double change = dm.getCurrentEconomicPoisition();
    if (motionsPassed > 0)
    {
      dm.setEconomicPosition(scale(change, movement / motionsPassed, 0.1));
      change = dm.getCurrentEconomicPoisition() - change;
    }
    else
    {
      change = 0;
    }
    // Inform each agent of how their vote went, and the overall group movement
    for (String agent : props.keySet())
    {
      Proposition p = props.get(agent);
      ec.act(new VoteResult(p, voteResult.get(p), change), getId(), authCode);
    }
  }

  private void doLeadersHunt()
  {
    AgentType strategy = decideGroupStrategy();
    this.dm.setGroupStrategy(strategy);

    Tuple<AgentType, Double> finalStrategy = makePayments();
    if (finalStrategy.getValue() != getDataModel().getCurrentReservedFood())
    {
      this.setReservedFood(finalStrategy.getValue());
    }
    this.dm.setGroupStrategy(finalStrategy.getKey());
  }

  private void doInteractWithOtherGroups()
  {
    Tuple<InteractionResult, Double> interactionResult = interactWithOtherGroups();
    switch (interactionResult.getKey())
    {
      case LoanTaken:
        this.setReservedFood(
                this.getDataModel().getCurrentReservedFood() + interactionResult.getValue());
        break;
      case LoanGiven:
        this.setReservedFood(
                this.getDataModel().getCurrentReservedFood() - interactionResult.getValue());
        break;
      case NothingHappened:
        //this.setReservedFood(this.getDataModel().getCurrentReservedFood());
        break;
    }

  }

  /**
   * Sets the number of cycles passed
   * @param cycle
   */
  @Override
  public final void setTime(long cycle)
  {
    dm.setTime(cycle);
  }

  /**
   * Returns the DataModel of this object
   * @return The DataModel of this object
   */
  @Override
  public final PlayerDataModel getInternalDataModel()
  {
    return dm.getPublicVersion();
  }

  /**
   * Returns the externally visible elements of the group agent
   * @return The externally visible elements of the group agent
   */
  public final PublicGroupDataModel getDataModel()
  {
    return dm.getPublicVersion();
  }

  protected final void setEconomicPosition(double newPosition)
  {
    this.dm.setEconomicPosition(newPosition);
  }

  protected final void setGroupStrategy(AgentType strategy)
  {
    this.dm.setGroupStrategy(strategy);
  }

  protected final void setPanel(List<String> newPanel)
  {
    this.dm.setPanel(newPanel);
  }

  protected final void setReservedFood(double newAmount)
  {
    this.dm.setReservedFoodHistory(newAmount);
  }

  /**
   * This function puts the inputs into a queue to be processed at the end of
   * the cycle
   * @param input
   */
  @Override
  public final void enqueueInput(Input input)
  {
    if (input.getClass().equals(JoinRequest.class))
    {
      final JoinRequest req = (JoinRequest)input;
      boolean response = this.respondToJoinRequest(req.getAgent());
      if (response) this.dm.addMember(req.getAgent());
      ec.act(new RespondToApplication(req.getAgent(), response), this.getId(),
              authCode);
      logger.log(Level.FINE, "{0} got a join request from {1}", new Object[]
              {
                dm.getName(),
                ec.nameof(((JoinRequest)input).getAgent())
              });
      return;
    }

    if (input.getClass().equals(LeaveNotification.class))
    {
      final LeaveNotification in = (LeaveNotification)input;

      dm.removeMember(in.getAgent());
      this.onMemberLeave(in.getAgent(), in.getReason());
      //Bug fix
      ec.act(new RespondToApplication(in.getAgent(), false), this.getId(),
              authCode);
      //Bug fix end
      logger.log(Level.FINE, "{0} lost memeber {1} because of {2}", new Object[]
              {
                dm.getName(),
                ec.nameof(in.getAgent()), in.getReason()
              });

      if (dm.getMemberList().isEmpty())
      {
        ec.act(new Death(), dm.getId(), authCode);
      }
      return;
    }

    if (input.getClass().equals(HuntResult.class))
    {
      final HuntResult in = (HuntResult)input;
      huntResult.put(in.getAgent(), in.getFoodHunted());
      logger.log(Level.FINE, "Agent {0} has hunted food worth {1} for {2}",
              new Object[]
              {
                ec.nameof(in.getAgent()),
                in.getFoodHunted(), dm.getName()
              });
      return;
    }

    if (input.getClass().equals(Vote.class))
    {
      final Vote v = (Vote)input;
      if (!voteResult.containsKey(v.getProposition()))
      {
        if (!v.getProposition().getOwnerGroup().equals(getId())) return;
        voteResult.put(v.getProposition(), 0);
      }
      voteResult.put(v.getProposition(),
              voteResult.get(v.getProposition()) + v.getVote().getValue());
      logger.log(Level.FINE,
              "Agent {0} has voted {1} on {2} by {3} as a member of {4}",
              new Object[]
              {
                ec.nameof(v.getAgent()),
                v.getVote(), v.getProposition().getType(),
                ec.nameof(v.getProposition().getProposer()), dm.getName()
              });
      return;
    }

    logger.log(Level.SEVERE, "Group Unable to handle Input of type {0}",
            input.getClass().getCanonicalName());
  }

  /**
   * Same as above, but used to handle ArrayLists
   * @param input
   */
  @Override
  public final void enqueueInput(ArrayList<Input> input)
  {
    for (Input in : input)
      enqueueInput(in);
  }

  /**
   * Function called at the very end of the simulation
   */
  @Override
  public void onSimulationComplete()
  {
    // Nothing to see here. Move along, citizen!
  }

  /**
   * Called when the group has been activated, and when both the {@link
   * GroupDataModel data model} and the {@link PublicEnvironmentConnection
   * environment connection} have been initialised
   * @see #getDataModel()
   * @see #getConn()
   */
  abstract protected void onActivate();

  /**
   * Allows the group to process and respond to a join request
   * @param playerID The player wishing to join
   * @return Whether the group wishes to let them join
   */
  abstract protected boolean respondToJoinRequest(String playerID);

  /**
   * Procedure to assign members to different teams, and get them to hunt food.
   * The list of different foods can be found using the {@link #getConn()
   * environment connection}, and the list of current group members can be
   * found in the {@link GroupDataModel dataModel} which can be accessed with
   * {@link #getInternalDataModel() }
   * @return A map of all hunting teams, and the food they should be ordered to
   * hunt
   */
  abstract protected List<HuntingTeam> selectTeams();

  /**
   * Function that is called after a member leaves the group.
   * The member will not appear in the member list
   * Remember to check if the leader has left and the implications of that
   * @param playerID The id of the leaving playing
   * @param reason The reason that the player left the group
   */
  abstract protected void onMemberLeave(String playerID,
          LeaveNotification.Reasons reason);

  abstract protected Tuple<AgentType, Double> makePayments();

  abstract protected AgentType decideGroupStrategy();

  abstract protected Tuple<Double, Double> updateTaxedPool(double sharedFood);

  abstract protected Tuple<InteractionResult, Double> interactWithOtherGroups();

  /**
   * Here you implement any code concerning data storage about the events
   * of this round before it is all deleted for a new round to begin.
   * N.B: a "round" occurs after all {@link TurnType turn types} have been
   * iterated through. This
   * is to avoid confusion between "cycles", "turn" and "time".
   * Alternatively, use of the unit "Harcourt" may also be used.
   * 1 Round = 1 Harcourt
   */
  abstract protected void beforeNewRound();

  /**
   * @return the conn
   */
  protected PublicEnvironmentConnection getConn()
  {
    return conn;
  }

  /**
   * Get the next random number in the sequence as a double uniformly
   * distributed between 0 and 1
   * @return Next random number
   */
  protected final double uniformRand()
  {
    return this.dm.random.nextDouble();
  }

  /**
   * Get the next random number in the sequence as a double uniformly
   * distributed between 0 and 1
   * @return Next random number
   */
  protected final long uniformRandLong()
  {
    return this.dm.random.nextLong();
  }
}
TOP

Related Classes of ise.mace.participants.AbstractGroupAgent

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.