@Override
  public Action generateAchievementAction(String focus) {
    myToken.setStrategyType(AgentToken.STRATEGY_ZONE_BUILDER);
    // successfulParries is covered by defaultAction
    if (focus == "achievementsSurveyedEdges") {
      if (myPosition.getNumberOfUnsurveyedEdges() > 0) {
        Action ret = new Action("survey", myPosition.getIdentifier());
        return ret;
      }
    }
    if (focus == "achievementsInspectedAgents") {
      if (longNotInspectedEnemyNear(myPosition)) {
        //                return new Action("inspect", myPosition.getIdentifier());
        LinkedList<AgentToken> agentsToCheck = new LinkedList<AgentToken>();
        agentsToCheck.addAll(myPosition.getTokens());
        for (Vertex w : myPosition.getAdjacentVertices()) agentsToCheck.addAll(w.getTokens());

        for (AgentToken t : agentsToCheck) {
          if (!t.getTeam().equals(myTeam) && notRecentlyInspected(t))
            return new Action("inspect", new Identifier(t.getName()));
        }
      }
    }

    if (focus == "achievementsAreaValue") {
      Action ret = ag.buildZone();
      return ret;
    }
    return ag.expandOwnComponent();
  }
  /**
   * checks for long not inspected enemy at a position and adjacent vertices
   *
   * @param v the vertex to check
   * @return true, if there is at least one long not inspected enemy, else false
   * @see {@link #notRecentlyInspected(AgentToken)}
   */
  private boolean longNotInspectedEnemyNear(Vertex v) {
    // check for uninspected enemy on own position and adjacent vertices
    LinkedList<AgentToken> agentsToCheck = new LinkedList<AgentToken>();
    agentsToCheck.addAll(v.getTokens());
    for (Vertex w : v.getAdjacentVertices()) agentsToCheck.addAll(w.getTokens());

    for (AgentToken t : agentsToCheck) {
      if (!t.getTeam().equals(myTeam) && notRecentlyInspected(t)) return true;
    }
    return false;
  }
  @Override
  public Action generateOffensiveAction(String focus) {
    // focus offensiveDestroyAgent not considered

    if (tactics == TACTIC_followLongNotInspected) {
      myToken.setStrategyType(AgentToken.STRATEGY_ATTACKER);
      if (longNotInspectedEnemyNear(myPosition)) {
        LinkedList<AgentToken> agentsToCheck = new LinkedList<AgentToken>();
        agentsToCheck.addAll(myPosition.getTokens());
        for (Vertex w : myPosition.getAdjacentVertices()) agentsToCheck.addAll(w.getTokens());

        for (AgentToken t : agentsToCheck) {
          if (!t.getTeam().equals(myTeam) && notRecentlyInspected(t))
            return new Action("inspect", new Identifier(t.getName()));
        }
      }
      //                return new Action("inspect", myPosition.getIdentifier());

      LinkedList<Vertex> possibleTargets = new LinkedList<Vertex>();
      for (AgentToken t : graph.getTokens()) {
        if (!t.getTeam().equals(myTeam) && notRecentlyInspected(t))
          possibleTargets.add(t.getPosition());
      }
      if (!possibleTargets.isEmpty()) return ag.moveTowardsNearest(possibleTargets);
    }

    if (focus == "offensiveDestroyZone") {
      myToken.setStrategyType(AgentToken.STRATEGY_ATTACKER);
      tactics = TACTIC_destroyZone;
      Action ret = ag.destroyZone();
      return ret;
    }
    if (focus == "offensiveDrawback") {
      myToken.setStrategyType(AgentToken.STRATEGY_UNKNOWN);
      Zone zone = getZoneManager().getMostPreciousZone();
      if (zone == null) return ag.expandOwnComponent();
      Action ret = ag.moveTowardsNearest(zone.getCriticalFrontier());
      return ret;
    }
    Action ret = ag.expandOwnComponent();
    return ret;
  }
  @Override
  public Action generateDefensiveAction(String focus) {
    myToken.setStrategyType(AgentToken.STRATEGY_UNKNOWN);
    if (focus == "defensiveRepair") {
      LinkedList<Vertex> repairerPosition = new LinkedList<Vertex>();
      for (AgentToken t : graph.getTokens()) {

        if (t.getRole() != null && t.getTeam().equals(myTeam) && t.getRole().equals("Repairer")) {
          if (t.getNextPosition() == null) return new Action("recharge");
          if (t.getNextPosition().equals(myPosition)) return new Action("recharge");
          repairerPosition.add(t.getPosition());
        }
      }
      return ag.moveTowardsNearest(repairerPosition);
    }

    if (focus == "defensiveParry") {
      return new Action("parry");
    }
    // standard action & focus runaway
    Zone zone = getZoneManager().getBiggestZone();
    if (zone != null) return ag.moveTowardsNearest(zone.getCriticalFrontier());
    return new Action("recharge");
  }
 /**
  * @param token related agent token
  * @return true, if token has not been inspected since LAST_INSPECTION_THRESHOLD steps, else false
  */
 private boolean notRecentlyInspected(AgentToken token) {
   return (currentStep - token.getLastInspection() > LAST_INSPECTION_THRESHOLD);
 }