/**
   * Environment's primary execution function
   *
   * <ul>
   *   <li>{@link #processTeamHunts() Processes Team Hunts}
   *   <li>On {@link TurnType#TeamSelect Team Select} turn, calls the {@link AbstractFreeAgentGroup
   *       Free Agent Group} to put all {@link AbstractAgent agents} (who are not in {@link
   *       AbstractGroupAgent groups}) int {@link HuntingTeam teams}
   * </ul>
   */
  @Override
  protected void updatePhysicalWorld() {
    processTeamHunts();

    // Deal with ungrouped agents having teams formed
    if (fAGroup != null && dmodel.getTurnType() == TurnType.TeamSelect) {
      List<HuntingTeam> teams = fAGroup.selectTeams(dmodel.getUngroupedAgents());
      for (HuntingTeam team : teams) {
        for (String agent : team.getMembers()) {
          sim.getPlayer(agent).enqueueInput(new HuntOrder(sim.getTime(), team));
          logger.log(
              Level.FINE,
              "FreeAgentsGroup has created team {0} including {1}",
              new Object[] {team.hashCode(), nameOf(agent)});
        }
      }
    }

    // Energy used on hunting, so this is when food is consumed
    if (dmodel.getTurnType() == TurnType.GoHunt) {
      for (Participant agent : sim.players.values()) {
        if (sim.isParticipantActive(agent.getId())) {
          if (agent instanceof ise.mace.participants.AbstractAgent) {
            agent.enqueueInput(new ConsumeFood(dmodel.getTime()));
          }
        }
      }
    }
  }
  /**
   * Processes the {@link Hunt} actions of {@link AbstractAgent agents} that were hunting as part of
   * {@link HuntingTeam HuntingTeams} whose hunt records were added to {@link #storedHuntResults}
   */
  private void processTeamHunts() {
    for (HuntingTeam team : storedHuntResults.keySet()) {
      // Reorganise each team into what they hunted
      // And who hunted it
      Map<Food, List<String>> hunters = new HashMap<Food, List<String>>();
      for (TeamHuntEvent h : storedHuntResults.get(team)) {
        if (!hunters.containsKey(h.getFood())) {
          hunters.put(h.getFood(), new LinkedList<String>());
        }
        hunters.get(h.getFood()).add(h.getAgent());
      }

      // Now, for each food, see if they got a unit on it
      for (Food f : hunters.keySet()) {
        List<String> agents = hunters.get(f);
        double foodGained;

        int count = 0;
        while ((count + 1) * f.getHuntersRequired() <= agents.size()) {
          ++count;
        }

        foodGained = count * f.getNutrition() / agents.size();

        // Then, for each agent, send the message
        String groupID = dmodel.getAgentById(agents.get(0)).getGroupId();
        if (groupID == null) {
          for (String agent : agents) {
            sim.getPlayer(agent)
                .enqueueInput(new HuntResult(agent, foodGained, foodGained, dmodel.time));
          }
        } else {
          Participant g = sim.getPlayer(groupID);
          for (String agent : agents) {
            g.enqueueInput(new HuntResult(agent, foodGained, 0, dmodel.time));
          }
        }
      }
    }

    storedHuntResults.clear();
  }