private static void moveSoldier(RobotController rc) throws GameActionException {
   // if we have a real current destination
   rc.setIndicatorString(1, "moving somewhere " + currentDestination + rc.getRoundNum());
   if (currentDestination != null) {
     // if bugging is never initialized or we are switching destinations, reinitialize bugging
     if (!currentDestination.equals(storedDestination) || bugging == null) {
       bugging = new Bugging(rc, currentDestination);
       storedDestination = currentDestination;
     }
     // if we are trying to move towards a turret, stay out of range
     if (rc.isCoreReady()) {
       if (currentDestination.equals(nearestTurretLocation)) {
         bugging.turretAvoidMove(turretLocations);
       } else
       // if core is ready, then try to move towards destination
       if (nearestTurretLocation != null) {
         bugging.turretAvoidMove(turretLocations);
       } else {
         bugging.move();
       }
     }
   } else if (nearestArchonLocation
       != null) { // we don't actually have a destination, so we want to try to move towards the
                  // closest archon
     rc.setIndicatorString(
         0, "moving to nearest archon " + nearestArchonLocation + rc.getRoundNum());
     if (!nearestArchonLocation.equals(storedDestination)) {
       bugging = new Bugging(rc, nearestArchonLocation);
       storedDestination = nearestArchonLocation;
     }
     // if core is ready, try to move
     if (rc.isCoreReady() && bugging != null) {
       if (nearestTurretLocation != null) {
         bugging.turretAvoidMove(turretLocations);
       } else if (nearestArchonLocation.equals(bugging.destination)
           && myLoc.distanceSquaredTo(nearestArchonLocation)
               > 13) { // if soldier is far, move towards archon
         bugging.move();
       } else if (nearestArchonLocation.equals(bugging.destination)
           && myLoc.distanceSquaredTo(nearestArchonLocation)
               < 13) { // if soldier is too close, move towards archon
         // try to move away from nearest archon
         if (rc.canMove(nearestArchonLocation.directionTo(myLoc))) {
           rc.move(nearestArchonLocation.directionTo(myLoc));
         }
       }
     }
   } else { // if we literally have nowhere to go
     rc.setIndicatorString(1, "bugging around friendly " + rc.getRoundNum());
     bugAroundFriendly(rc);
   }
 }
 public static void bugAroundFriendly(RobotController rc) throws GameActionException {
   RobotInfo[] nearbyFriendlyRobots = rc.senseNearbyRobots(sightRadius, myTeam);
   if (nearbyFriendlyRobots.length > 0) {
     RobotInfo nearestFriend = null;
     for (RobotInfo r : nearbyFriendlyRobots) {
       if (r.type == RobotType.ARCHON) {
         nearestFriend = r;
       }
     }
     if (nearestFriend != null && !nearestFriend.location.equals(storedDestination)
         || bugging == null) {
       bugging = new Bugging(rc, nearestFriend.location);
       storedDestination = nearestFriend.location;
     }
     if (rc.isCoreReady()) { // don't want to get too close to archon
       bugging.move();
     }
   }
 }
  public static void zombieMicro(RobotController rc) throws GameActionException {
    boolean thereIsNonKitableZombie = false;
    RobotInfo closestEnemy = null;
    int closestDist = 10000;
    for (RobotInfo hostile : nearbyEnemies) {
      if (hostile.type == RobotType.FASTZOMBIE || hostile.type == RobotType.RANGEDZOMBIE) {
        thereIsNonKitableZombie = true;
      }
      int dist = myLoc.distanceSquaredTo(hostile.location);
      if (dist < closestDist) {
        closestDist = dist;
        closestEnemy = hostile;
      }
    }

    Direction d = myLoc.directionTo(closestEnemy.location);
    // if we're too close, move further away
    if (myLoc.distanceSquaredTo(closestEnemy.location) < 5 && rc.isCoreReady()) {
      Direction desired = d.opposite();
      Direction dir = Movement.getBestMoveableDirection(desired, rc, 1);
      if (dir != Direction.NONE) {
        rc.move(dir);
      } else if (shouldMine(rc, desired)) {
        rc.clearRubble(desired);
      } else if (shouldMine(rc, desired.rotateLeft())) {
        rc.clearRubble(desired.rotateLeft());
      } else if (shouldMine(rc, desired.rotateRight())) {
        rc.clearRubble(desired.rotateRight());
      }
    }
    if (!thereIsNonKitableZombie) {
      // Only move in closer if there is no non-kitable zombie
      if (myLoc.distanceSquaredTo(closestEnemy.location) > attackRadius
          && rc.isCoreReady()) { // if we are too far, we want to move closer
        // Desired direction is d.
        Direction dir = Movement.getBestMoveableDirection(d, rc, 1);
        if (dir != Direction.NONE) {
          rc.move(dir);
        } else if (shouldMine(rc, d)) {
          rc.clearRubble(d);
        } else if (shouldMine(rc, d.rotateLeft())) {
          rc.clearRubble(d.rotateLeft());
        } else if (shouldMine(rc, d.rotateRight())) {
          rc.clearRubble(d.rotateRight());
        } else { // probably meaning you are blocked by allies
          if (closestEnemy.type == RobotType.ZOMBIEDEN) {
            // It is likely that we wanted to go to that den, but possibly coincidence
            // If not a coincidence, bug there.
            if (bugging != null) {
              if (bugging.destination.equals(closestEnemy.location)) {
                bugging.turretAvoidMove(turretLocations);
                // If coincidence, set new bugging.
              } else {
                bugging = new Bugging(rc, closestEnemy.location);
                bugging.turretAvoidMove(turretLocations);
              }
            } else {
              bugging = new Bugging(rc, closestEnemy.location);
              bugging.turretAvoidMove(turretLocations);
            }
          }
        }
      }
    }
    if (rc.isWeaponReady() && rc.canAttackLocation(closestEnemy.location)) {
      broadcastingAttack(rc, closestEnemy);
    }
  }
  public static void run(RobotController rc) {
    sightRadius = RobotType.SOLDIER.sensorRadiusSquared;
    attackRadius = RobotType.SOLDIER.attackRadiusSquared;
    myTeam = rc.getTeam();
    enemyTeam = myTeam.opponent();
    while (true) {
      try {
        numEnemySoldiers = 0;
        totalEnemySoldierHealth = 0;
        myLoc = rc.getLocation();
        nearbyAllies = rc.senseNearbyRobots(sightRadius, myTeam);
        nearbyEnemies = rc.senseHostileRobots(myLoc, sightRadius);
        newArchonLoc = null;

        // clear bad locations
        resetLocations(rc);
        // read messages and get destination
        readMessages(rc);
        // heal if need (and set the archon destination to go to)
        setRetreatingStatus(rc, nearbyEnemies);

        // Remove turret locations that you can see are not there.
        // Does NOT remove turret locations due to broadcasts. Already done in read messages.
        removeTurretLocations(rc);

        if (newArchonLoc != null) {
          nearestArchonLocation = newArchonLoc;
        }

        rc.setIndicatorString(2, "Round: " + rc.getRoundNum() + ", rushing: " + rush);
        // Reset rushing if turns since rush is > 20 and see no more enemies.
        if (rush && myLoc.distanceSquaredTo(rushLocation) <= 100) turnsSinceRush++;
        if (turnsSinceRush > 20) {
          if (rc.senseNearbyRobots(sightRadius, enemyTeam).length == 0) {
            turnsSinceRush = 0;
            rush = false;
          }
        }

        // When rushing, be mad aggressive.
        if (rush) {
          rushMicro(rc, nearbyEnemies);
        }
        // When retreating, retreat
        else if (healing) {
          if (rc.isCoreReady()) {
            if (nearestArchonLocation != null) {
              if (myLoc.distanceSquaredTo(nearestArchonLocation) > 13) {
                bugging.enemyAvoidMove(nearbyEnemies);
                // Get away from archons that are not too close together.
              } else if (myLoc.distanceSquaredTo(nearestArchonLocation) <= 2) {
                Direction radialDir = nearestArchonLocation.directionTo(myLoc);
                Direction awayDir = Movement.getBestMoveableDirection(radialDir, rc, 2);
                if (awayDir != Direction.NONE) {
                  rc.move(awayDir);
                }
              }
            }
          }
          // Make sure to attack people even when retreating.
          // Prioritize the closest enemy. Then the closest zombie.
          if (rc.isWeaponReady()) {
            // Attack the closest enemy. If there is not one, then attack the closest zombie
            int closestDist = 10000;
            RobotInfo target = null;
            for (RobotInfo hostile : nearbyEnemies) {
              int dist = myLoc.distanceSquaredTo(hostile.location);
              if (rc.canAttackLocation(hostile.location)) {
                // There is already is a target
                if (target != null) {
                  if (target.team == enemyTeam) {
                    // Target is already enemy, so prioritize the closest
                    if (hostile.team == enemyTeam) {
                      if (dist < closestDist) {
                        target = hostile;
                        closestDist = dist;
                      }
                    } // If hostile is not an enemy, not worth considering.
                  } else {
                    // Target is not on enemy team, so hostile is best choice!
                    if (hostile.team == enemyTeam) {
                      target = hostile;
                      closestDist = dist;
                      // Both are zombies, so just pick the closest.
                    } else {
                      if (dist < closestDist) {
                        target = hostile;
                        closestDist = dist;
                      }
                    }
                  }
                  // Set a target when there is not one.
                } else {
                  target = hostile;
                  closestDist = dist;
                }
              }
            }
            // We know that if there is a target, we can attack it.
            if (target != null) {
              rc.attackLocation(target.location);
            }
          }
        }

        // When viper infected and will die from the infection, do special micro
        else if (isViperInfected(rc)
            && (rc.getHealth() < rc.getViperInfectedTurns() * 2 || rc.getRoundNum() > 2100)) {
          viperInfectedMicro(rc);
        }

        // if there are enemies in range, we should focus on attack and micro
        else if (nearbyEnemies.length > 0) {
          if (shouldLure(rc, nearbyEnemies, nearbyAllies)) luringMicro(rc);
          else micro(rc);
        } else { // otherwise, we should always be moving somewhere
          moveSoldier(rc);
        }

        Clock.yield();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
  private static void luringMicro(RobotController rc) throws GameActionException {
    boolean thereIsNonKitableZombie = false;
    RobotInfo closestEnemy = null;
    MapLocation closestOpponent = null;
    int closestDist = 10000;
    for (RobotInfo hostile : nearbyEnemies) {
      if (hostile.type == RobotType.FASTZOMBIE || hostile.type == RobotType.RANGEDZOMBIE) {
        thereIsNonKitableZombie = true;
      }
      int dist = myLoc.distanceSquaredTo(hostile.location);
      if (dist < closestDist) {
        closestDist = dist;
        closestEnemy = hostile;
      }
    }

    // try to get the closest place to lure zombie
    for (MapLocation loc : turretLocations) {
      if (closestOpponent == null) closestOpponent = loc;
      else if (myLoc.distanceSquaredTo(loc) < myLoc.distanceSquaredTo(closestOpponent))
        closestOpponent = null;
    }
    if (closestOpponent == null) closestOpponent = nearestEnemyLocation;
    Direction d = null;
    if (closestOpponent != null) d = myLoc.directionTo(closestOpponent);
    else d = myLoc.directionTo(rc.getInitialArchonLocations(enemyTeam)[0]);

    // if we are moving directly into the zombie, try to move to the side
    Direction temp = myLoc.directionTo(closestEnemy.location);
    if (d.equals(temp)) d = d.rotateLeft().rotateLeft();
    else if (d.equals(temp.rotateLeft())) d = d.rotateLeft();
    else if (d.equals(temp.rotateRight())) d = d.rotateRight();

    // if we're too close, move further away towards the closest turret location or the closest
    // enemy
    if (myLoc.distanceSquaredTo(closestEnemy.location) < 10 && rc.isCoreReady()) {
      Direction desired = d;
      Direction dir = Movement.getBestMoveableDirection(desired, rc, 1);
      if (dir != Direction.NONE) {
        rc.move(dir);
      } else if (shouldMine(rc, desired)) {
        rc.clearRubble(desired);
      } else if (shouldMine(rc, desired.rotateLeft())) {
        rc.clearRubble(desired.rotateLeft());
      } else if (shouldMine(rc, desired.rotateRight())) {
        rc.clearRubble(desired.rotateRight());
      }
    }
    if (!thereIsNonKitableZombie) {
      // Only move in closer if there is no non-kitable zombie
      if (myLoc.distanceSquaredTo(closestEnemy.location) > attackRadius
          && rc.isCoreReady()) { // if we are too far, we want to move closer
        // Desired direction is d.
        Direction dir = Movement.getBestMoveableDirection(d, rc, 1);
        if (dir != Direction.NONE) {
          rc.move(dir);
        } else if (shouldMine(rc, d)) {
          rc.clearRubble(d);
        } else if (shouldMine(rc, d.rotateLeft())) {
          rc.clearRubble(d.rotateLeft());
        } else if (shouldMine(rc, d.rotateRight())) {
          rc.clearRubble(d.rotateRight());
        } else { // probably meaning you are blocked by allies
          if (closestEnemy.type == RobotType.ZOMBIEDEN) {
            // It is likely that we wanted to go to that den, but possibly coincidence
            // If not a coincidence, bug there.
            if (bugging != null) {
              if (bugging.destination.equals(closestEnemy.location)) {
                bugging.turretAvoidMove(turretLocations);
                // If coincidence, set new bugging.
              } else {
                bugging = new Bugging(rc, closestOpponent);
                bugging.turretAvoidMove(turretLocations);
              }
            } else {
              bugging = new Bugging(rc, closestOpponent);
              bugging.turretAvoidMove(turretLocations);
            }
          }
        }
      }
    }
    if (rc.isWeaponReady() && rc.canAttackLocation(closestEnemy.location)) {
      broadcastingAttack(rc, closestEnemy);
    }
  }