static void init(RobotController rc) { int roundLimit = rc.getRoundLimit(); Common.rc = rc; rand = new Random(rc.getID()); id = rc.getID(); myTeam = rc.getTeam(); enemyTeam = myTeam.opponent(); history = new MapLocation[roundLimit]; robotType = rc.getType(); enrollment = rc.getRoundNum(); if (robotType != RobotType.ARCHON) birthday = enrollment - robotType.buildTurns - BUILD_LAG; hometown = rc.getLocation(); sightRadius = robotType.sensorRadiusSquared; straightSight = (int) Math.sqrt(sightRadius); canMessageSignal = robotType.canMessageSignal(); Signals.buildTarget = new MapLocation[roundLimit]; Signals.buildStrategy = new SignalStrategy[roundLimit]; try { addInfo(rc.senseRobot(id)); myArchonHometowns = rc.getInitialArchonLocations(myTeam); enemyArchonHometowns = rc.getInitialArchonLocations(enemyTeam); int coordinates[] = new int[MAP_MAX]; int x = 0; int y = 0; for (int i = enemyArchonHometowns.length - 1; i >= 0; --i) { MapLocation loc = enemyArchonHometowns[i]; twiceCenterX += loc.x; twiceCenterY += loc.y; coordinates[loc.y] *= MAP_MAX; coordinates[loc.y] += loc.x + 1; } for (int i = 0; i < myArchonHometowns.length; ++i) { MapLocation loc = myArchonHometowns[i]; twiceCenterX += loc.x; twiceCenterY += loc.y; x += loc.x; y += loc.y; } twiceCenterX /= myArchonHometowns.length; twiceCenterY /= myArchonHometowns.length; x /= myArchonHometowns.length; y /= myArchonHometowns.length; for (int i = 0; i < myArchonHometowns.length; ++i) { MapLocation loc = myArchonHometowns[i]; int xCoord = coordinates[loc.y] - 1; coordinates[loc.y] /= MAP_MAX; if (loc.x != twiceCenterX - xCoord) rotation = true; } Archon.center = new MapLocation(x, y); myBase = new MapLocation(twiceCenterX / 2, twiceCenterY / 2).directionTo(Archon.center); enemyBase = myBase.opposite(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } }
// TODO: this takes a little too long on big maps private void computePastrScores() { int mapWidth = rc.getMapWidth(); int mapHeight = rc.getMapHeight(); double mapSize = Math.hypot(mapWidth, mapHeight); MapLocation mapCenter = new MapLocation(mapWidth / 2, mapHeight / 2); double[][] pastrScores = new double[mapWidth][mapHeight]; for (int y = 2; y < mapHeight - 2; y += 5) { for (int x = 2; x < mapWidth - 2; x += 5) { if (rc.senseTerrainTile(new MapLocation(x, y)) != TerrainTile.VOID) { MapLocation loc = new MapLocation(x, y); double distOurHQ = Math.sqrt(loc.distanceSquaredTo(ourHQ)); double distTheirHQ = Math.sqrt(loc.distanceSquaredTo(theirHQ)); if (distOurHQ < distTheirHQ) { int numCows = 0; for (int cowX = x - 2; cowX <= x + 2; cowX++) { for (int cowY = y - 2; cowY <= y + 2; cowY++) { if (rc.senseTerrainTile(new MapLocation(cowX, cowY)) != TerrainTile.VOID) { numCows += cowGrowth[cowX][cowY]; } } } if (numCows >= 5) { double distCenter = Math.sqrt(loc.distanceSquaredTo(mapCenter)); pastrScores[x][y] = numCows * (1 + (1.0 * distCenter - 0.5 * distOurHQ + 0.5 * distTheirHQ) / mapSize); } else { pastrScores[x][y] = -999999; // must be at least some cows } } else { pastrScores[x][y] = -999999; // only make pastrs on squares closer to our HQ than theirs } } else { pastrScores[x][y] = -999999; // don't make pastrs on void squares } } } computedPastrScores = pastrScores; }
/** * @param rc * @param dirToCorner * @return the location of the corner in the given direction or LOCATION_NONE if it is not a * corner * @throws GameActionException */ private static MapLocation checkForCorner(RobotController rc, Direction dirToCorner) throws GameActionException { int senseRadiusMinusOneSquared = (int) Math.pow(Math.sqrt(rc.getType().sensorRadiusSquared) - 1, 2); // so that when you add one below to check for a corner, you can still sense the +1 location MapLocation[] nearby = MapLocation.getAllMapLocationsWithinRadiusSq(rc.getLocation(), senseRadiusMinusOneSquared); boolean isCorner = true; MapLocation corner = getFurthestInDirection(rc, nearby, dirToCorner); Direction[] nearDirections = {dirToCorner, dirToCorner.rotateLeft(), dirToCorner.rotateRight()}; for (Direction dir : nearDirections) { if (rc.onTheMap(corner.add(dir))) { isCorner = false; } } return isCorner ? corner : LOCATION_NONE; }
public void probeAndUpdateMapInfoModule( final MapInfoModule mapInfoModule, final MapLocation location, final RobotController robotController) throws GameActionException { final int probeDistance = (int) Math.floor(Math.sqrt(robotController.getType().sensorRadiusSquared)); if (mapInfoModule.eastBoundaryValue == MapInfoModule.UnknownValue) { final MapLocation foundProbeLocation = this.probeDirection(Direction.EAST, probeDistance, location, robotController); if (foundProbeLocation != null) { mapInfoModule.eastBoundaryValue = foundProbeLocation.x; } } if (mapInfoModule.westBoundaryValue == MapInfoModule.UnknownValue) { final MapLocation foundProbeLocation = this.probeDirection(Direction.WEST, probeDistance, location, robotController); if (foundProbeLocation != null) { mapInfoModule.westBoundaryValue = foundProbeLocation.x; } } if (mapInfoModule.northBoundaryValue == MapInfoModule.UnknownValue) { final MapLocation foundProbeLocation = this.probeDirection(Direction.NORTH, probeDistance, location, robotController); if (foundProbeLocation != null) { mapInfoModule.northBoundaryValue = foundProbeLocation.y; } } if (mapInfoModule.southBoundaryValue == MapInfoModule.UnknownValue) { final MapLocation foundProbeLocation = this.probeDirection(Direction.SOUTH, probeDistance, location, robotController); if (foundProbeLocation != null) { mapInfoModule.southBoundaryValue = foundProbeLocation.y; } } }
private int guessTravelRounds(MapLocation start, MapLocation dest) { int ret = (int) (GameConstants.SOLDIER_MOVE_ACTION_DELAY * Math.sqrt(start.distanceSquaredTo(dest))); MapLocation probe = start; boolean inObstacle = false; int numObstacles = 0; do { probe = probe.add(probe.directionTo(theirHQ)); if (rc.senseTerrainTile(probe) == TerrainTile.VOID) { if (!inObstacle) numObstacles++; // too big? inObstacle = true; } else { inObstacle = false; } } while (!probe.equals(theirHQ)); ret += 25 * numObstacles; return ret; }
private static boolean archonIsTooClose(RobotController rc) { boolean tooClose = false; int archonReserveDistance = (int) (Math.sqrt(rc.getRobotCount()) * 1.4); // @Hope make this more finessed List<RobotInfo> robots = Arrays.asList(rc.senseNearbyRobots(archonReserveDistance + 1, myTeam)); List<RobotInfo> archons = new ArrayList<>(); for (RobotInfo robot : robots) { if (robot.type == RobotType.ARCHON) { archons.add(robot); } } MapLocation myLocation = rc.getLocation(); for (RobotInfo archon : archons) { if (!tooClose && myLocation.distanceSquaredTo(archon.location) < archonReserveDistance) { tooClose = true; break; } } return tooClose; }
/** * Code to run every turn. * * @param rc */ static void runBefore(RobotController rc) throws GameActionException { // -2 for build signals Signals.maxMessages = GameConstants.MESSAGE_SIGNALS_PER_TURN - 2; read = Signals.readSignals(rc); sent = 0; int turn = rc.getRoundNum(); switch (turn - enrollment) { case 0: if (targetType != null && Signals.targetsSize > 0) { models.addFirst(new Target(targetType, Signals.targets[0])); } break; case 1: for (int i = 0; i < sqrt.length; ++i) sqrt[i] = Math.sqrt(i); break; case 2: // Sense rubble a little after construction // TODO: change to 3(?) to avoid overlapping with action senseRubble(rc); break; default: break; } if (canMessageSignal) { sendRadius = 2 * sightRadius; sendBoundariesLow = false; sendBoundariesHigh = false; senseParts(rc); } updateMap(rc); if (turn > 5) { robotInfos = rc.senseNearbyRobots(); for (RobotInfo info : robotInfos) { addInfo(info); } } }
// find a safe location public static MapLocation findSaferLocation() // move to far spot in direction with fewest enemies { MapLocation currentLocation = rc.getLocation(); ArrayList<Direction> directions = Utility.arrayListOfDirections(); /* ArrayList<Integer> enemiesInEachDirection = new ArrayList<Integer>(10); //initialize the enemiesInEachDirection arraylist for(int i = 0; i < 10; i++) { enemiesInEachDirection.add(0); } for(RobotInfo foe : foes) { Direction dirToFoe = currentLocation.directionTo(foe.location); int index = directions.indexOf(dirToFoe); int numberOfFoesInDirection = enemiesInEachDirection.get(index); enemiesInEachDirection.set(index, numberOfFoesInDirection++); } int leastEnemies = 1000000; int directionWithLeastEnemies = 0; for(int i = 0; i<enemiesInEachDirection.size(); i++) { int numberOfEnemies = enemiesInEachDirection.get(i); if(numberOfEnemies < leastEnemies) { directionWithLeastEnemies = i; leastEnemies = numberOfEnemies; } } Direction direction = directions.get(directionWithLeastEnemies);//the direction with the fewest enemies */ // find if foes are within attack range RobotInfo[] foes = rc.senseHostileRobots(rc.getLocation(), RobotType.SCOUT.sensorRadiusSquared); ArrayList<RobotInfo> nearAttackRange = new ArrayList<RobotInfo>(); for (RobotInfo foe : foes) { RobotType type = foe.type; if (type != RobotType.ARCHON && type != RobotType.ZOMBIEDEN && type != RobotType.SCOUT) // only want enemies who can attack { // if you're close to the attack range if (currentLocation.distanceSquaredTo(foe.location) < foe.type.attackRadiusSquared + 4) { nearAttackRange.add(foe); } } } // get average loc of hostiles // could also just run away from the closest hostile // neither one of those would have you go up or down if you have enemies directly to // your left and right int n_hostiles = 0; int x_sum = 0; int y_sum = 0; if (nearAttackRange.size() > 0) { for (RobotInfo robot : nearAttackRange) { n_hostiles++; MapLocation robotLoc = robot.location; x_sum += robotLoc.x; y_sum += robotLoc.y; } int x = x_sum / n_hostiles; int y = y_sum / n_hostiles; MapLocation hostileLoc = new MapLocation(x, y); Direction dirToMove = hostileLoc.directionTo(rc.getLocation()); MapLocation locationToGoTo = currentLocation.add(dirToMove, (int) Math.sqrt(RobotType.ARCHON.sensorRadiusSquared)); return locationToGoTo; } /* OTHER WAY TO DO IT //get the average direction to them //ArrayList<Direction> listOfDirections = Utility.arrayListOfDirections(); int averageDirection = 0; for(RobotInfo foe : nearAttackRange) { averageDirection += directions.indexOf(currentLocation.directionTo(foe.location)); } if(nearAttackRange.size() > 0) { averageDirection /= nearAttackRange.size(); Direction directionToEnemies = directions.get(averageDirection); //move in that direction as far as you can see MapLocation locationToGoTo = currentLocation.add(directionToEnemies.opposite(), (int)Math.sqrt(RobotType.ARCHON.sensorRadiusSquared)); return locationToGoTo; } */ else { return rc.getLocation(); } }
private Strategy pickStrategyByAnalyzingMap() throws GameActionException { // Guess how long it would take the enemy to rush a well-placed pastr MapLocation mapCenter = new MapLocation(rc.getMapWidth() / 2, rc.getMapHeight() / 2); int openPastrRushRounds = guessTravelRounds(theirHQ, mapCenter) + guessTravelRounds(mapCenter, computedBestPastrLocation); // my pathfinding rocks: int pastrTravelDelay = (int) (GameConstants.SOLDIER_MOVE_ACTION_DELAY * Math.sqrt(ourHQ.distanceSquaredTo(computedBestPastrLocation))); int pastrBuildDelay = (int) (GameConstants.HQ_SPAWN_DELAY_CONSTANT_1 + RobotType.PASTR.captureTurns); // how long it will take for our pastr to go up openPastrRushRounds += pastrBuildDelay; // they can't rush until they know where to rush to // Guess how many rounds it would take us to win with a noise tower in the open double openPastrCowGrowth = estimateNearbyCowGrowth(computedBestPastrLocation); int openPastrRoundsNeeded = estimateTimeToWin(openPastrCowGrowth); int towerInefficiency = 150; // we don't start milking immediately, unfortunately openPastrRoundsNeeded += towerInefficiency; int fastTowerBuildDelay = RobotType.NOISETOWER.captureTurns + pastrTravelDelay; // account for the time needed to go there and set up a tower int safeTowerBuildDelay = RobotType.NOISETOWER.captureTurns + Math.max( 81, pastrTravelDelay); // account for the time needed to go there and set up a // tower and wait for them to make a pastr int fastOpenPastrRoundsToWin = openPastrRoundsNeeded + fastTowerBuildDelay; int safeOpenPastrRoundsToWin = openPastrRoundsNeeded + safeTowerBuildDelay; // Guess how many rounds it would take us to win with a noise tower in the HQ double hqPastrCowGrowth = estimateNearbyCowGrowth(ourHQ); int hqPastrRoundsToWin = estimateTimeToWin(hqPastrCowGrowth); double hqSlowdown = estimateHQHerdObstacleSlowdownFactor(); hqPastrRoundsToWin *= hqSlowdown; hqPastrRoundsToWin += RobotType.NOISETOWER.captureTurns; hqPastrRoundsToWin += towerInefficiency; // Debug.indicate("map", 0, String.format("fastOpenPastrRoundsToWin = %d, // safeOpenPastrRoundsToWin = %d (cows = %f)", fastOpenPastrRoundsToWin, // safeOpenPastrRoundsToWin, openPastrCowGrowth)); // Debug.indicate("map", 1, String.format("hqPastrRoundsToWin = %d (cows = %f, slowdown = %f), // rushRounds = %d", hqPastrRoundsToWin, hqPastrCowGrowth, // hqSlowdown, openPastrRushRounds)); Strategy strat; if (fastOpenPastrRoundsToWin < openPastrRushRounds) { // I can't imagine this actually happening, but if we can win before the rush even gets to us // then go for it! strat = Strategy.NOISE_THEN_ONE_PASTR; } else if (safeOpenPastrRoundsToWin < hqPastrRoundsToWin) { // otherwise we probably have to decide between a safe open pastr and an HQ pastr. // Go open pastr only if is significantly faster strat = Strategy.ONE_PASTR_THEN_NOISE; } else { strat = Strategy.HQ_PASTR; } return strat; }
public static void computeAndPublish(MapLocation here, MapLocation pastr, RobotController rc) throws GameActionException { // Useful data int attackRange = (int) (Math.sqrt(RobotType.NOISETOWER.attackRadiusMaxSquared) - 3); // -3 becauase we actually have to shoot past the square int attackRangeSq = attackRange * attackRange; int mapWidth = rc.getMapWidth(); int mapHeight = rc.getMapHeight(); Direction[] dirs = new Direction[] { Direction.NORTH_WEST, Direction.SOUTH_WEST, Direction.SOUTH_EAST, Direction.NORTH_EAST, Direction.NORTH, Direction.WEST, Direction.SOUTH, Direction.EAST }; int[] dirsX = new int[] {1, 1, -1, -1, 0, 1, 0, -1}; int[] dirsY = new int[] {1, -1, -1, 1, 1, 0, -1, 0}; // Set up the queue MapLocation[] locQueue = new MapLocation [(2 * RobotType.NOISETOWER.attackRadiusMaxSquared + 1) * (2 * RobotType.NOISETOWER.attackRadiusMaxSquared + 1)]; int locQueueHead = 0; int locQueueTail = 0; boolean[][] wasQueued = new boolean[GameConstants.MAP_MAX_WIDTH][GameConstants.MAP_MAX_HEIGHT]; // Push pastr onto queue locQueue[locQueueTail] = pastr; locQueueTail++; wasQueued[pastr.x][pastr.y] = true; while (locQueueHead != locQueueTail) { // pop a location from the queue MapLocation loc = locQueue[locQueueHead]; locQueueHead++; int locX = loc.x; int locY = loc.y; for (int i = 8; i-- > 0; ) { int x = locX + dirsX[i]; int y = locY + dirsY[i]; if (x > 0 && y > 0 && x < mapWidth && y < mapHeight && !wasQueued[x][y]) { MapLocation newLoc = new MapLocation(x, y); if (here.distanceSquaredTo(newLoc) <= attackRangeSq) { if (rc.senseTerrainTile(newLoc) != TerrainTile.VOID) { writeHerdDir(newLoc, dirs[i], rc); // push newLoc onto queue locQueue[locQueueTail] = newLoc; locQueueTail++; wasQueued[x][y] = true; } } } } } }
public class BotNoiseTower extends Bot { public static void loop(RobotController theRC) throws Exception { init(theRC); while (true) { try { turn(); } catch (Exception e) { e.printStackTrace(); } rc.yield(); } } protected static void init(RobotController theRC) throws GameActionException { Bot.init(theRC); // Debug.init(theRC, "herd"); here = rc.getLocation(); // claim the assignment to build this tower so others know not to build it int numPastrLocations = MessageBoard.NUM_PASTR_LOCATIONS.readInt(); amSuppressor = true; for (int i = 0; i < numPastrLocations; i++) { MapLocation pastrLoc = MessageBoard.BEST_PASTR_LOCATIONS.readFromMapLocationList(i); if (rc.getLocation().isAdjacentTo(pastrLoc)) { amSuppressor = false; MessageBoard.TOWER_BUILDER_ROBOT_IDS.claimAssignment(i); break; } } if (amSuppressor) { int bestDistSq = 999999; int numSuppressors = MessageBoard.NUM_SUPPRESSORS.readInt(); int suppressorIndex = -1; for (int i = 0; i < numSuppressors; i++) { MapLocation target = MessageBoard.SUPPRESSOR_TARGET_LOCATIONS.readFromMapLocationList(i); int distSq = here.distanceSquaredTo(target); if (distSq < bestDistSq) { bestDistSq = distSq; suppressionTarget = target; suppressorIndex = i; } } if (suppressorIndex != -1) { MessageBoard.SUPPRESSOR_BUILDER_ROBOT_IDS.claimAssignment(suppressorIndex); } } else { // Figure out the best direction to start herding in double[] freeCows = new double[8]; double[][] cowGrowth = rc.senseCowGrowth(); Direction[] dirs = Direction.values(); for (int i = 0; i < 8; i++) { Direction dir = dirs[i]; MapLocation probe = here.add(dir); while (Util.passable(rc.senseTerrainTile(probe)) && here.distanceSquaredTo(probe) <= RobotType.NOISETOWER.attackRadiusMaxSquared) { freeCows[i] += cowGrowth[probe.x][probe.y]; probe = probe.add(dir); } } double bestScore = -1; int bestDir = -1; for (int i = 0; i < 8; i++) { double score = freeCows[i] + freeCows[(i + 1) % 8] + freeCows[(i + 2) % 8]; if (score > bestScore) { bestScore = score; bestDir = i; } } attackDir = dirs[bestDir]; } } static MapLocation here; static MapLocation pastr = null; static boolean amSuppressor; static MapLocation suppressionTarget; private static void turn() throws GameActionException { if (!rc.isActive()) return; if (amSuppressor) { MapLocation[] theirPastrs = rc.sensePastrLocations(them); MapLocation closestEnemyPastr = Util.closest(theirPastrs, here); if (closestEnemyPastr != null) { if (rc.canAttackSquare(closestEnemyPastr)) { rc.attackSquare(closestEnemyPastr); return; } else { MapLocation closer = closestEnemyPastr.add(closestEnemyPastr.directionTo(here)); if (rc.canAttackSquare(closer)) { rc.attackSquare(closer); return; } } } else { if (suppressionTarget != null && rc.canAttackSquare(suppressionTarget)) { rc.attackSquare(suppressionTarget); return; } } } pastr = findNearestAlliedPastr(); if (pastr == null || here.distanceSquaredTo(pastr) > 2 * RobotType.NOISETOWER.attackRadiusMaxSquared) { pastr = here; } herdTowardPastrDumb(); // herdTowardPastrSmart(); } private static MapLocation findNearestAlliedPastr() { MapLocation[] pastrs = rc.sensePastrLocations(us); return Util.closest(pastrs, here); } static final int maxOrthogonalRadius = (int) Math.sqrt(RobotType.NOISETOWER.attackRadiusMaxSquared); static final int maxDiagonalRadius = (int) Math.sqrt(RobotType.NOISETOWER.attackRadiusMaxSquared / 2); static Direction attackDir = Direction.NORTH; static int radius = attackDir.isDiagonal() ? maxDiagonalRadius : maxOrthogonalRadius; // static final int[] nextDumbHerdDir = new int[] { 2, 3, 4, 5, 6, 7, 1, 0 }; static final int[] nextDumbHerdDir = new int[] {1, 2, 3, 4, 5, 6, 7, 0}; private static void herdTowardPastrDumb() throws GameActionException { MapLocation target = null; do { int dx = radius * attackDir.dx; int dy = radius * attackDir.dy; target = new MapLocation(pastr.x + dx, pastr.y + dy); radius--; if (radius <= (attackDir.isDiagonal() ? 3 : 5)) { attackDir = Direction.values()[nextDumbHerdDir[attackDir.ordinal()]]; radius = attackDir.isDiagonal() ? maxDiagonalRadius : maxOrthogonalRadius; } } while (tooFarOffMap(target) || !rc.canAttackSquare(target)); rc.attackSquare(target); } private static boolean tooFarOffMap(MapLocation loc) { int W = 2; return loc.x < -W || loc.y < -W || loc.x >= rc.getMapWidth() + W || loc.y >= rc.getMapWidth() + W; } static MapLocation smartLoc = null; static Direction nextStartDir = Direction.NORTH; static int[] edgesX = new int[] {-2, -1, 0, 1, 2, -3, -2, 2, 3, -3, 3, -3, 3, -3, 3, -3, -2, 2, 3, -2, -1, 0, 1, 2}; static int[] edgesY = new int[] {3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 0, 0, -1, -1, -2, -2, -2, -2, -3, -3, -3, -3, -3}; static int edgeTrimIndex = 0; private static void herdTowardPastrSmart() throws GameActionException { if (smartLoc == null || smartLoc.distanceSquaredTo(pastr) <= GameConstants.PASTR_RANGE) { smartLoc = pastr.add( nextStartDir, nextStartDir.isDiagonal() ? maxDiagonalRadius - 3 : maxOrthogonalRadius - 3); nextStartDir = nextStartDir.rotateRight(); edgeTrimIndex = edgesX.length - 1; // Debug.indicate("herd", 0, "starting new spoke"); } while (edgeTrimIndex >= 0) { MapLocation edge = new MapLocation(pastr.x + edgesX[edgeTrimIndex], pastr.y + edgesY[edgeTrimIndex]); edgeTrimIndex--; if (isOnMap(edge) && rc.canSenseSquare(edge) && rc.senseCowsAtLocation(edge) > 1000) { MapLocation targetSquare = edge.add(pastr.directionTo(edge)); if (rc.canAttackSquare(targetSquare)) { rc.attackSquareLight(targetSquare); return; } } } while (!rc.canAttackSquare(smartLoc) || !isOnMap(smartLoc)) { Direction moveDir = smartLoc.directionTo(pastr); Direction computedMoveDir = HerdPattern.readHerdDir(smartLoc, rc); if (computedMoveDir != null) moveDir = computedMoveDir; smartLoc = smartLoc.add(moveDir); if (here.distanceSquaredTo(smartLoc) > RobotType.NOISETOWER.attackRadiusMaxSquared) { smartLoc = null; return; } if (smartLoc.equals(pastr)) return; // otherwise in some situations we could get an infinite loop } Direction herdDir = smartLoc.directionTo(pastr); Direction computedHerdDir = HerdPattern.readHerdDir(smartLoc, rc); if (computedHerdDir != null) herdDir = computedHerdDir; MapLocation targetSquare = smartLoc.add(Util.opposite(herdDir), 3); // Debug.indicate("herd", 2, "want to attack " + targetSquare.toString()); if (rc.canAttackSquare(targetSquare)) rc.attackSquare(targetSquare); smartLoc = smartLoc.add(herdDir); } }