/** * If rc finds a zombie den, it signals out to surrounding robots If rc has no weapon delay, * attacks in the following priority: 1) adjacent robots (if robot is a bigzombie or standard * zombie move away every other turn to kite it) 2) big zombies 3) nearest enemy * * @param rc RobotController which will attack * @param RobotController * @throws GameActionException * @return true if this robot attacked else false */ private static void attackFirst(RobotController rc) throws GameActionException { boolean equalHealth = true; int lowestHealthIndex = -1; int lowestDistanceIndex = -1; int attackIndex = -1; RobotInfo[] enemies = rc.senseHostileRobots(rc.getLocation(), rc.getType().attackRadiusSquared); if (rc.isWeaponReady() && enemies.length > 0) { for (int i = 0; i < enemies.length; i++) { if (enemies[i].type == RobotType.ZOMBIEDEN) { rc.broadcastSignal(rc.getType().sensorRadiusSquared * 2); } if (attackIndex < 0 && (rc.getLocation()).isAdjacentTo(enemies[i].location)) { attackIndex = i; // TODO test this part - work on kiting if ((enemies[i].type == RobotType.BIGZOMBIE || enemies[i].type == RobotType.STANDARDZOMBIE) && rc.getRoundNum() % 2 == 0 && rc.isCoreReady()) { moveAwayFromEnemy(rc, rc.getLocation().directionTo(enemies[i].location)); } if (rc.isWeaponReady()) { rc.attackLocation(enemies[i].location); } } if (rc.isWeaponReady() && enemies[i].type == RobotType.BIGZOMBIE) { attackIndex = i; rc.attackLocation(enemies[i].location); } if (attackIndex < 0) { lowestHealthIndex = lowestHealthIndex < 0 ? 0 : lowestHealthIndex; lowestDistanceIndex = lowestDistanceIndex < 0 ? 0 : lowestDistanceIndex; equalHealth = equalHealth && enemies[i].health == enemies[lowestHealthIndex].health; lowestDistanceIndex = rc.getLocation().distanceSquaredTo(enemies[i].location) < rc.getLocation().distanceSquaredTo(enemies[lowestDistanceIndex].location) ? i : lowestDistanceIndex; lowestHealthIndex = enemies[i].health < enemies[lowestHealthIndex].health ? i : lowestHealthIndex; } } if (attackIndex < 0 && enemies.length > 0) { attackIndex = equalHealth ? lowestDistanceIndex : lowestHealthIndex; } if (attackIndex >= 0 && rc.isWeaponReady()) { rc.attackLocation(enemies[attackIndex].location); } } }
private static void broadcastingAttack(RobotController rc, RobotInfo enemy) throws GameActionException { if (enemy.health <= RobotType.SOLDIER.attackPower) { if (enemy.type == RobotType.ZOMBIEDEN) { rc.attackLocation(enemy.location); Message.sendBasicGivenRange(rc, Message.FULL_MAP_RANGE); denLocations.remove(enemy.location); nearestDenLocation = denLocations.getClosest(myLoc); } else { rc.attackLocation(enemy.location); } } else { rc.attackLocation(enemy.location); } }
private static void archonMicro(RobotController rc, RobotInfo enemyArchon) throws GameActionException { if (rc.isCoreReady()) { int dist = myLoc.distanceSquaredTo(enemyArchon.location); // When not adjacent to the archon, walk/mine through to him. if (dist > 2) { Direction desired = myLoc.directionTo(enemyArchon.location); Direction dir = Movement.getBestMoveableDirection(desired, rc, 2); 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()); } } // When adjacent to archon, rotate to the left/right when possible. else { Direction dir = myLoc.directionTo(enemyArchon.location); if (rc.canMove(dir.rotateLeft())) { rc.move(dir.rotateLeft()); } else if (rc.canMove(dir.rotateRight())) { rc.move(dir.rotateRight()); } } } if (rc.isWeaponReady()) { if (rc.canAttackLocation(enemyArchon.location)) { rc.attackLocation(enemyArchon.location); } } }
/** * Attack a robot from infos. Assumed to have delay. * * @param rc * @param infos * @return true if attacked */ static boolean attack(RobotController rc, RobotInfo[] infos) throws GameActionException { if (Common.robotType == RobotType.VIPER) return Viper.attack(rc, infos); // TODO: better selection for (RobotInfo info : infos) { if (rc.canAttackLocation(info.location)) { rc.attackLocation(info.location); return true; } } return false; }
private static void turretAttack(RobotController rc) throws GameActionException { if (rc.isWeaponReady()) { // can't attack if enemy is too close so attackFirst throws errors RobotInfo[] enemies = rc.senseHostileRobots(rc.getLocation(), rc.getType().attackRadiusSquared); for (RobotInfo enemy : enemies) { if (rc.canAttackLocation(enemy.location) && rc.isWeaponReady()) { rc.attackLocation(enemy.location); } } } }
static boolean attack(RobotController rc, RobotInfo[] infos) throws GameActionException { RobotInfo best = null; double points = -Common.MAX_ID; for (RobotInfo info : infos) { double newPoints = 300 - info.health; newPoints /= Math.max(3, Math.max(info.viperInfectedTurns, info.zombieInfectedTurns)); if (newPoints > points) { best = info; points = newPoints; } } if (best != null) { if (rc.canAttackLocation(best.location)) { rc.attackLocation(best.location); return true; } } return false; }
/** * Message-processing for non-archons Currently handles messages: Change of mode Setting * turtle-corner location * * @param rc * @throws GameActionException */ private static void processFighterSignals(RobotController rc) throws GameActionException { int cornerX = Integer.MIN_VALUE; int cornerY = Integer.MIN_VALUE; RobotType type = rc.getType(); Signal[] signals = rc.emptySignalQueue(); for (Signal s : signals) { if (s.getTeam().equals(myTeam) && s.getMessage() != null) { final int[] message = s.getMessage(); if (message[0] == SENDING_MODE) { currentMode = message[1]; } else if (message[0] == SENDING_TURTLE_X) { cornerX = message[1]; } else if (message[0] == SENDING_TURTLE_Y) { cornerY = message[1]; } } // when a soldier finds a zombie den, it signals. Other soldiers that receive // the message then should move toward the den to help kill it. Ideally, // this should make it easier to remove zombie dens near the turtle corner if (type == RobotType.SOLDIER && s.getTeam().equals(myTeam) && s.getMessage() == null) { if (rc.getLocation().distanceSquaredTo(s.getLocation()) < rc.getType().sensorRadiusSquared * 2.5 && rc.isCoreReady()) { moveTowards(rc, rc.getLocation().directionTo(s.getLocation())); } } // for turrets to attack broadcasting enemies outside of sight range if (type == RobotType.TURRET && !s.getTeam().equals(myTeam) && rc.isWeaponReady() && rc.canAttackLocation(s.getLocation())) { rc.attackLocation(s.getLocation()); } } if (cornerX > Integer.MIN_VALUE && cornerY > Integer.MIN_VALUE) { turtleCorner = new MapLocation(cornerX, cornerY); } }
// This method will attack the weakest enemy in sight static boolean attackWeakest() { RobotInfo[] targets = rc.senseNearbyRobots(attackRange, enemyTeam); if (targets.length == 0) return false; // Find enemy with lowest health - pick units that can damage us as a preference RobotInfo weakest = targets[0]; for (RobotInfo e : targets) { if ((!canDamage(weakest.type) && canDamage(e.type)) || (canDamage(weakest.type) == canDamage(e.type) && e.health < weakest.health)) { weakest = e; } } try { rc.attackLocation(weakest.location); } catch (GameActionException e) { System.out.println("Attack exception"); // e.printStackTrace(); } return true; }
public void run(final RobotController robotController) throws GameActionException { final MapInfoModule mapInfoModule = new MapInfoModule(); final CombatModule combatModule = new CombatModule(); final CommunicationModule communicationModule = new CommunicationModule(mapInfoModule); final DirectionModule directionModule = new DirectionModule(robotController.getID()); final MovementModule movementModule = new MovementModule(); final RubbleModule rubbleModule = new RubbleModule(); final Team currentTeam = robotController.getTeam(); int turnsStuck = 0; while (true) { RobotType type = robotController.getType(); MapLocation currentLocation = robotController.getLocation(); // update communication communicationModule.processIncomingSignals(robotController); // let's verify existing information communicationModule.verifyCommunicationsInformation(robotController, null, false); if (type == RobotType.TTM) { // MOVE // let's get the best assignment CommunicationModuleSignal objectiveSignal = null; int closestObjectiveLocationDistance = Integer.MAX_VALUE; final Enumeration<CommunicationModuleSignal> zombieDenCommunicationModuleSignals = communicationModule.zombieDens.elements(); while (zombieDenCommunicationModuleSignals.hasMoreElements()) { final CommunicationModuleSignal signal = zombieDenCommunicationModuleSignals.nextElement(); final int distance = signal.location.distanceSquaredTo(currentLocation); if (distance < closestObjectiveLocationDistance) { objectiveSignal = signal; closestObjectiveLocationDistance = distance; } } final Enumeration<CommunicationModuleSignal> enemyArchonCommunicationModuleSignals = communicationModule.enemyArchons.elements(); while (enemyArchonCommunicationModuleSignals.hasMoreElements()) { final CommunicationModuleSignal signal = enemyArchonCommunicationModuleSignals.nextElement(); final int distance = signal.location.distanceSquaredTo(currentLocation) * 6; // multiplying by 6 to prioritize the dens if (distance < closestObjectiveLocationDistance) { objectiveSignal = signal; closestObjectiveLocationDistance = distance; } } final Enumeration<CommunicationModuleSignal> enemyTurretCommunicationModuleSignals = communicationModule.enemyTurrets.elements(); while (enemyTurretCommunicationModuleSignals.hasMoreElements()) { final CommunicationModuleSignal signal = enemyTurretCommunicationModuleSignals.nextElement(); final int distance = signal.location.distanceSquaredTo(currentLocation) * 20; if (distance < closestObjectiveLocationDistance) { objectiveSignal = signal; closestObjectiveLocationDistance = distance; } } boolean shouldMove = true; Direction desiredMovementDirection = null; Direction targetRubbleClearanceDirection = null; // check to make sure we are safe final RobotInfo[] enemies = robotController.senseHostileRobots( currentLocation, robotController.getType().sensorRadiusSquared); if (robotController.isCoreReady() && enemies.length > 0) { final Direction fleeDirection = directionModule.averageDirectionTowardDangerousRobotsAndOuterBounds( robotController, enemies); if (fleeDirection != null) { final Direction fleeMovementDirection = directionModule.recommendedMovementDirectionForDirection( fleeDirection.opposite(), robotController, false); if (fleeMovementDirection != null) { robotController.move(fleeMovementDirection); currentLocation = robotController.getLocation(); robotController.setIndicatorString( 1, fleeDirection.name() + " " + fleeMovementDirection.name()); } } } // check if there are nearby signals if (desiredMovementDirection == null) { int closestSignalDistance = Integer.MAX_VALUE; MapLocation closestSignalLocation = null; final ArrayList<Signal> notifications = communicationModule.notifications; for (int i = 0; i < notifications.size(); i++) { final Signal signal = notifications.get(i); final int distance = currentLocation.distanceSquaredTo(signal.getLocation()); if (distance < closestSignalDistance) { closestSignalDistance = distance; closestSignalLocation = signal.getLocation(); } } if (closestSignalLocation != null) { desiredMovementDirection = currentLocation.directionTo(closestSignalLocation); } } // now let's try move toward an assignment if (robotController.isCoreReady() && communicationModule.initialInformationReceived && shouldMove) { // check if we have an objective if (desiredMovementDirection == null) { if (objectiveSignal != null) { final MapLocation objectiveLocation = objectiveSignal.location; if (objectiveLocation.distanceSquaredTo(currentLocation) >= 8) { desiredMovementDirection = currentLocation.directionTo(objectiveLocation); } } } // try move towards archon starting positions if (desiredMovementDirection == null) { int closestArchonDistance = Integer.MAX_VALUE; MapLocation closestArchonLocation = null; final MapLocation[] archonLocations = robotController.getInitialArchonLocations(robotController.getTeam().opponent()); for (int i = 0; i < archonLocations.length; i++) { final MapLocation location = archonLocations[i]; final int distance = currentLocation.distanceSquaredTo(location); if (distance < closestArchonDistance) { closestArchonDistance = distance; closestArchonLocation = location; } } if (closestArchonLocation != null) { desiredMovementDirection = currentLocation.directionTo(closestArchonLocation); } } // process movement if (desiredMovementDirection != null) { final Direction recommendedMovementDirection = directionModule.recommendedMovementDirectionForDirection( desiredMovementDirection, robotController, false); final MapLocation recommendedMovementLocation = recommendedMovementDirection != null ? currentLocation.add(recommendedMovementDirection) : null; if (recommendedMovementDirection != null && !movementModule.isMovementLocationRepetitive( recommendedMovementLocation, robotController)) { robotController.move(recommendedMovementDirection); movementModule.addMovementLocation(recommendedMovementLocation, robotController); currentLocation = robotController.getLocation(); turnsStuck = 0; } } } // unpack if we're safe RobotInfo[] nearbyTeammates = robotController.senseNearbyRobots(8, currentTeam); RobotInfo[] nearbySoldiers = combatModule.robotsOfTypesFromRobots( nearbyTeammates, new RobotType[] {RobotType.SOLDIER}); if (nearbySoldiers.length > 2) { robotController.unpack(); } } else { // ATTACK final RobotInfo[] enemies = robotController.senseHostileRobots( currentLocation, robotController.getType().attackRadiusSquared); RobotInfo bestEnemy = this.getBestEnemyToAttackFromEnemies(robotController, enemies); // handle attacking if (bestEnemy != null) { if (robotController.isWeaponReady()) { // we can attack the enemy robotController.attackLocation(bestEnemy.location); if (bestEnemy.type != RobotType.ZOMBIEDEN) { communicationModule.broadcastSignal( robotController, CommunicationModule.maximumFreeBroadcastRangeForRobotType( robotController.getType())); } } } // pack if we aren't near soldiers RobotInfo[] nearbyTeammates = robotController.senseNearbyRobots(type.sensorRadiusSquared, currentTeam); RobotInfo[] nearbySoldiers = combatModule.robotsOfTypesFromRobots( nearbyTeammates, new RobotType[] {RobotType.SOLDIER}); if (nearbySoldiers.length < 3) { robotController.pack(); } } Clock.yield(); } }
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(); } } }
/** * run() is the method that is called when a robot is instantiated in the Battlecode world. If * this method returns, the robot dies! */ @SuppressWarnings("unused") public static void run(RobotController rc) { // You can instantiate variables here. Direction[] directions = { Direction.NORTH, Direction.NORTH_EAST, Direction.EAST, Direction.SOUTH_EAST, Direction.SOUTH, Direction.SOUTH_WEST, Direction.WEST, Direction.NORTH_WEST }; RobotType[] robotTypes = { RobotType.SCOUT, RobotType.SOLDIER, RobotType.SOLDIER, RobotType.SOLDIER, RobotType.GUARD, RobotType.GUARD, RobotType.VIPER, RobotType.TURRET }; Random rand = new Random(rc.getID()); int myAttackRange = 0; Team myTeam = rc.getTeam(); Team enemyTeam = myTeam.opponent(); if (rc.getType() == RobotType.ARCHON) { try { // Any code here gets executed exactly once at the beginning of the game. } catch (Exception e) { // Throwing an uncaught exception makes the robot die, so we need to catch exceptions. // Caught exceptions will result in a bytecode penalty. System.out.println(e.getMessage()); e.printStackTrace(); } while (true) { /* // This is a loop to prevent the run() method from returning. Because of the Clock.yield() // at the end of it, the loop will iterate once per game round. try { int fate = rand.nextInt(1000); // Check if this ARCHON's core is ready if (fate % 10 == 2) { // Send a message signal containing the data (6370, 6147) rc.broadcastMessageSignal(6370, 6147, 80); } Signal[] signals = rc.emptySignalQueue(); if (signals.length > 0) { // Set an indicator string that can be viewed in the client rc.setIndicatorString(0, "I received a signal this turn!"); } else { rc.setIndicatorString(0, "I don't any signal buddies"); } if (rc.isCoreReady()) { if (fate < 800) { // Choose a random direction to try to move in Direction dirToMove = directions[fate % 8]; // Check the rubble in that direction if (rc.senseRubble(rc.getLocation().add(dirToMove)) >= GameConstants.RUBBLE_OBSTRUCTION_THRESH) { // Too much rubble, so I should clear it rc.clearRubble(dirToMove); // Check if I can move in this direction } else if (rc.canMove(dirToMove)) { // Move rc.move(dirToMove); } } else { // Choose a random unit to build RobotType typeToBuild = robotTypes[fate % 8]; // Check for sufficient parts if (rc.hasBuildRequirements(typeToBuild)) { // Choose a random direction to try to build in Direction dirToBuild = directions[rand.nextInt(8)]; for (int i = 0; i < 8; i++) { // If possible, build in this direction if (rc.canBuild(dirToBuild, typeToBuild)) { rc.build(dirToBuild, typeToBuild); break; } else { // Rotate the direction to try dirToBuild = dirToBuild.rotateLeft(); } } } } } Clock.yield(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } */ } } else if (rc.getType() != RobotType.TURRET) { try { // Any code here gets executed exactly once at the beginning of the game. myAttackRange = rc.getType().attackRadiusSquared; } catch (Exception e) { // Throwing an uncaught exception makes the robot die, so we need to catch exceptions. // Caught exceptions will result in a bytecode penalty. System.out.println(e.getMessage()); e.printStackTrace(); } while (true) { // This is a loop to prevent the run() method from returning. Because of the Clock.yield() // at the end of it, the loop will iterate once per game round. try { int fate = rand.nextInt(1000); if (fate % 5 == 3) { // Send a normal signal rc.broadcastSignal(80); } boolean shouldAttack = false; // If this robot type can attack, check for enemies within range and attack one if (myAttackRange > 0) { RobotInfo[] enemiesWithinRange = rc.senseNearbyRobots(myAttackRange, enemyTeam); RobotInfo[] zombiesWithinRange = rc.senseNearbyRobots(myAttackRange, Team.ZOMBIE); if (enemiesWithinRange.length > 0) { shouldAttack = true; // Check if weapon is ready if (rc.isWeaponReady()) { rc.attackLocation( enemiesWithinRange[rand.nextInt(enemiesWithinRange.length)].location); } } else if (zombiesWithinRange.length > 0) { shouldAttack = true; // Check if weapon is ready if (rc.isWeaponReady()) { rc.attackLocation( zombiesWithinRange[rand.nextInt(zombiesWithinRange.length)].location); } } } if (!shouldAttack) { if (rc.isCoreReady()) { if (fate < 600) { // Choose a random direction to try to move in Direction dirToMove = directions[fate % 8]; // Check the rubble in that direction if (rc.senseRubble(rc.getLocation().add(dirToMove)) >= GameConstants.RUBBLE_OBSTRUCTION_THRESH) { // Too much rubble, so I should clear it rc.clearRubble(dirToMove); // Check if I can move in this direction } else if (rc.canMove(dirToMove)) { // Move rc.move(dirToMove); } } } } Clock.yield(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } } else if (rc.getType() == RobotType.TURRET) { try { myAttackRange = rc.getType().attackRadiusSquared; } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } while (true) { // This is a loop to prevent the run() method from returning. Because of the Clock.yield() // at the end of it, the loop will iterate once per game round. try { // If this robot type can attack, check for enemies within range and attack one if (rc.isWeaponReady()) { RobotInfo[] enemiesWithinRange = rc.senseNearbyRobots(myAttackRange, enemyTeam); RobotInfo[] zombiesWithinRange = rc.senseNearbyRobots(myAttackRange, Team.ZOMBIE); if (enemiesWithinRange.length > 0) { for (RobotInfo enemy : enemiesWithinRange) { // Check whether the enemy is in a valid attack range (turrets have a minimum range) if (rc.canAttackLocation(enemy.location)) { rc.attackLocation(enemy.location); break; } } } else if (zombiesWithinRange.length > 0) { for (RobotInfo zombie : zombiesWithinRange) { if (rc.canAttackLocation(zombie.location)) { rc.attackLocation(zombie.location); break; } } } } Clock.yield(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } } }
// HQ is responsible for collating unit counts and broadcasting them each turn // It also needs to pass on its supply each turn and fire if there are enemies in range private static void runHQ() { // double lastOre = 500; strategy = new BuildStrategy(rc); while (true) { threats.update(); strategy.broadcast(); // double oreIncome = rc.getTeamOre() - lastOre + strategy.oreSpent(); // System.out.println("Ore income " + oreIncome + " per miner = " + (oreIncome-5) / // (strategy.units(RobotType.MINER) + strategy.units(RobotType.BEAVER))); // See if we need to spawn a beaver if (rc.isCoreReady()) { RobotType build = strategy.getBuildOrder(); if (build != null) { trySpawn(rc.getLocation().directionTo(threats.enemyHQ), build); } } // Attack if there is an enemy in sight if (rc.isWeaponReady()) { int senseRange = RobotType.HQ.attackRadiusSquared; MapLocation[] myTowers = rc.senseTowerLocations(); if (myTowers.length >= 5) { senseRange = 52; // This is slightly larger than the real range but does include all possible // enemies that can be hit with splash attackRange = GameConstants.HQ_BUFFED_ATTACK_RADIUS_SQUARED; } else if (myTowers.length >= 2) { attackRange = GameConstants.HQ_BUFFED_ATTACK_RADIUS_SQUARED; } else { attackRange = senseRange; } RobotInfo[] enemies = rc.senseNearbyRobots(senseRange, enemyTeam); // Pick the first valid target MapLocation best = null; for (RobotInfo e : enemies) { int range = e.location.distanceSquaredTo(myLoc); if (range <= attackRange) { best = e.location; break; } if (myTowers.length >= 5) { // Check for tiles adjacent to the enemy as they might be in splash range Direction d = e.location.directionTo(myLoc); if (e.location.add(d).distanceSquaredTo(myLoc) <= attackRange) { best = e.location.add(d); break; } if (e.location.add(d.rotateLeft()).distanceSquaredTo(myLoc) <= attackRange) { best = e.location.add(d.rotateLeft()); break; } if (e.location.add(d.rotateRight()).distanceSquaredTo(myLoc) <= attackRange) { best = e.location.add(d.rotateRight()); break; } } } if (best != null) { try { rc.attackLocation(best); } catch (GameActionException e) { System.out.println("HQ attack exception"); // e.printStackTrace(); } } } doTransfer(); // lastOre = rc.getTeamOre(); rc.yield(); } }