Esempio n. 1
0
  /**
   * Returns a list of the enemies with radius squares of your hero
   *
   * @param gameState
   * @param searchResults
   * @param radius
   * @return
   */
  public static List<GameState.Hero> getHeroesAround(
      AdvancedGameState gameState,
      Map<GameState.Position, AdvancedMurderBot.DijkstraResult> searchResults,
      int radius) {
    List<GameState.Hero> heroes = new LinkedList<>();

    for (GameState.Hero currentHero : gameState.getHeroesByPosition().values()) {
      GameState.Position currentHeroPosition = currentHero.getPos();
      if (searchResults.get(currentHeroPosition).getDistance() <= radius
          && currentHero.getId() != gameState.getMe().getId()) heroes.add(currentHero);
    }

    return heroes;
  }
  /**
   * Creates a new AdvancedGameState by taking he previous AdvancedGameState and updating is using a
   * new GameState
   *
   * @param oldGameState
   * @param updatedState
   */
  public AdvancedGameState(AdvancedGameState oldGameState, GameState updatedState) {

    // Copy the stuff we can just re-use
    this.boardGraph = oldGameState.getBoardGraph();
    this.pubs = oldGameState.getPubs();
    this.viewUrl = oldGameState.getViewUrl();
    // Re-build the hero maps
    this.heroesByPosition = new HashMap<>();
    this.heroesById = new HashMap<>();
    for (GameState.Hero currentHero : updatedState.getGame().getHeroes()) {
      this.heroesByPosition.put(currentHero.getPos(), currentHero);
      this.heroesById.put(currentHero.getId(), currentHero);
    }
    this.me = updatedState.getHero();

    // Update the mines
    this.mines = oldGameState.getMines();
    for (Mine currentMine : this.mines.values()) {
      // Vindinium does the x and y coordinates backwards
      int tileStart =
          currentMine.getPosition().getX() * updatedState.getGame().getBoard().getSize() * 2
              + (currentMine.getPosition().getY() * 2);
      // We don't want the whole tile; we want the second char
      String owner =
          updatedState.getGame().getBoard().getTiles().substring(tileStart + 1, tileStart + 1 + 1);
      Mine mine;
      if (owner.equals("-")) {
        mine = new Mine(currentMine.getPosition(), null);
      } else {
        int ownerId = Integer.parseInt(owner);
        mine = new Mine(currentMine.getPosition(), this.heroesById.get(ownerId));
      }

      this.mines.put(mine.getPosition(), mine);
    }
  }
  /**
   * Creates an AdvancedGameState from a GameState
   *
   * @param gameState
   */
  public AdvancedGameState(GameState gameState) {
    boardGraph = new HashMap<>();
    mines = new HashMap<>();
    pubs = new HashMap<>();
    heroesById = new HashMap<>();
    heroesByPosition = new HashMap<>();
    viewUrl = gameState.getViewUrl();

    // Hero stuffs
    for (GameState.Hero currentHero : gameState.getGame().getHeroes()) {
      this.heroesByPosition.put(currentHero.getPos(), currentHero);
      this.heroesById.put(currentHero.getId(), currentHero);
    }

    this.me = gameState.getHero();

    // Build the graph sans edges
    GameState.Board board = gameState.getGame().getBoard();
    for (int row = 0; row < board.getSize(); row++) {
      for (int col = 0; col < board.getSize(); col++) {
        // Yeah, Vindinium does the x and y coordinates backwards
        GameState.Position pos = new GameState.Position(row, col);
        int tileStart = row * board.getSize() * 2 + (col * 2);
        String tileValue = board.getTiles().substring(tileStart, tileStart + 1 + 1);

        // We do nothing with tiles that are barriers
        if (tileValue.equals("##")) {
          continue;
        }

        Vertex v = new Vertex(pos, new LinkedList<Vertex>());

        this.boardGraph.put(pos, v);

        // If its a mine or tavern, we treat it differently
        // We don't care if its a hero because a separate index for those already exists
        if (tileValue.startsWith("$")) {
          String owner = tileValue.substring(1);
          Mine mine;
          if (owner.equals("-")) {
            mine = new Mine(pos, null);
          } else {
            int ownerId = Integer.parseInt(owner);
            mine = new Mine(pos, this.heroesById.get(ownerId));
          }

          this.mines.put(pos, mine);
        } else if (tileValue.equals("[]")) {
          Pub pub = new Pub(pos);
          this.pubs.put(pos, pub);
        }
      }
    }

    // Add in the edges
    // This graph doesn't take into account players because they move.  That is done elsewhere.
    for (Vertex currentVertex : this.boardGraph.values()) {
      GameState.Position currentVertexPosition = currentVertex.getPosition();

      // Pubs and mines cannot be passed through
      if (this.mines.containsKey(currentVertexPosition)
          || this.pubs.containsKey(currentVertexPosition)) {
        continue;
      }

      // Other players cannot be passed through.  However, they move, and mines/pubs don't, so its
      // easier to make
      // the bot and path-finding deal with that.  We don't take other players into account here.
      // We can only move NSEW, so no need for a fancy set of nested loops...
      for (int xDelta = -1; xDelta <= 1; xDelta += 2) {
        int currentX = currentVertex.getPosition().getX();
        int newX = currentX + xDelta;
        if (newX >= 0 && newX < board.getSize()) {
          GameState.Position adjacentPos =
              new GameState.Position(newX, currentVertex.getPosition().getY());
          Vertex adjacentVertex = this.boardGraph.get(adjacentPos);
          if (adjacentVertex != null) {
            currentVertex.getAdjacentVertices().add(adjacentVertex);
          }
        }
      }
      for (int yDelta = -1; yDelta <= 1; yDelta += 2) {
        int currentY = currentVertex.getPosition().getY();
        int newY = currentY + yDelta;
        if (newY >= 0 && newY < board.getSize()) {
          GameState.Position adjacentPos =
              new GameState.Position(currentVertex.getPosition().getX(), newY);
          Vertex adjacentVertex = this.boardGraph.get(adjacentPos);
          if (adjacentVertex != null) {
            currentVertex.getAdjacentVertices().add(adjacentVertex);
          }
        }
      }
    }
  }
  @Override
  public BotMove makeDecision(AdvancedMurderBot.GameContext context) {
    logger.info("Deciding which bot to target");
    GameState.Hero me = context.getGameState().getMe();

    // Are there a crashed bot with mines we can take advantage of?
    //        for(Mine currentMine : context.getGameState().getMines().values()) {
    //            if(currentMine.getOwner() != null && currentMine.getOwner().isCrashed()) {
    //
    //                GameState.Hero target = currentMine.getOwner();
    //                AdvancedMurderBot.DijkstraResult currentDijkstraResult =
    //                        context.getDijkstraResultMap().get(target.getPos());
    //                GameState.Position nextPosition = target.getPos();
    //
    //                while(null != currentDijkstraResult && currentDijkstraResult.getDistance() >
    // 1) {
    //                    nextPosition = currentDijkstraResult.getPrevious();
    //                    currentDijkstraResult = context.getDijkstraResultMap().get(nextPosition);
    //                }
    //
    //                logger.info("Going after a crashed bot");
    //                return BotUtils.directionTowards(currentDijkstraResult.getPrevious(),
    // nextPosition);
    //            }
    //        }

    Set<GameState.Hero> heroesWithMines = new HashSet<>();

    // Which heroes have mines?
    for (Mine currentMine : context.getGameState().getMines().values()) {
      if (currentMine.getOwner() != null) heroesWithMines.add(currentMine.getOwner());
    }

    // Ok, crashed bots.  How about bots that aren't squatting?
    GameState.Hero closestTarget = null;
    AdvancedMurderBot.DijkstraResult closestTargetDijkstraResult = null;
    for (GameState.Hero currentHero : heroesWithMines) {
      AdvancedMurderBot.DijkstraResult currentDijkstraResult =
          context.getDijkstraResultMap().get(currentHero.getPos());

      // We don't want to target bots that we cannot reach
      if (currentDijkstraResult == null) continue;

      // We don't want to target ourselves
      if (currentHero.getId() == context.getGameState().getMe().getId()) continue;

      // We don't want to target other bots of our type
      // TODO We probably shouldn't hardcode this name
      //            if(currentHero.getName().equals("Assassin Bot"))
      //                continue;

      // Are they on their spawn?
      if (currentHero.getPos().equals(currentHero.getSpawnPos())) continue;

      // Does he have more HP than we do?
      if (currentHero.getLife() > 20 && currentHero.getLife() > me.getLife()) continue;

      // Check the adjacent squares to see if a pub exists
      Vertex currentHeroVertext = context.getGameState().getBoardGraph().get(currentHero.getPos());
      for (Vertex currentVertext : currentHeroVertext.getAdjacentVertices()) {
        if (context.getGameState().getPubs().containsKey(currentVertext.getPosition())) {
          continue;
        }
      }

      // Ok, we got this far...it must not be squatting.  Is it closest?
      if (closestTarget == null) {
        closestTarget = currentHero;
        closestTargetDijkstraResult = context.getDijkstraResultMap().get(closestTarget.getPos());
        continue;
      } else if (closestTargetDijkstraResult.getDistance() > currentDijkstraResult.getDistance()) {
        closestTarget = currentHero;
        closestTargetDijkstraResult = context.getDijkstraResultMap().get(closestTarget.getPos());
      }
    }

    if (closestTarget != null) {
      GameState.Position nextMove = closestTarget.getPos();
      while (closestTarget != null && closestTargetDijkstraResult.getDistance() > 1) {
        nextMove = closestTargetDijkstraResult.getPrevious();
        closestTargetDijkstraResult = context.getDijkstraResultMap().get(nextMove);
      }

      logger.info("Going after another bot");
      return BotUtils.directionTowards(closestTargetDijkstraResult.getPrevious(), nextMove);
    }

    // Ok, no one worth attacking.
    logger.info("No bot worth attacking.  Deferring.");
    return noTargetFoundDecisioner.makeDecision(context);
  }