From 61f4ba9c18551ec86ec744d706ab7fc6ea61ba06 Mon Sep 17 00:00:00 2001 From: 2022tgoel Date: Sun, 23 Jan 2022 17:26:13 -0500 Subject: [PATCH 1/6] add new player --- src/rebutia_micro_heal/Archon.java | 465 ++++++ src/rebutia_micro_heal/BOT.java | 16 + src/rebutia_micro_heal/BiCHANNEL.java | 25 + src/rebutia_micro_heal/Builder.java | 206 +++ src/rebutia_micro_heal/CHANNEL.java | 36 + src/rebutia_micro_heal/CONSTANTS.java | 10 + src/rebutia_micro_heal/Comms.java | 270 +++ src/rebutia_micro_heal/Laboratory.java | 12 + src/rebutia_micro_heal/Miner.java | 380 +++++ src/rebutia_micro_heal/MinerNav.java | 87 + src/rebutia_micro_heal/Navigation.java | 2016 +++++++++++++++++++++++ src/rebutia_micro_heal/RANK.java | 11 + src/rebutia_micro_heal/RobotPlayer.java | 102 ++ src/rebutia_micro_heal/Sage.java | 273 +++ src/rebutia_micro_heal/Soldier.java | 522 ++++++ src/rebutia_micro_heal/Unit.java | 563 +++++++ src/rebutia_micro_heal/Watchtower.java | 499 ++++++ 17 files changed, 5493 insertions(+) create mode 100644 src/rebutia_micro_heal/Archon.java create mode 100644 src/rebutia_micro_heal/BOT.java create mode 100644 src/rebutia_micro_heal/BiCHANNEL.java create mode 100644 src/rebutia_micro_heal/Builder.java create mode 100644 src/rebutia_micro_heal/CHANNEL.java create mode 100644 src/rebutia_micro_heal/CONSTANTS.java create mode 100644 src/rebutia_micro_heal/Comms.java create mode 100644 src/rebutia_micro_heal/Laboratory.java create mode 100644 src/rebutia_micro_heal/Miner.java create mode 100644 src/rebutia_micro_heal/MinerNav.java create mode 100644 src/rebutia_micro_heal/Navigation.java create mode 100644 src/rebutia_micro_heal/RANK.java create mode 100644 src/rebutia_micro_heal/RobotPlayer.java create mode 100644 src/rebutia_micro_heal/Sage.java create mode 100644 src/rebutia_micro_heal/Soldier.java create mode 100644 src/rebutia_micro_heal/Unit.java create mode 100644 src/rebutia_micro_heal/Watchtower.java diff --git a/src/rebutia_micro_heal/Archon.java b/src/rebutia_micro_heal/Archon.java new file mode 100644 index 0000000..d28ad28 --- /dev/null +++ b/src/rebutia_micro_heal/Archon.java @@ -0,0 +1,465 @@ +package rebutia_micro_heal; + +import battlecode.common.*; +import java.util.*; + +public class Archon extends Unit { + + enum MODE { + INITIAL, + DEFAULT, + SOLDIER_HUB, + MAKE_BUILDER, + THREATENED, + OTHER_THREATENED, + REINFORCE_WATCHTOWER; + } + + int round_num; + int archonNumber = -1; + + Direction[] dirs; + + int built_units = 0; + int counter = 0; + + int num_soldiers = 0; + int num_miners = 0; + int num_builders = 0; + int num_archons_init; + int num_archons_alive; + + int num_soldiers_hub = 0; + + int[] defaultBuildOrder; + int threatChannel = -1; + + private int[] troopCounter = { 0, 0, 0, 0, 0 }; // miner, soldier, builder, sage, watchtower + private int desiredNumMiners = 1000; + private boolean initial = true; + + public Archon(RobotController rc) throws GameActionException { + super(rc); + System.out.println("here"); + num_archons_alive = rc.getArchonCount(); + num_archons_init = num_archons_alive; + dirs = sortedDirections(); + defaultBuildOrder = chooseBuildOrder(); + archonNumber = radio.getArchonNum(); + radio.initalizeArchonLoc(archonNumber, rc.getLocation()); + addLeadEstimate(); + } + + @Override + public void run() throws GameActionException { + round_num = rc.getRoundNum(); + radio.update(); + radio.clearThreat(); + radio.clearMiningAreas(); + radio.clearTargetAreas(); + updateAmountMined(); + + archonNumber = radio.getArchonNum(); + + troopCounter = new int[] { + radio.readCounter(RobotType.MINER), + radio.readCounter(RobotType.SOLDIER), + radio.readCounter(RobotType.BUILDER), + 0, + radio.readCounter(RobotType.WATCHTOWER) + }; + + if (round_num == 2) { + int leadEstimate = radio.getLeadEstimate(); + desiredNumMiners = determineMinerNum(leadEstimate); + } + + //System.out.println("Archon number: " + archonNumber + " Mode num: " + radio.getMode() + " " + " round: " + round_num); + MODE mode = determineMode(); + double useful_miners = (double) radio.readCounter(BiCHANNEL.USEFUL_MINERS); + + switch (mode) { + case THREATENED: + threatChannel = radio.sendThreatAlert(); + int tot = radio.totalUnderThreat(); + + if (tot != 0 && round_num % tot != threatChannel) { // alternate between those under threat + break; + } + if (checkForResources(RobotType.SOLDIER.buildCostLead)) { + Direction[] enemyDirs = getEnemyDirs(); + for (Direction dir : enemyDirs) { + buildSoldier(dir); + } + } else + attemptHeal(); + break; + case INITIAL: + if (round_num >= 60) { + initial = false; + break; + } + if (round_num % num_archons_alive != archonNumber) break; + if (num_miners > (double) troopCounter[0] / (double) num_archons_init) break; + if (troopCounter[0] < desiredNumMiners) { + build(new int[] {1, 0, 0}); + } + else if ((useful_miners / (double) troopCounter[0]) >= 0.80) { + build(new int[] {1, 0, 0}); + } + else if ((useful_miners / (double) troopCounter[0]) <= 0.75) { + initial = false; + } + System.out.println("Desired miners: " + desiredNumMiners + " Useful miners: " + useful_miners + " Ratio: " + (useful_miners / (double) troopCounter[0])); + break; + case SOLDIER_HUB: + if (checkForResources(RobotType.SOLDIER.buildCostLead)) { + boolean soldier_built = build(new int[] { 0, 1, 0 }); + if (soldier_built) + num_soldiers_hub++; + } else { + attemptHeal(); + // rc.setIndicatorString("ATTEMPTING HEALING"); + } + if (num_soldiers_hub > 20) { + radio.broadcastMode((archonNumber + 1) % num_archons_alive); + num_soldiers_hub = 0; + } + break; + case OTHER_THREATENED: + if (rc.getTeamLeadAmount(rc.getTeam()) < 600) { + attemptHeal(); + break; // save for attacked archons + } + case DEFAULT: + attemptHeal(); + if (round_num % num_archons_alive != archonNumber || round_num % 5 != 0) break; + else { + if ((useful_miners / (double) troopCounter[0]) >= 0.25) { + build(new int[] {1, 0, 0}); + } + } + // if ((useful_miners / (double) troopCounter[0]) >= 0.60) build(new int[] {1, 0, 0}); + break; + } + num_archons_alive = rc.getArchonCount(); + rc.setIndicatorString("mode: " + mode.toString() + " " + leadLastCall + " " + getAvgMined()); + } + + public boolean build(int[] build_order) throws GameActionException { + boolean unit_built = false; + for (Direction dir : dirs) { + switch (counter % 3) { + case 0: + if (built_units < build_order[counter % 3]) { + // rc.setIndicatorString("Trying to build a miner" + " built_units: " + + // built_units + " " + build_order[counter % 3]); + unit_built = buildMiner(dir); + // System.out.println("MINER BUILT: " + unit_built + " Roundnum: " + + // rc.getRoundNum()); + } + break; + case 1: + if (built_units < build_order[counter % 3]) { + // rc.setIndicatorString("Trying to build a soldier" + " built_units: " + + // built_units + " " + build_order[counter % 3]); + unit_built = buildSoldier(dir); + // System.out.println("SOLDIER BUILT: " + unit_built); + } + break; + case 2: + if (built_units < build_order[counter % 3]) { + // rc.setIndicatorString("Trying to build a builder" + " built_units: " + + // built_units + " " + build_order[counter % 3]); + unit_built = buildBuilder(dir); + // System.out.println("BUILDER BUILT: " + unit_built); + } + break; + } + if (built_units >= build_order[counter % 3]) { + counter++; + built_units = 0; + } + if (unit_built) + return true; + } + return false; + } + + public MODE determineMode() throws GameActionException { + if (underThreat()) + return MODE.THREATENED; + else if (radio.totalUnderThreat() > 0) + return MODE.OTHER_THREATENED; + else if (initial) + return MODE.INITIAL; + + if (radio.getMode() == archonNumber) + return MODE.SOLDIER_HUB; + else + return MODE.DEFAULT; + } + + public int determineMinerNum(int leadEstimate) throws GameActionException { + int sizeBracket = (int) Math.ceil((double) mapArea / 1000.0); + int numMinersMap = sizeBracket * 2; + if (leadEstimate > 2000) { + return 12 + numMinersMap; + } + else if (leadEstimate > 1000) { + return 8 + numMinersMap; + } + else if (leadEstimate > 500) { + return 4 + numMinersMap; + } + else if (leadEstimate > 100) { + return 2 + numMinersMap; + } + else { + return 2 + numMinersMap; + } + } + + public boolean underThreat() throws GameActionException { + RobotInfo[] enemies = rc.senseNearbyRobots(-1, rc.getTeam().opponent()); + if (enemies.length > 0) { + broadcastTarget(enemies[0].location); + return true; + } + return false; + } + + ///////////////////////////////////////////////////////////////////// + public boolean buildMiner(Direction dir) throws GameActionException { + if (rc.canBuildRobot(RobotType.MINER, dir)) { + rc.buildRobot(RobotType.MINER, dir); + radio.updateCounter(RobotType.MINER); + built_units++; + num_miners++; + troopCounter[0]++; + return true; + } + return false; + } + + public boolean buildSoldier(Direction dir) throws GameActionException { + if (rc.canBuildRobot(RobotType.SOLDIER, dir)) { + rc.buildRobot(RobotType.SOLDIER, dir); + radio.updateCounter(RobotType.SOLDIER); + built_units++; + num_soldiers++; + troopCounter[1]++; + return true; + } + return false; + } + + public boolean buildBuilder(Direction dir) throws GameActionException { + if (rc.canBuildRobot(RobotType.BUILDER, dir)) { + rc.buildRobot(RobotType.BUILDER, dir); + radio.updateCounter(RobotType.BUILDER); + built_units++; + num_builders++; + troopCounter[2]++; + return true; + } + return false; + } + + public boolean builderInRange() throws GameActionException { + RobotInfo[] allies = rc.senseNearbyRobots(RobotType.BUILDER.actionRadiusSquared, rc.getTeam()); + for (RobotInfo r : allies) { + if (r.type == RobotType.BUILDER) { + return true; + } + } + return false; + } + + ////////////////////////////////////////////////////////////////////// + static int curLead = 200; + static int leadLastCall = 200; + static int[] amountMined = new int[10]; // 10 turn avg + + public void updateAmountMined() { + curLead = rc.getTeamLeadAmount(rc.getTeam()); + if (curLead >= leadLastCall) { // otherwise, something was spent + int minedLastCall = curLead - leadLastCall; + amountMined[round_num % amountMined.length] = minedLastCall; + } + leadLastCall = curLead; + } + + public double getAvgMined() { + int valid_entries = 0; + double avg = 0; + for (int i = 0; i < amountMined.length; i++) + if (amountMined[i] != 0) { + avg += amountMined[i]; + valid_entries++; + } + avg = avg / ((double) valid_entries); + return avg; + } + + public boolean checkForResources(int buildCost) throws GameActionException { // CHANGE TO INCORPORATE GOLD ONCE WE + // USE SAGES + if (curLead >= buildCost || round_num < 20) { + return true; + } else { + int numTurnsToResources = (int) (((double) buildCost - (double) curLead) / Math.max(getAvgMined(), 2.0)); + int numTurnsToAct = rc.getActionCooldownTurns() + + (int) ((cooldownMultiplier(rc.getLocation()) * rc.getType().actionCooldown) / 10); + if (numTurnsToResources > numTurnsToAct) { + return false; + } + if (numTurnsToResources > numTurnsToAct) { + return false; + } else + return true; + } + } + + public MapLocation getAvgEnemyLocation() throws GameActionException { + RobotInfo[] enemies = rc.senseNearbyRobots(-1, rc.getTeam().opponent()); + int num_enemies = 0; + double cx = 0; + double cy = 0; + for (RobotInfo enemy : enemies) { + if (enemy.type == RobotType.SOLDIER || enemy.type == RobotType.SAGE) { + cx += (double) enemy.location.x; + cy += (double) enemy.location.y; + num_enemies += 1; + } + } + if (num_enemies > 0) + return new MapLocation((int) (cx / num_enemies), (int) (cy / num_enemies)); + else + return rc.getLocation().add(dirs[0]); + } + + public Direction[] getEnemyDirs() throws GameActionException { + MapLocation loc = getAvgEnemyLocation(); + Direction toDest = rc.getLocation().directionTo(loc); + Direction[] d_arr = { toDest, toDest.rotateLeft(), toDest.rotateRight(), toDest.rotateLeft().rotateLeft(), + toDest.rotateRight().rotateRight(), toDest.opposite().rotateLeft(), toDest.opposite().rotateRight(), + toDest.opposite() }; + + return d_arr; + } + + public int distToWall(Direction d) { + MapLocation my = rc.getLocation(); + MapLocation n = my.add(d); + int min = Math.min(rc.getMapWidth() - 1 - n.x, n.x) + Math.min(n.y, rc.getMapHeight() - 1 - n.y); + assert (min <= 60); + return min; + } + + public Direction[] sortedDirections() { + Direction[] dirs = { Direction.NORTH, Direction.NORTHEAST, Direction.EAST, Direction.SOUTHEAST, Direction.SOUTH, + Direction.SOUTHWEST, Direction.WEST, Direction.NORTHWEST }; + Arrays.sort(dirs, (a, b) -> distToWall(b) - distToWall(a)); + return dirs; + } + + public int[] chooseBuildOrder() { + if (mapArea < 1400) { + return new int[] { 1, 6, 0 }; // miners, soldiers, builders + } else if (mapArea < 2200) { + return new int[] { 1, 6, 0 }; // miners, soldiers, builders + } else { + return new int[] { 1, 6, 0 }; // miners, soldiers, builders + } + } + + public int[] chooseInitialBuildOrder() throws GameActionException { + return new int[] { 1, 0, 0 }; + } + + public void attemptHeal() throws GameActionException { + RobotInfo[] nearbyBots = rc.senseNearbyRobots(rc.getType().actionRadiusSquared, rc.getTeam()); + // if there are any nearby enemy robots, attack the one with the least health + if (nearbyBots.length > 0) { + RobotInfo weakestBot = null; + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.SOLDIER) + if ((weakestBot == null && bot.health < RobotType.SOLDIER.health) || + (weakestBot != null && bot.health < weakestBot.health)) { + weakestBot = bot; + } + } + if (weakestBot != null) { + if (rc.canRepair(weakestBot.location)) { + // rc.setIndicatorString("Succesful Heal!"); + rc.repair(weakestBot.location); + } + } else { + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.MINER) + if ((weakestBot == null && bot.health < RobotType.MINER.health) || + (weakestBot != null && bot.health < weakestBot.health)) { + weakestBot = bot; + } + } + if (weakestBot != null) { + if (rc.canRepair(weakestBot.location)) { + rc.repair(weakestBot.location); + } + } + } + } + } + + public void addLeadEstimate() throws GameActionException { + MapLocation[] leadLocs = rc.senseNearbyLocationsWithLead(); + MapLocation[] friendlyArchonLocs = radio.getFriendlyArchons(num_archons_alive); + int total_value = 0; + if (archonNumber != 0) { + MapLocation[] prevArchons = firstN(friendlyArchonLocs, archonNumber - 1); + MapLocation[] leadLocsUncounted = leadLocsNotCounted(leadLocs, prevArchons); + for (MapLocation loc : leadLocsUncounted) { + total_value += rc.senseLead(loc); + } + } else { + for (MapLocation loc : leadLocs) { + total_value += rc.senseLead(loc); + } + } + if (total_value > 0) { + radio.incrementLeadEsimate(total_value); + } + } + + public MapLocation[] leadLocsNotCounted(MapLocation[] leadLocs, MapLocation[] archons) throws GameActionException { + MapLocation[] locs = new MapLocation[leadLocs.length]; + int uncounted = 0; + for (int i = 0; i < leadLocs.length; i++) { + boolean counted = false; + // check if lead is visible by any of the archons + for (int j = 0; j < archons.length; j++) { + if (leadLocs[i].distanceSquaredTo(archons[j]) <= RobotType.ARCHON.visionRadiusSquared) { + counted = true; + } + } + // if not visible, add to list + if (!counted) { + locs[uncounted] = leadLocs[i]; + uncounted++; + } + } + MapLocation[] leadLocsUncounted = new MapLocation[uncounted]; + for (int i = 0; i < uncounted; i++) { + leadLocsUncounted[i] = locs[i]; + } + return leadLocsUncounted; + } + + public MapLocation[] firstN(MapLocation[] locs, int n) throws GameActionException { + MapLocation[] newLocs = new MapLocation[n]; + for (int i = 0; i < n; i++) { + newLocs[i] = locs[i]; + } + return newLocs; + } +} \ No newline at end of file diff --git a/src/rebutia_micro_heal/BOT.java b/src/rebutia_micro_heal/BOT.java new file mode 100644 index 0000000..0d3f740 --- /dev/null +++ b/src/rebutia_micro_heal/BOT.java @@ -0,0 +1,16 @@ +package rebutia_micro_heal; + +public enum BOT { + NONE(0), + MINER(1), + SOLDIER(2), + BUILDER(3), + SAGE(4), + WATCHTOWER(5), + LABORATORY(6), + ; + + private final int id; + BOT(int id) { this.id = id; } + public int getValue() { return id; } +} diff --git a/src/rebutia_micro_heal/BiCHANNEL.java b/src/rebutia_micro_heal/BiCHANNEL.java new file mode 100644 index 0000000..60aabaa --- /dev/null +++ b/src/rebutia_micro_heal/BiCHANNEL.java @@ -0,0 +1,25 @@ +package rebutia_micro_heal; + +/** + * For BiCHANNEL communications using one-round lagging updates. + * Use for data that needs to be recomputed each round (ex. # of soldiers alive + * this round). + * BiCHANNEL alternate between two channels. Use Comms.getCounterChannel() to + * get the update or read (lagging) channel. + */ +public enum BiCHANNEL { + MINERS_ALIVE(CHANNEL.MINERS_ALIVE, CHANNEL.MINERS_ALIVE_ALT), + SOLDIERS_ALIVE(CHANNEL.SOLDIERS_ALIVE, CHANNEL.SOLDIERS_ALIVE_ALT), + BUILDERS_ALIVE(CHANNEL.BUILDERS_ALIVE, CHANNEL.BUILDERS_ALIVE_ALT), + TOWERS_ALIVE(CHANNEL.TOWERS_ALIVE, CHANNEL.TOWERS_ALIVE_ALT), + USEFUL_MINERS(CHANNEL.USEFUL_MINERS, CHANNEL.USEFUL_MINERS_ALT), + ; + + final CHANNEL ch1; + final CHANNEL ch2; + + BiCHANNEL(CHANNEL ch1, CHANNEL ch2) { + this.ch1 = ch1; + this.ch2 = ch2; + } +} diff --git a/src/rebutia_micro_heal/Builder.java b/src/rebutia_micro_heal/Builder.java new file mode 100644 index 0000000..b754976 --- /dev/null +++ b/src/rebutia_micro_heal/Builder.java @@ -0,0 +1,206 @@ +package rebutia_micro_heal; + +import battlecode.common.*; +import java.util.*; + +public class Builder extends Unit { + public enum MODE { + HEALING, + BUILDING, + REPAIRING + } + + int travel_counter = 0; + int[] exploratoryDir = getExploratoryDir(); + int counter = 0; + Direction[] dirs; + RANK rank; + MODE mode; + + private int num_watchtowers = 0; + private int num_labs = 0; + private int[] troopCounter = { 0, 0, 0, 0, 0 }; // miner, soldier, builder, sage, watchtower + MapLocation target = null; + + private int built_units = 0; + private int[] build_order; + + public Builder(RobotController rc) throws GameActionException { + super(rc); + rank = getBuilderRank(); + dirs = sortedDirections(); + } + + @Override + public void run() throws GameActionException { + super.run(); + radio.updateCounter(); + troopCounter = new int[] { radio.readCounter(RobotType.MINER), radio.readCounter(RobotType.SOLDIER), + radio.readCounter(RobotType.BUILDER), 0, radio.readCounter(RobotType.WATCHTOWER) }; + build_order = getBuildOrder(); + switch (rank) { + case MARTYR: + forTheGreaterGood(); + break; + case DEFAULT: + mode = getMode(); + switch (mode) { + case HEALING: + heal(); + break; + case BUILDING: + build(build_order); + break; + case REPAIRING: + if (rc.canRepair(target)) + rc.repair(target); + else + moveToLocation(target); + target = null; + break; + } + break; + default: + break; + } + } + + private int[] getBuildOrder() { + return new int[] { 0, 1 }; // laboratories, watchtowers + } + + public MODE getMode() throws GameActionException { + if (findUnrepaired()) { + return MODE.REPAIRING; + } else if (troopCounter[4] <= (CONSTANTS.SOLDIERS_TO_TOWERS * (double) troopCounter[2])) { + return MODE.BUILDING; + } else + return MODE.HEALING; + } + + public boolean findUnrepaired() throws GameActionException { + RobotInfo[] nearbyBots = rc.senseNearbyRobots(-1, rc.getTeam()); + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.WATCHTOWER && bot.mode == RobotMode.PROTOTYPE) { + target = bot.location; + return true; + } + } + return false; + } + + public int distToWall(Direction d) { + MapLocation my = rc.getLocation(); + MapLocation n = my.add(d); + int min = 61; + min = Math.min(min, n.x); + min = Math.min(min, n.y); + min = Math.min(min, rc.getMapWidth() - n.x); + min = Math.min(min, rc.getMapHeight() - n.y); + return min; + } + + public Direction[] sortedDirections() { + Direction[] dirs = { Direction.NORTH, Direction.NORTHEAST, Direction.EAST, Direction.SOUTHEAST, Direction.SOUTH, + Direction.SOUTHWEST, Direction.WEST, Direction.NORTHWEST }; + Arrays.sort(dirs, (a, b) -> distToWall(b) - distToWall(a)); + return dirs; + } + + public void build(int[] build_order) throws GameActionException { + for (Direction dir : dirs) { + switch (counter % 2) { + case 0: + rc.setIndicatorString("Trying to build a laboratory" + " built_units: " + built_units + " " + + build_order[counter % 2]); + buildLaboratory(dir); + break; + case 1: + rc.setIndicatorString("Trying to build a watchtower" + " built_units: " + built_units + " " + + build_order[counter % 2]); + buildWatchtower(dir); + break; + } + if (built_units >= build_order[counter % 2]) { + counter++; + built_units = 0; + } + } + } + + public void buildLaboratory(Direction dir) throws GameActionException { + if (rc.canBuildRobot(RobotType.LABORATORY, dir)) { + rc.buildRobot(RobotType.LABORATORY, dir); + built_units++; + num_labs++; + } + } + + public void buildWatchtower(Direction dir) throws GameActionException { + if (rc.canBuildRobot(RobotType.WATCHTOWER, dir)) { + rc.buildRobot(RobotType.WATCHTOWER, dir); + built_units++; + num_watchtowers++; + } + } + + public void heal() throws GameActionException { + RobotInfo[] nearbyBots = rc.senseNearbyRobots(-1, rc.getTeam()); + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.WATCHTOWER || bot.type == RobotType.LABORATORY) { + if (bot.health < bot.type.health) { + if (rc.canRepair(bot.location)) + rc.repair(bot.location); + else + moveToLocation(bot.location); + } + } + } + } + + public void forTheGreaterGood() throws GameActionException { + MapLocation cur = rc.getLocation(); + MapLocation target = null; + if (rc.senseLead(cur) == 0) { + rc.disintegrate(); + } + // robot finds closest spot to archon without lead on it, then destroys itself. + int distSquared; + int minDistSquared = 10000; + for (int dx = -4; dx <= 4; dx++) { + for (int dy = -4; dy <= 4; dy++) { + if (dx == 0 && dy == 0) + continue; + if (validCoords(cur.x + dx, cur.y + dy)) { + MapLocation loc = new MapLocation(cur.x + dx, cur.y + dy); + if (loc.equals(homeArchon)) + continue; + if (rc.canSenseLocation(loc)) { + int numLead = rc.senseLead(loc); + if (numLead == 0) { + distSquared = cur.distanceSquaredTo(loc); + if (distSquared < minDistSquared) { + minDistSquared = distSquared; + target = loc; + } + } + + } + } + } + } + if (target != null) { + moveToLocation(target); + rc.setIndicatorString("target: " + target.x + " " + target.y); + } else + moveInDirection(exploratoryDir); + } + + public RANK getBuilderRank() throws GameActionException { + RANK new_rank = findRank(); + if (new_rank == RANK.DEFAULT || new_rank == RANK.MARTYR) { + return new_rank; + } + return RANK.DEFAULT; + } +} \ No newline at end of file diff --git a/src/rebutia_micro_heal/CHANNEL.java b/src/rebutia_micro_heal/CHANNEL.java new file mode 100644 index 0000000..8e1e70d --- /dev/null +++ b/src/rebutia_micro_heal/CHANNEL.java @@ -0,0 +1,36 @@ +package rebutia_micro_heal; + +public enum CHANNEL { + ROUND_NUM(0), + MINERS_ALIVE(1), + SOLDIERS_ALIVE(2), + BUILDERS_ALIVE(3), + TOWERS_ALIVE(4), + MINERS_ALIVE_ALT(5), + SOLDIERS_ALIVE_ALT(6), + BUILDERS_ALIVE_ALT(7), + TOWERS_ALIVE_ALT(8), + USEFUL_MINERS(9), + USEFUL_MINERS_ALT(10), + + LEAD_ESTIMATE(19), + ARCHON_LOC_1(20), + fARCHON_STATUS1(24), + ARCHON_NUMBER(28), + UNIT_BUILT(29), + + MINING1(30), + TARGET(35), + ARCHON_MODE(40), + + ORDERS(61), + SEND_RANKS1(62), + SEND_RANKS2(63), + ; + + public static final int NUM_TARGETS = 5; + + private final int id; + CHANNEL(int id) { this.id = id; } + public int getValue() { return id; } +} diff --git a/src/rebutia_micro_heal/CONSTANTS.java b/src/rebutia_micro_heal/CONSTANTS.java new file mode 100644 index 0000000..d7fa1f0 --- /dev/null +++ b/src/rebutia_micro_heal/CONSTANTS.java @@ -0,0 +1,10 @@ +package rebutia_micro_heal; + +import battlecode.common.Direction; + +public class CONSTANTS { + public static final double SOLDIERS_TO_TOWERS = 0.25; + public static Direction[] directions = { + Direction.NORTH, Direction.NORTHEAST, Direction.EAST, Direction.SOUTHEAST, + Direction.SOUTH, Direction.SOUTHWEST, Direction.WEST, Direction.NORTHWEST }; +} diff --git a/src/rebutia_micro_heal/Comms.java b/src/rebutia_micro_heal/Comms.java new file mode 100644 index 0000000..30bc94a --- /dev/null +++ b/src/rebutia_micro_heal/Comms.java @@ -0,0 +1,270 @@ +package rebutia_micro_heal; + +import battlecode.common.*; + +public class Comms { + RobotController rc; + private int round_num; + boolean wasFirstConnection; + + public Comms(RobotController robotController) throws GameActionException { + rc = robotController; + } + + public boolean init() throws GameActionException { + wasFirstConnection = false; + // TODO: distribute init comms clearing? + if (rc.readSharedArray(CHANNEL.ROUND_NUM.getValue()) != rc.getRoundNum()) { + rc.writeSharedArray(CHANNEL.ROUND_NUM.getValue(), rc.getRoundNum()); + + // clear robot counter update channels + for (BiCHANNEL bich : BiCHANNEL.values()) { + CHANNEL ch = getCounterChannel(bich, false); + if (ch != null) + rc.writeSharedArray(ch.getValue(), 0); + } + + wasFirstConnection = true; + } + return wasFirstConnection; + } + + public void update() { + round_num = rc.getRoundNum(); + } + + public void updateCounter() throws GameActionException { + updateCounter(rc.getType()); + } + + public void updateCounter(RobotType rt) throws GameActionException { + updateCounter(getRobotCounterBiChannel(rt)); + } + + public void updateCounter(BiCHANNEL bich) throws GameActionException { + CHANNEL channel = getCounterChannel(bich, false); + int num = wasFirstConnection ? 0 : rc.readSharedArray(channel.getValue()); + rc.writeSharedArray(channel.getValue(), num + 1); + } + + public int readCounter(RobotType rt) throws GameActionException { + return readCounter(getRobotCounterBiChannel(rt)); + } + + public int readCounter(BiCHANNEL bich) throws GameActionException { + CHANNEL channel = getCounterChannel(bich, true); + return rc.readSharedArray(channel.getValue()); + } + + public BiCHANNEL getRobotCounterBiChannel(RobotType rt) { + switch (rt) { + case MINER: + return BiCHANNEL.MINERS_ALIVE; + case SOLDIER: + return BiCHANNEL.SOLDIERS_ALIVE; + case BUILDER: + return BiCHANNEL.BUILDERS_ALIVE; + case WATCHTOWER: + return BiCHANNEL.TOWERS_ALIVE; + default: + return null; + } + } + + public CHANNEL getCounterChannel(BiCHANNEL bich, boolean isReadMode) { + boolean mod = rc.getRoundNum() % 2 == 0; + if (isReadMode) + mod = !mod; + return mod ? bich.ch1 : bich.ch2; + } + + public void postBuild(BOT b) throws GameActionException { + switch (b) { + case MINER: + rc.writeSharedArray(CHANNEL.UNIT_BUILT.getValue(), BOT.MINER.getValue()); + break; + case SOLDIER: + rc.writeSharedArray(CHANNEL.UNIT_BUILT.getValue(), BOT.SOLDIER.getValue()); + break; + case BUILDER: + rc.writeSharedArray(CHANNEL.UNIT_BUILT.getValue(), BOT.BUILDER.getValue()); + break; + case SAGE: + rc.writeSharedArray(CHANNEL.UNIT_BUILT.getValue(), BOT.SAGE.getValue()); + break; + case NONE: + rc.writeSharedArray(CHANNEL.UNIT_BUILT.getValue(), BOT.NONE.getValue()); + default: + break; + } + } + + public BOT getPreviousBuild() throws GameActionException { + int data = rc.readSharedArray(CHANNEL.UNIT_BUILT.getValue()); + switch (data) { + case 0: + return BOT.NONE; + case 1: + return BOT.MINER; + case 2: + return BOT.SOLDIER; + case 3: + return BOT.BUILDER; + case 4: + return BOT.SAGE; + default: + return BOT.NONE; + } + } + + public void clearThreat() throws GameActionException { + if (round_num % 15 == 0) { + for (int i = 0; i < 4; i++) { + rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i, 0); + } + } + } + + public void clearTargetAreas() throws GameActionException { + if (round_num % 3 == 0) { + for (int i = 0; i < CHANNEL.NUM_TARGETS; i++) { + rc.writeSharedArray(CHANNEL.TARGET.getValue() + i, 0); + } + } + } + + public void clearMiningAreas() throws GameActionException { + if (round_num % 3 == 0) { + for (int i = 0; i < 5; i++) { + rc.writeSharedArray(CHANNEL.MINING1.getValue() + i, 0); + } + } + } + + public void initalizeArchonLoc(int archonIndex, MapLocation loc) throws GameActionException { + int locInt = locationToInt(loc); + rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + archonIndex, locInt); + } + + public MapLocation[] getFriendlyArchons(int num_archons) throws GameActionException { + MapLocation[] locs = new MapLocation[num_archons]; + for (int i = 0; i < num_archons; i++) { + int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); + int w = data / 4096; + int x = (data - w * 4096) / 64; + int y = data % 64; + locs[i] = new MapLocation(x, y); + } + return locs; + } + + public int getLeadEstimate() throws GameActionException { + return rc.readSharedArray(CHANNEL.LEAD_ESTIMATE.getValue()); + } + + public void incrementLeadEsimate(int increment) throws GameActionException { + rc.writeSharedArray(CHANNEL.LEAD_ESTIMATE.getValue(), + rc.readSharedArray(CHANNEL.LEAD_ESTIMATE.getValue()) + increment); + } + + public int getMode() throws GameActionException { + return rc.readSharedArray(CHANNEL.ARCHON_MODE.getValue()); + } + + public void broadcastMode(int num) throws GameActionException { + rc.writeSharedArray(CHANNEL.ARCHON_MODE.getValue(), num); + } + + public int sendThreatAlert() throws GameActionException { + MapLocation my = rc.getLocation(); + int threatChannel = -1; + int threat_index = 0; + for (int i = 0; i < 4; i++) { + // rc.writeSharedArray(, value); + int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); + // go through channels until you find an empty one to communicate with. + int w = data / 4096; + int x = data / 64; + int y = data % 64; + // already alerted. + if (w == 1 && x == my.x && y == my.y) { + threatChannel = i; + threat_index++; + break; + } + // FAILURE POINT: if x and y aren't updated, then this will not work. + if (w == 0 && x == my.x && y == my.y && threatChannel == -1) { + threatChannel = i; + data = 1 * 4096 + locationToInt(my); + rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + threatChannel, data); + } + } + + return threat_index; + } + + public int totalUnderThreat() throws GameActionException { + int numThreatenedArchons = 0; + for (int i = 0; i < 4; i++) { + // rc.writeSharedArray(, value); + int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); + if ((data / 4096) != 0) + numThreatenedArchons++; + } + return numThreatenedArchons; + } + + public void clearArchonNumbers() throws GameActionException { + // if you don't read all 0s for the first four numbers, set them to zero. + if (rc.readSharedArray(CHANNEL.ARCHON_NUMBER.getValue()) != 0) { + rc.writeSharedArray(CHANNEL.ARCHON_NUMBER.getValue(), 0); + } + } + + public int getArchonNum() throws GameActionException { + int data = rc.readSharedArray(CHANNEL.ARCHON_NUMBER.getValue()); + int archonNumber = -1; + if (data == 0) { + rc.writeSharedArray(CHANNEL.ARCHON_NUMBER.getValue(), 1); + archonNumber = 0; + } else if (data == 1) { + rc.writeSharedArray(CHANNEL.ARCHON_NUMBER.getValue(), 2); + archonNumber = 1; + } else if (data == 2) { + rc.writeSharedArray(CHANNEL.ARCHON_NUMBER.getValue(), 3); + archonNumber = 2; + } else + archonNumber = 3; + if (archonNumber == rc.getArchonCount() - 1) + clearArchonNumbers(); + return archonNumber; + } + + public void postRank(RANK rank) throws GameActionException { + MapLocation loc = rc.getLocation(); + int loc_int; + if (rank == RANK.DEFAULT) { + return; + } else { + // all locations are within 60, so can be compressed to 6 bits. + loc_int = rank.getValue() * 4096 + locationToInt(loc); + if (rc.getRoundNum() % 2 == 0) { + rc.writeSharedArray(CHANNEL.SEND_RANKS1.getValue(), loc_int); + } else { + rc.writeSharedArray(CHANNEL.SEND_RANKS2.getValue(), loc_int); + } + } + } + + public void clearRanks() throws GameActionException { + if (rc.getRoundNum() % 2 == 0) { + rc.writeSharedArray(CHANNEL.SEND_RANKS1.getValue(), 0); + } else { + rc.writeSharedArray(CHANNEL.SEND_RANKS2.getValue(), 0); + } + } + + public int locationToInt(MapLocation loc) { + return 64 * loc.x + loc.y; + } +} \ No newline at end of file diff --git a/src/rebutia_micro_heal/Laboratory.java b/src/rebutia_micro_heal/Laboratory.java new file mode 100644 index 0000000..2519bd3 --- /dev/null +++ b/src/rebutia_micro_heal/Laboratory.java @@ -0,0 +1,12 @@ +package rebutia_micro_heal; + +import battlecode.common.*; +import java.util.*; + +public class Laboratory extends Unit { + public Laboratory(RobotController rc) throws GameActionException { + super(rc); + } + + public void run() throws GameActionException {} +} \ No newline at end of file diff --git a/src/rebutia_micro_heal/Miner.java b/src/rebutia_micro_heal/Miner.java new file mode 100644 index 0000000..ebdb1e2 --- /dev/null +++ b/src/rebutia_micro_heal/Miner.java @@ -0,0 +1,380 @@ +package rebutia_micro_heal; + +import battlecode.common.*; +import java.util.*; + +public class Miner extends Unit { + enum MODE { + EXPLORING, + MINE_DISCOVERED, + MINING, + FLEEING; + } + + int[] exploratoryDir; + int round_num; + MODE mode; + private MapLocation exploratoryTarget; + private MapLocation miningSpot; + private MapLocation target; + static MinerNav mNav; + private boolean isBroadcast; //whether the target you are pursuing was taken off broadcast + private int[] fleeDirection; + RANK rank; + private int stopFleeingRound = 10000; + private MapLocation deposit; + + public Miner(RobotController rc) throws GameActionException { + super(rc); + exploratoryDir = getExploratoryDir(7); + rank = findRankMiner(); + mNav = new MinerNav(rc); + } + @Override + public void run() throws GameActionException { + super.run(); + round_num = rc.getRoundNum(); + radio.updateCounter(); + int amountMined = mine(); + mode = getMode(amountMined); + switch (rank) { + case DEFAULT: + switch (mode) { + case EXPLORING: + moveInDirection(exploratoryDir); + break; + case MINE_DISCOVERED: + if (miningSpot != null) { + rc.setIndicatorLine(rc.getLocation(), miningSpot, 255, 0, 255); + moveToLocation(miningSpot); + } + else { + rc.setIndicatorLine(rc.getLocation(), target, 0, 0, 255); + moveToLocation(target); + } + break; + case FLEEING: + moveInDirection(fleeDirection); + break; + } + senseArchon(); + if (adjacentToEdge()) { + exploratoryDir = getExploratoryDir(7); + } + break; + default: + break; + } + amountMined+=mine(); + int deposit_value = senseMiningArea(); + int num_friends = numFriendlyMiners(2); + if (amountMined > 0) { + if (((double) deposit_value / (double) (num_friends + 1)) >= 15) { + radio.updateCounter(BiCHANNEL.USEFUL_MINERS); + } + } + rc.setIndicatorString(" " + mode + " " + amountMined + " " + target + " exploratoryDir: " + exploratoryDir[0] + " " + exploratoryDir[1]); + } + + public MapLocation findMiningSpot(MapLocation target) throws GameActionException { + int minRubble = 10000; + int rubble; + MapLocation[] leadLocs = rc.senseNearbyLocationsWithLead(target, 2, 2); + MapLocation bestSpot = null; + for (MapLocation leadLoc : leadLocs) { + MapLocation spot = mNav.findBestSquare(leadLoc, minRubble); + if (spot != null) { + rubble = rc.senseRubble(spot); + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = spot; + deposit = leadLoc; + } + } + } + return bestSpot; + } + public RANK findRankMiner() throws GameActionException{ + return RANK.DEFAULT; + } + + public MODE getMode(int amountMined) throws GameActionException { + int[] potFleeDirection = enemiesDetected(); + // if you just escaped an enemy, explore in a new direction + if (potFleeDirection == null && stopFleeingRound == round_num) exploratoryDir = getExploratoryDir(7); + + // if there are enemies nearby or there were recently, flee + if (potFleeDirection != null || stopFleeingRound <= round_num) { + // fleeDirection is official. + if (potFleeDirection != null) fleeDirection = potFleeDirection; + // keep fleeing for two moves (2 rounds per move) + if (stopFleeingRound <= round_num) { + stopFleeingRound = round_num + 4; + } + return MODE.FLEEING; + } + //check that you should still pursue + if (target!=null) { + if ((!isBroadcast && rc.canSenseLocation(target)) || (isBroadcast && rc.getLocation().distanceSquaredTo(target)<=10)) {//stricter distance requirements for a broadcast + if (getValue(target) <= 1 || occupiedWithMinerAlly(target)){ + rc.setIndicatorDot(target, 0, 255, 0); + target = null; + } + } + } + //choose location to pursue + if (target!=null){ + if (miningSpot == null && rc.getLocation().distanceSquaredTo(target) <= 9) { + miningSpot = findMiningSpot(target); + } + else { + if (deposit != null) { + if (rc.canSenseLocation(deposit)) { + if (getValue(deposit) <= 1) { + deposit = null; + miningSpot = findMiningSpot(target); + } + } + } + } + return MODE.MINE_DISCOVERED; + } + else { + miningSpot = null; + deposit = null; + MapLocation loc = findMiningAreaWithSensing(); + if (loc!=null){ + target = loc; + isBroadcast = false; + return MODE.MINE_DISCOVERED; + } + loc = findMiningAreaWithBroadcast(); + if (loc!=null){ + target = loc; + isBroadcast = true; + return MODE.MINE_DISCOVERED; + } + } + // + return MODE.EXPLORING; + } + public int[] enemiesDetected() throws GameActionException { + RobotInfo[] enemies = rc.senseNearbyRobots(-1, rc.getTeam().opponent()); + double cxs = 0; + double cys = 0; + double cxm = 0; + double cym = 0; + double numSoldiers = 0; + double numMiners = 0; + for (RobotInfo enemy: enemies) { + if (enemy.type == RobotType.SOLDIER) { + cxs += enemy.location.x; + cys += enemy.location.y; + numSoldiers++; + } + if (enemy.type == RobotType.MINER) { + cxm += enemy.location.x; + cym += enemy.location.y; + numMiners++; + } + } + if (numMiners > 0) { + cxm /= numMiners; + cym /= numMiners; + MapLocation enemy_center = new MapLocation((int)cxm, (int)cym); + // broadcastTarget(enemy_center); + } + if (numSoldiers > 0) { + cxs /= numSoldiers; + cys /= numSoldiers; + MapLocation enemy_center = new MapLocation((int)cxs, (int)cys); + broadcastTarget(enemy_center); + Direction d = rc.getLocation().directionTo(enemy_center).opposite(); + return new int[] {d.getDeltaX() * 5, d.getDeltaY() * 5}; + } + return null; + } + + public int getValue(MapLocation loc) throws GameActionException{ + return rc.senseGold(loc) * goldToLeadConversionRate + rc.senseLead(loc); + } + + public boolean occupiedWithMinerAlly(MapLocation loc) throws GameActionException{ + if (rc.getLocation().equals(loc)) return false; + RobotInfo r = rc.senseRobotAtLocation(loc); + if (r!= null && r.team == rc.getTeam() && r.type == RobotType.MINER){ + return true; + } + else return false; + } + + public boolean isMiningArea(MapLocation loc) throws GameActionException{ + for (int i = 0; i < 5; i++){ + int data = rc.readSharedArray(CHANNEL.MINING1.getValue()+i); + if (data != 0) { + int x = data / 64; + int y = data % 64; + MapLocation dest = new MapLocation(x, y); + if (dest.equals(loc)) return true; //within range + } + } + return false; + } + + public MapLocation findMiningAreaWithSensing() throws GameActionException{ + int maxRes = 1; + MapLocation[] goldLocs = rc.senseNearbyLocationsWithGold(); + MapLocation[] leadLocs = rc.senseNearbyLocationsWithLead(rc.getType().visionRadiusSquared, 2); + MapLocation bestLocation = null; + + for (MapLocation loc: goldLocs) { + if (!occupiedWithMinerAlly(loc)){ + int res = getValue(loc) + rng.nextInt(5); + if (res > maxRes) { + maxRes = res; + bestLocation = loc; + } + } + } + + for (MapLocation loc: leadLocs) { + if (!occupiedWithMinerAlly(loc)){ + int res = getValue(loc)+ rng.nextInt(5); + if (res > maxRes) { + maxRes = res; + bestLocation = loc; + } + } + } + + // if our best location is outside of the mining range, return it + if (maxRes >=1 && bestLocation != null) { + return bestLocation; + } + + return null; + } + + + + static final int[] dx = {0, 0, 0, 1, 1, 1, -1,-1, -1}; + static final int[] dy = {0, 1, -1, 0, 1, -1, 0, 1, -1}; + public MapLocation findMiningAreaWithSensingIntensive() throws GameActionException{ //currently too bytecode intensive + int maxRes = 1; + MapLocation bestLocation = null; + + MapLocation my = rc.getLocation(); + //look at surrounding area + MapLocation[] goldLocs = rc.senseNearbyLocationsWithGold(); + MapLocation[] leadLocs = rc.senseNearbyLocationsWithLead(rc.getType().visionRadiusSquared, 2); + + int[][] value = new int[9][9]; + for (MapLocation loc: goldLocs) { + int x = (loc.x-my.x)+4; + int y = (loc.y-my.y)+4; + assert(x >= 0 && x < 9 && y>=0 && y < 9); + int upd = rc.senseGold(loc)*goldToLeadConversionRate; + for (int i= 0; i < dx.length; i++){ + int nx = x + dx[i]; + int ny = y + dy[i]; + + if (nx >=0 && nx < 9 && ny >=0 && ny < 9) value[nx][ny] += upd; + } + + } + + for (MapLocation loc: leadLocs) { + int x = (loc.x-my.x)+4; + int y = (loc.y-my.y)+4; + assert(x >= 0 && x < 9 && y>=0 && y < 9); + int upd = rc.senseLead(loc) - 1; + for (int i= 0; i < dx.length; i++){ + int nx = x + dx[i]; + int ny = y + dy[i]; + + if (nx >=0 && nx < 9 && ny >=0 && ny < 9) value[nx][ny] += upd; + } + } + + for (int i = 0; i < 9; i++){ + for (int j = 0; j < 9; j++){ + MapLocation loc = new MapLocation(my.x + (i -4), my.y +(j-4)); + if (value[i][j] > maxRes) { + maxRes = value[i][j]; + bestLocation = loc; + } + } + } + + if (maxRes >=1 && bestLocation != null) { + return bestLocation; + } + + return null; + } + + public MapLocation findMiningAreaWithBroadcast() throws GameActionException{ + int maxRes = 1; + MapLocation bestLocation = null; + int channel = -1; + + MapLocation my = rc.getLocation(); + + //look at the channels + for (int i = 0; i < 5; i++){ + int data = rc.readSharedArray(CHANNEL.MINING1.getValue()+i); + if (data != 0) { + int demand = (data >> 8) & 255; + int x = (data >> 4) & 15; + int y = data & 15; + MapLocation dest = new MapLocation(Math.min(x*4, rc.getMapWidth() - 1), Math.min(y*4, rc.getMapHeight() - 1)); + // System.out.println("Recieved miner request: " + x*4 + " " + y*4 + " " + demand); + int res = minerToLeadRate*demand; + if (my.distanceSquaredTo(dest) < 300 && res > maxRes && demand > 0) { //within range //TODO: add not fulfilled + maxRes = res; + bestLocation = dest; + channel = i; + } + } + } + + if (maxRes >=1 && bestLocation != null) { + //reduce demand + int data = rc.readSharedArray(CHANNEL.MINING1.getValue()+channel); + int demand = ((data >> 8) & 255) - 1; + int x = (data >> 4) & 15; + int y = data & 15; + // System.out.println("Taking miner request: " + x*4 + " " + y*4 + " " + demand); + rc.writeSharedArray(CHANNEL.MINING1.getValue()+channel,(demand << 8) + (x << 4) + y); + return bestLocation; + } + + return null; + } + /** + * mine() mines the surrounding area + * @return int representing total value of what was mined + **/ + public int mine() throws GameActionException{ + //prioritize gold + int amountMined = 0; + for (MapLocation loc : rc.senseNearbyLocationsWithGold(RobotType.MINER.actionRadiusSquared)) { + // Notice that the Miner's action cooldown is very low. + // You can mine multiple times per turn! + while (rc.canMineGold(loc)) { + rc.mineGold(loc); + amountMined += goldToLeadConversionRate; + } + } + //then go to lead + for (MapLocation loc : rc.senseNearbyLocationsWithLead(RobotType.MINER.actionRadiusSquared)) { + // Notice that the Miner's action cooldown is very low. + // You can mine multiple times per turn; + while (rc.canMineLead(loc) && rc.senseLead(loc) > 1) { + rc.mineLead(loc); + amountMined+=1; + } + } + return amountMined; + } +} diff --git a/src/rebutia_micro_heal/MinerNav.java b/src/rebutia_micro_heal/MinerNav.java new file mode 100644 index 0000000..6ad1234 --- /dev/null +++ b/src/rebutia_micro_heal/MinerNav.java @@ -0,0 +1,87 @@ +package rebutia_micro_heal; + +import battlecode.common.*; +public class MinerNav { + static RobotController rc; + MinerNav(RobotController rc) { + this.rc = rc; + } + static MapLocation loc0; + static MapLocation loc1; + static MapLocation loc2; + static MapLocation loc3; + static MapLocation loc4; + static MapLocation loc5; + static MapLocation loc6; + static MapLocation loc7; + static MapLocation bestSpot; + int rubble; + MapLocation findBestSquare(MapLocation leadLoc, int minRubble) throws GameActionException{ + loc0 = leadLoc.add(Direction.EAST); + loc1 = leadLoc.add(Direction.WEST); + loc2 = leadLoc.add(Direction.SOUTH); + loc3 = leadLoc.add(Direction.NORTH); + loc4 = leadLoc.add(Direction.NORTHEAST); + loc5 = leadLoc.add(Direction.NORTHWEST); + loc6 = leadLoc.add(Direction.SOUTHEAST); + loc7 = leadLoc.add(Direction.SOUTHWEST); + if (rc.canSenseLocation(loc0)) { + rubble = 1 + rc.senseRubble(loc0) / 10; + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = loc0; + } + } + if (rc.canSenseLocation(loc1)) { + rubble = 1 + rc.senseRubble(loc1) / 10; + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = loc1; + } + } + if (rc.canSenseLocation(loc2)) { + rubble = 1 + rc.senseRubble(loc2) / 10; + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = loc2; + } + } + if (rc.canSenseLocation(loc3)) { + rubble = 1 + rc.senseRubble(loc3) / 10; + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = loc3; + } + } + if (rc.canSenseLocation(loc4)) { + rubble = 1 + rc.senseRubble(loc4) / 10; + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = loc4; + } + } + if (rc.canSenseLocation(loc5)) { + rubble = 1 + rc.senseRubble(loc5) / 10; + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = loc5; + } + } + if (rc.canSenseLocation(loc6)) { + rubble = 1 + rc.senseRubble(loc6) / 10; + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = loc6; + } + } + if (rc.canSenseLocation(loc7)) { + rubble = 1 + rc.senseRubble(loc7) / 10; + if (rubble < minRubble) { + minRubble = rubble; + bestSpot = loc7; + } + } + return bestSpot; + } +} + diff --git a/src/rebutia_micro_heal/Navigation.java b/src/rebutia_micro_heal/Navigation.java new file mode 100644 index 0000000..709d39f --- /dev/null +++ b/src/rebutia_micro_heal/Navigation.java @@ -0,0 +1,2016 @@ +package rebutia_micro_heal; +import battlecode.common.*; +public class Navigation { + static RobotController rc; + static int cooldown; + Navigation(RobotController rc) { + this.rc= rc; + this.cooldown= rc.getType().movementCooldown; + } + + static MapLocation l84; + static double v84; + static Direction d84; + static double p84; + + static MapLocation l71; + static double v71; + static Direction d71; + static double p71; + + static MapLocation l83; + static double v83; + static Direction d83; + static double p83; + + static MapLocation l85; + static double v85; + static Direction d85; + static double p85; + + static MapLocation l97; + static double v97; + static Direction d97; + static double p97; + + static MapLocation l70; + static double v70; + static Direction d70; + static double p70; + + static MapLocation l72; + static double v72; + static Direction d72; + static double p72; + + static MapLocation l96; + static double v96; + static Direction d96; + static double p96; + + static MapLocation l98; + static double v98; + static Direction d98; + static double p98; + + static MapLocation l58; + static double v58; + static Direction d58; + static double p58; + + static MapLocation l82; + static double v82; + static Direction d82; + static double p82; + + static MapLocation l86; + static double v86; + static Direction d86; + static double p86; + + static MapLocation l110; + static double v110; + static Direction d110; + static double p110; + + static MapLocation l57; + static double v57; + static Direction d57; + static double p57; + + static MapLocation l59; + static double v59; + static Direction d59; + static double p59; + + static MapLocation l69; + static double v69; + static Direction d69; + static double p69; + + static MapLocation l73; + static double v73; + static Direction d73; + static double p73; + + static MapLocation l95; + static double v95; + static Direction d95; + static double p95; + + static MapLocation l99; + static double v99; + static Direction d99; + static double p99; + + static MapLocation l109; + static double v109; + static Direction d109; + static double p109; + + static MapLocation l111; + static double v111; + static Direction d111; + static double p111; + + static MapLocation l56; + static double v56; + static Direction d56; + static double p56; + + static MapLocation l60; + static double v60; + static Direction d60; + static double p60; + + static MapLocation l108; + static double v108; + static Direction d108; + static double p108; + + static MapLocation l112; + static double v112; + static Direction d112; + static double p112; + + static MapLocation l45; + static double v45; + static Direction d45; + static double p45; + + static MapLocation l81; + static double v81; + static Direction d81; + static double p81; + + static MapLocation l87; + static double v87; + static Direction d87; + static double p87; + + static MapLocation l123; + static double v123; + static Direction d123; + static double p123; + + static MapLocation l44; + static double v44; + static Direction d44; + static double p44; + + static MapLocation l46; + static double v46; + static Direction d46; + static double p46; + + static MapLocation l68; + static double v68; + static Direction d68; + static double p68; + + static MapLocation l74; + static double v74; + static Direction d74; + static double p74; + + static MapLocation l94; + static double v94; + static Direction d94; + static double p94; + + static MapLocation l100; + static double v100; + static Direction d100; + static double p100; + + static MapLocation l122; + static double v122; + static Direction d122; + static double p122; + + static MapLocation l124; + static double v124; + static Direction d124; + static double p124; + + static MapLocation l43; + static double v43; + static Direction d43; + static double p43; + + static MapLocation l47; + static double v47; + static Direction d47; + static double p47; + + static MapLocation l55; + static double v55; + static Direction d55; + static double p55; + + static MapLocation l61; + static double v61; + static Direction d61; + static double p61; + + static MapLocation l107; + static double v107; + static Direction d107; + static double p107; + + static MapLocation l113; + static double v113; + static Direction d113; + static double p113; + + static MapLocation l121; + static double v121; + static Direction d121; + static double p121; + + static MapLocation l125; + static double v125; + static Direction d125; + static double p125; + + static MapLocation l32; + static double v32; + static Direction d32; + static double p32; + + static MapLocation l80; + static double v80; + static Direction d80; + static double p80; + + static MapLocation l88; + static double v88; + static Direction d88; + static double p88; + + static MapLocation l136; + static double v136; + static Direction d136; + static double p136; + + static MapLocation l31; + static double v31; + static Direction d31; + static double p31; + + static MapLocation l33; + static double v33; + static Direction d33; + static double p33; + + static MapLocation l67; + static double v67; + static Direction d67; + static double p67; + + static MapLocation l75; + static double v75; + static Direction d75; + static double p75; + + static MapLocation l93; + static double v93; + static Direction d93; + static double p93; + + static MapLocation l101; + static double v101; + static Direction d101; + static double p101; + + static MapLocation l135; + static double v135; + static Direction d135; + static double p135; + + static MapLocation l137; + static double v137; + static Direction d137; + static double p137; + + static MapLocation l42; + static double v42; + static Direction d42; + static double p42; + + static MapLocation l48; + static double v48; + static Direction d48; + static double p48; + + static MapLocation l120; + static double v120; + static Direction d120; + static double p120; + + static MapLocation l126; + static double v126; + static Direction d126; + static double p126; + + static MapLocation l30; + static double v30; + static Direction d30; + static double p30; + + static MapLocation l34; + static double v34; + static Direction d34; + static double p34; + + static MapLocation l54; + static double v54; + static Direction d54; + static double p54; + + static MapLocation l62; + static double v62; + static Direction d62; + static double p62; + + static MapLocation l106; + static double v106; + static Direction d106; + static double p106; + + static MapLocation l114; + static double v114; + static Direction d114; + static double p114; + + static MapLocation l134; + static double v134; + static Direction d134; + static double p134; + + static MapLocation l138; + static double v138; + static Direction d138; + static double p138; + + + Direction getBestDir(MapLocation target) throws GameActionException{ + l84 = rc.getLocation(); + v84 = 0; + l71 = l84.add(Direction.SOUTH); + v71 = 1000000; + d71 = null; + l83 = l84.add(Direction.WEST); + v83 = 1000000; + d83 = null; + l85 = l84.add(Direction.EAST); + v85 = 1000000; + d85 = null; + l97 = l84.add(Direction.NORTH); + v97 = 1000000; + d97 = null; + l70 = l84.add(Direction.SOUTHWEST); + v70 = 1000000; + d70 = null; + l72 = l84.add(Direction.SOUTHEAST); + v72 = 1000000; + d72 = null; + l96 = l84.add(Direction.NORTHWEST); + v96 = 1000000; + d96 = null; + l98 = l84.add(Direction.NORTHEAST); + v98 = 1000000; + d98 = null; + l58 = l71.add(Direction.SOUTH); + v58 = 1000000; + d58 = null; + l82 = l83.add(Direction.WEST); + v82 = 1000000; + d82 = null; + l86 = l85.add(Direction.EAST); + v86 = 1000000; + d86 = null; + l110 = l97.add(Direction.NORTH); + v110 = 1000000; + d110 = null; + l57 = l71.add(Direction.SOUTHWEST); + v57 = 1000000; + d57 = null; + l59 = l71.add(Direction.SOUTHEAST); + v59 = 1000000; + d59 = null; + l69 = l83.add(Direction.SOUTHWEST); + v69 = 1000000; + d69 = null; + l73 = l85.add(Direction.SOUTHEAST); + v73 = 1000000; + d73 = null; + l95 = l83.add(Direction.NORTHWEST); + v95 = 1000000; + d95 = null; + l99 = l85.add(Direction.NORTHEAST); + v99 = 1000000; + d99 = null; + l109 = l97.add(Direction.NORTHWEST); + v109 = 1000000; + d109 = null; + l111 = l97.add(Direction.NORTHEAST); + v111 = 1000000; + d111 = null; + l56 = l70.add(Direction.SOUTHWEST); + v56 = 1000000; + d56 = null; + l60 = l72.add(Direction.SOUTHEAST); + v60 = 1000000; + d60 = null; + l108 = l96.add(Direction.NORTHWEST); + v108 = 1000000; + d108 = null; + l112 = l98.add(Direction.NORTHEAST); + v112 = 1000000; + d112 = null; + l45 = l58.add(Direction.SOUTH); + v45 = 1000000; + d45 = null; + l81 = l82.add(Direction.WEST); + v81 = 1000000; + d81 = null; + l87 = l86.add(Direction.EAST); + v87 = 1000000; + d87 = null; + l123 = l110.add(Direction.NORTH); + v123 = 1000000; + d123 = null; + l44 = l58.add(Direction.SOUTHWEST); + v44 = 1000000; + d44 = null; + l46 = l58.add(Direction.SOUTHEAST); + v46 = 1000000; + d46 = null; + l68 = l82.add(Direction.SOUTHWEST); + v68 = 1000000; + d68 = null; + l74 = l86.add(Direction.SOUTHEAST); + v74 = 1000000; + d74 = null; + l94 = l82.add(Direction.NORTHWEST); + v94 = 1000000; + d94 = null; + l100 = l86.add(Direction.NORTHEAST); + v100 = 1000000; + d100 = null; + l122 = l110.add(Direction.NORTHWEST); + v122 = 1000000; + d122 = null; + l124 = l110.add(Direction.NORTHEAST); + v124 = 1000000; + d124 = null; + l43 = l57.add(Direction.SOUTHWEST); + v43 = 1000000; + d43 = null; + l47 = l59.add(Direction.SOUTHEAST); + v47 = 1000000; + d47 = null; + l55 = l69.add(Direction.SOUTHWEST); + v55 = 1000000; + d55 = null; + l61 = l73.add(Direction.SOUTHEAST); + v61 = 1000000; + d61 = null; + l107 = l95.add(Direction.NORTHWEST); + v107 = 1000000; + d107 = null; + l113 = l99.add(Direction.NORTHEAST); + v113 = 1000000; + d113 = null; + l121 = l109.add(Direction.NORTHWEST); + v121 = 1000000; + d121 = null; + l125 = l111.add(Direction.NORTHEAST); + v125 = 1000000; + d125 = null; + l32 = l45.add(Direction.SOUTH); + v32 = 1000000; + d32 = null; + l80 = l81.add(Direction.WEST); + v80 = 1000000; + d80 = null; + l88 = l87.add(Direction.EAST); + v88 = 1000000; + d88 = null; + l136 = l123.add(Direction.NORTH); + v136 = 1000000; + d136 = null; + l31 = l45.add(Direction.SOUTHWEST); + v31 = 1000000; + d31 = null; + l33 = l45.add(Direction.SOUTHEAST); + v33 = 1000000; + d33 = null; + l67 = l81.add(Direction.SOUTHWEST); + v67 = 1000000; + d67 = null; + l75 = l87.add(Direction.SOUTHEAST); + v75 = 1000000; + d75 = null; + l93 = l81.add(Direction.NORTHWEST); + v93 = 1000000; + d93 = null; + l101 = l87.add(Direction.NORTHEAST); + v101 = 1000000; + d101 = null; + l135 = l123.add(Direction.NORTHWEST); + v135 = 1000000; + d135 = null; + l137 = l123.add(Direction.NORTHEAST); + v137 = 1000000; + d137 = null; + l42 = l56.add(Direction.SOUTHWEST); + v42 = 1000000; + d42 = null; + l48 = l60.add(Direction.SOUTHEAST); + v48 = 1000000; + d48 = null; + l120 = l108.add(Direction.NORTHWEST); + v120 = 1000000; + d120 = null; + l126 = l112.add(Direction.NORTHEAST); + v126 = 1000000; + d126 = null; + l30 = l44.add(Direction.SOUTHWEST); + v30 = 1000000; + d30 = null; + l34 = l46.add(Direction.SOUTHEAST); + v34 = 1000000; + d34 = null; + l54 = l68.add(Direction.SOUTHWEST); + v54 = 1000000; + d54 = null; + l62 = l74.add(Direction.SOUTHEAST); + v62 = 1000000; + d62 = null; + l106 = l94.add(Direction.NORTHWEST); + v106 = 1000000; + d106 = null; + l114 = l100.add(Direction.NORTHEAST); + v114 = 1000000; + d114 = null; + l134 = l122.add(Direction.NORTHWEST); + v134 = 1000000; + d134 = null; + l138 = l124.add(Direction.NORTHEAST); + v138 = 1000000; + d138 = null; + if (rc.onTheMap(l71)) { + if (!rc.isLocationOccupied(l71)) { + p71 = Math.floor((1.0 + (double)rc.senseRubble(l71)/10.0)*cooldown); + if (v71 > v84 + p71) { + v71 = v84 + p71; + d71 = Direction.SOUTH; + } + } + } + if (rc.onTheMap(l83)) { + if (!rc.isLocationOccupied(l83)) { + p83 = Math.floor((1.0 + (double)rc.senseRubble(l83)/10.0)*cooldown); + if (v83 > v84 + p83) { + v83 = v84 + p83; + d83 = Direction.WEST; + } + if (v83 > v71 + p83) { + v83 = v71 + p83; + d83 = d71; + } + } + } + if (rc.onTheMap(l85)) { + if (!rc.isLocationOccupied(l85)) { + p85 = Math.floor((1.0 + (double)rc.senseRubble(l85)/10.0)*cooldown); + if (v85 > v84 + p85) { + v85 = v84 + p85; + d85 = Direction.EAST; + } + if (v85 > v71 + p85) { + v85 = v71 + p85; + d85 = d71; + } + } + } + if (rc.onTheMap(l97)) { + if (!rc.isLocationOccupied(l97)) { + p97 = Math.floor((1.0 + (double)rc.senseRubble(l97)/10.0)*cooldown); + if (v97 > v84 + p97) { + v97 = v84 + p97; + d97 = Direction.NORTH; + } + if (v97 > v83 + p97) { + v97 = v83 + p97; + d97 = d83; + } + if (v97 > v85 + p97) { + v97 = v85 + p97; + d97 = d85; + } + } + } + if (rc.onTheMap(l70)) { + if (!rc.isLocationOccupied(l70)) { + p70 = Math.floor((1.0 + (double)rc.senseRubble(l70)/10.0)*cooldown); + if (v70 > v84 + p70) { + v70 = v84 + p70; + d70 = Direction.SOUTHWEST; + } + if (v70 > v71 + p70) { + v70 = v71 + p70; + d70 = d71; + } + if (v70 > v83 + p70) { + v70 = v83 + p70; + d70 = d83; + } + } + } + if (rc.onTheMap(l72)) { + if (!rc.isLocationOccupied(l72)) { + p72 = Math.floor((1.0 + (double)rc.senseRubble(l72)/10.0)*cooldown); + if (v72 > v84 + p72) { + v72 = v84 + p72; + d72 = Direction.SOUTHEAST; + } + if (v72 > v71 + p72) { + v72 = v71 + p72; + d72 = d71; + } + if (v72 > v85 + p72) { + v72 = v85 + p72; + d72 = d85; + } + } + } + if (rc.onTheMap(l96)) { + if (!rc.isLocationOccupied(l96)) { + p96 = Math.floor((1.0 + (double)rc.senseRubble(l96)/10.0)*cooldown); + if (v96 > v84 + p96) { + v96 = v84 + p96; + d96 = Direction.NORTHWEST; + } + if (v96 > v83 + p96) { + v96 = v83 + p96; + d96 = d83; + } + if (v96 > v97 + p96) { + v96 = v97 + p96; + d96 = d97; + } + } + } + if (rc.onTheMap(l98)) { + if (!rc.isLocationOccupied(l98)) { + p98 = Math.floor((1.0 + (double)rc.senseRubble(l98)/10.0)*cooldown); + if (v98 > v84 + p98) { + v98 = v84 + p98; + d98 = Direction.NORTHEAST; + } + if (v98 > v85 + p98) { + v98 = v85 + p98; + d98 = d85; + } + if (v98 > v97 + p98) { + v98 = v97 + p98; + d98 = d97; + } + } + } + if (rc.onTheMap(l58)) { + p58 = Math.floor((1.0 + (double)rc.senseRubble(l58)/10.0)*cooldown); + if (v58 > v71 + p58) { + v58 = v71 + p58; + d58 = d71; + } + if (v58 > v70 + p58) { + v58 = v70 + p58; + d58 = d70; + } + if (v58 > v72 + p58) { + v58 = v72 + p58; + d58 = d72; + } + } + if (rc.onTheMap(l82)) { + p82 = Math.floor((1.0 + (double)rc.senseRubble(l82)/10.0)*cooldown); + if (v82 > v83 + p82) { + v82 = v83 + p82; + d82 = d83; + } + if (v82 > v70 + p82) { + v82 = v70 + p82; + d82 = d70; + } + if (v82 > v96 + p82) { + v82 = v96 + p82; + d82 = d96; + } + } + if (rc.onTheMap(l86)) { + p86 = Math.floor((1.0 + (double)rc.senseRubble(l86)/10.0)*cooldown); + if (v86 > v85 + p86) { + v86 = v85 + p86; + d86 = d85; + } + if (v86 > v72 + p86) { + v86 = v72 + p86; + d86 = d72; + } + if (v86 > v98 + p86) { + v86 = v98 + p86; + d86 = d98; + } + } + if (rc.onTheMap(l110)) { + p110 = Math.floor((1.0 + (double)rc.senseRubble(l110)/10.0)*cooldown); + if (v110 > v97 + p110) { + v110 = v97 + p110; + d110 = d97; + } + if (v110 > v96 + p110) { + v110 = v96 + p110; + d110 = d96; + } + if (v110 > v98 + p110) { + v110 = v98 + p110; + d110 = d98; + } + } + if (rc.onTheMap(l57)) { + p57 = Math.floor((1.0 + (double)rc.senseRubble(l57)/10.0)*cooldown); + if (v57 > v71 + p57) { + v57 = v71 + p57; + d57 = d71; + } + if (v57 > v70 + p57) { + v57 = v70 + p57; + d57 = d70; + } + if (v57 > v58 + p57) { + v57 = v58 + p57; + d57 = d58; + } + } + if (rc.onTheMap(l59)) { + p59 = Math.floor((1.0 + (double)rc.senseRubble(l59)/10.0)*cooldown); + if (v59 > v71 + p59) { + v59 = v71 + p59; + d59 = d71; + } + if (v59 > v72 + p59) { + v59 = v72 + p59; + d59 = d72; + } + if (v59 > v58 + p59) { + v59 = v58 + p59; + d59 = d58; + } + } + if (rc.onTheMap(l69)) { + p69 = Math.floor((1.0 + (double)rc.senseRubble(l69)/10.0)*cooldown); + if (v69 > v83 + p69) { + v69 = v83 + p69; + d69 = d83; + } + if (v69 > v70 + p69) { + v69 = v70 + p69; + d69 = d70; + } + if (v69 > v82 + p69) { + v69 = v82 + p69; + d69 = d82; + } + if (v69 > v57 + p69) { + v69 = v57 + p69; + d69 = d57; + } + } + if (rc.onTheMap(l73)) { + p73 = Math.floor((1.0 + (double)rc.senseRubble(l73)/10.0)*cooldown); + if (v73 > v85 + p73) { + v73 = v85 + p73; + d73 = d85; + } + if (v73 > v72 + p73) { + v73 = v72 + p73; + d73 = d72; + } + if (v73 > v86 + p73) { + v73 = v86 + p73; + d73 = d86; + } + if (v73 > v59 + p73) { + v73 = v59 + p73; + d73 = d59; + } + } + if (rc.onTheMap(l95)) { + p95 = Math.floor((1.0 + (double)rc.senseRubble(l95)/10.0)*cooldown); + if (v95 > v83 + p95) { + v95 = v83 + p95; + d95 = d83; + } + if (v95 > v96 + p95) { + v95 = v96 + p95; + d95 = d96; + } + if (v95 > v82 + p95) { + v95 = v82 + p95; + d95 = d82; + } + } + if (rc.onTheMap(l99)) { + p99 = Math.floor((1.0 + (double)rc.senseRubble(l99)/10.0)*cooldown); + if (v99 > v85 + p99) { + v99 = v85 + p99; + d99 = d85; + } + if (v99 > v98 + p99) { + v99 = v98 + p99; + d99 = d98; + } + if (v99 > v86 + p99) { + v99 = v86 + p99; + d99 = d86; + } + } + if (rc.onTheMap(l109)) { + p109 = Math.floor((1.0 + (double)rc.senseRubble(l109)/10.0)*cooldown); + if (v109 > v97 + p109) { + v109 = v97 + p109; + d109 = d97; + } + if (v109 > v96 + p109) { + v109 = v96 + p109; + d109 = d96; + } + if (v109 > v110 + p109) { + v109 = v110 + p109; + d109 = d110; + } + if (v109 > v95 + p109) { + v109 = v95 + p109; + d109 = d95; + } + } + if (rc.onTheMap(l111)) { + p111 = Math.floor((1.0 + (double)rc.senseRubble(l111)/10.0)*cooldown); + if (v111 > v97 + p111) { + v111 = v97 + p111; + d111 = d97; + } + if (v111 > v98 + p111) { + v111 = v98 + p111; + d111 = d98; + } + if (v111 > v110 + p111) { + v111 = v110 + p111; + d111 = d110; + } + if (v111 > v99 + p111) { + v111 = v99 + p111; + d111 = d99; + } + } + if (rc.onTheMap(l56)) { + p56 = Math.floor((1.0 + (double)rc.senseRubble(l56)/10.0)*cooldown); + if (v56 > v70 + p56) { + v56 = v70 + p56; + d56 = d70; + } + if (v56 > v57 + p56) { + v56 = v57 + p56; + d56 = d57; + } + if (v56 > v69 + p56) { + v56 = v69 + p56; + d56 = d69; + } + } + if (rc.onTheMap(l60)) { + p60 = Math.floor((1.0 + (double)rc.senseRubble(l60)/10.0)*cooldown); + if (v60 > v72 + p60) { + v60 = v72 + p60; + d60 = d72; + } + if (v60 > v59 + p60) { + v60 = v59 + p60; + d60 = d59; + } + if (v60 > v73 + p60) { + v60 = v73 + p60; + d60 = d73; + } + } + if (rc.onTheMap(l108)) { + p108 = Math.floor((1.0 + (double)rc.senseRubble(l108)/10.0)*cooldown); + if (v108 > v96 + p108) { + v108 = v96 + p108; + d108 = d96; + } + if (v108 > v95 + p108) { + v108 = v95 + p108; + d108 = d95; + } + if (v108 > v109 + p108) { + v108 = v109 + p108; + d108 = d109; + } + } + if (rc.onTheMap(l112)) { + p112 = Math.floor((1.0 + (double)rc.senseRubble(l112)/10.0)*cooldown); + if (v112 > v98 + p112) { + v112 = v98 + p112; + d112 = d98; + } + if (v112 > v99 + p112) { + v112 = v99 + p112; + d112 = d99; + } + if (v112 > v111 + p112) { + v112 = v111 + p112; + d112 = d111; + } + } + if (rc.onTheMap(l45)) { + p45 = Math.floor((1.0 + (double)rc.senseRubble(l45)/10.0)*cooldown); + if (v45 > v58 + p45) { + v45 = v58 + p45; + d45 = d58; + } + if (v45 > v57 + p45) { + v45 = v57 + p45; + d45 = d57; + } + if (v45 > v59 + p45) { + v45 = v59 + p45; + d45 = d59; + } + } + if (rc.onTheMap(l81)) { + p81 = Math.floor((1.0 + (double)rc.senseRubble(l81)/10.0)*cooldown); + if (v81 > v82 + p81) { + v81 = v82 + p81; + d81 = d82; + } + if (v81 > v69 + p81) { + v81 = v69 + p81; + d81 = d69; + } + if (v81 > v95 + p81) { + v81 = v95 + p81; + d81 = d95; + } + } + if (rc.onTheMap(l87)) { + p87 = Math.floor((1.0 + (double)rc.senseRubble(l87)/10.0)*cooldown); + if (v87 > v86 + p87) { + v87 = v86 + p87; + d87 = d86; + } + if (v87 > v73 + p87) { + v87 = v73 + p87; + d87 = d73; + } + if (v87 > v99 + p87) { + v87 = v99 + p87; + d87 = d99; + } + } + if (rc.onTheMap(l123)) { + p123 = Math.floor((1.0 + (double)rc.senseRubble(l123)/10.0)*cooldown); + if (v123 > v110 + p123) { + v123 = v110 + p123; + d123 = d110; + } + if (v123 > v109 + p123) { + v123 = v109 + p123; + d123 = d109; + } + if (v123 > v111 + p123) { + v123 = v111 + p123; + d123 = d111; + } + } + if (rc.onTheMap(l44)) { + p44 = Math.floor((1.0 + (double)rc.senseRubble(l44)/10.0)*cooldown); + if (v44 > v58 + p44) { + v44 = v58 + p44; + d44 = d58; + } + if (v44 > v57 + p44) { + v44 = v57 + p44; + d44 = d57; + } + if (v44 > v56 + p44) { + v44 = v56 + p44; + d44 = d56; + } + if (v44 > v45 + p44) { + v44 = v45 + p44; + d44 = d45; + } + } + if (rc.onTheMap(l46)) { + p46 = Math.floor((1.0 + (double)rc.senseRubble(l46)/10.0)*cooldown); + if (v46 > v58 + p46) { + v46 = v58 + p46; + d46 = d58; + } + if (v46 > v59 + p46) { + v46 = v59 + p46; + d46 = d59; + } + if (v46 > v60 + p46) { + v46 = v60 + p46; + d46 = d60; + } + if (v46 > v45 + p46) { + v46 = v45 + p46; + d46 = d45; + } + } + if (rc.onTheMap(l68)) { + p68 = Math.floor((1.0 + (double)rc.senseRubble(l68)/10.0)*cooldown); + if (v68 > v82 + p68) { + v68 = v82 + p68; + d68 = d82; + } + if (v68 > v69 + p68) { + v68 = v69 + p68; + d68 = d69; + } + if (v68 > v56 + p68) { + v68 = v56 + p68; + d68 = d56; + } + if (v68 > v81 + p68) { + v68 = v81 + p68; + d68 = d81; + } + } + if (rc.onTheMap(l74)) { + p74 = Math.floor((1.0 + (double)rc.senseRubble(l74)/10.0)*cooldown); + if (v74 > v86 + p74) { + v74 = v86 + p74; + d74 = d86; + } + if (v74 > v73 + p74) { + v74 = v73 + p74; + d74 = d73; + } + if (v74 > v60 + p74) { + v74 = v60 + p74; + d74 = d60; + } + if (v74 > v87 + p74) { + v74 = v87 + p74; + d74 = d87; + } + } + if (rc.onTheMap(l94)) { + p94 = Math.floor((1.0 + (double)rc.senseRubble(l94)/10.0)*cooldown); + if (v94 > v82 + p94) { + v94 = v82 + p94; + d94 = d82; + } + if (v94 > v95 + p94) { + v94 = v95 + p94; + d94 = d95; + } + if (v94 > v108 + p94) { + v94 = v108 + p94; + d94 = d108; + } + if (v94 > v81 + p94) { + v94 = v81 + p94; + d94 = d81; + } + } + if (rc.onTheMap(l100)) { + p100 = Math.floor((1.0 + (double)rc.senseRubble(l100)/10.0)*cooldown); + if (v100 > v86 + p100) { + v100 = v86 + p100; + d100 = d86; + } + if (v100 > v99 + p100) { + v100 = v99 + p100; + d100 = d99; + } + if (v100 > v112 + p100) { + v100 = v112 + p100; + d100 = d112; + } + if (v100 > v87 + p100) { + v100 = v87 + p100; + d100 = d87; + } + } + if (rc.onTheMap(l122)) { + p122 = Math.floor((1.0 + (double)rc.senseRubble(l122)/10.0)*cooldown); + if (v122 > v110 + p122) { + v122 = v110 + p122; + d122 = d110; + } + if (v122 > v109 + p122) { + v122 = v109 + p122; + d122 = d109; + } + if (v122 > v108 + p122) { + v122 = v108 + p122; + d122 = d108; + } + if (v122 > v123 + p122) { + v122 = v123 + p122; + d122 = d123; + } + } + if (rc.onTheMap(l124)) { + p124 = Math.floor((1.0 + (double)rc.senseRubble(l124)/10.0)*cooldown); + if (v124 > v110 + p124) { + v124 = v110 + p124; + d124 = d110; + } + if (v124 > v111 + p124) { + v124 = v111 + p124; + d124 = d111; + } + if (v124 > v112 + p124) { + v124 = v112 + p124; + d124 = d112; + } + if (v124 > v123 + p124) { + v124 = v123 + p124; + d124 = d123; + } + } + if (rc.onTheMap(l43)) { + p43 = Math.floor((1.0 + (double)rc.senseRubble(l43)/10.0)*cooldown); + if (v43 > v57 + p43) { + v43 = v57 + p43; + d43 = d57; + } + if (v43 > v56 + p43) { + v43 = v56 + p43; + d43 = d56; + } + if (v43 > v44 + p43) { + v43 = v44 + p43; + d43 = d44; + } + } + if (rc.onTheMap(l47)) { + p47 = Math.floor((1.0 + (double)rc.senseRubble(l47)/10.0)*cooldown); + if (v47 > v59 + p47) { + v47 = v59 + p47; + d47 = d59; + } + if (v47 > v60 + p47) { + v47 = v60 + p47; + d47 = d60; + } + if (v47 > v46 + p47) { + v47 = v46 + p47; + d47 = d46; + } + } + if (rc.onTheMap(l55)) { + p55 = Math.floor((1.0 + (double)rc.senseRubble(l55)/10.0)*cooldown); + if (v55 > v69 + p55) { + v55 = v69 + p55; + d55 = d69; + } + if (v55 > v56 + p55) { + v55 = v56 + p55; + d55 = d56; + } + if (v55 > v68 + p55) { + v55 = v68 + p55; + d55 = d68; + } + if (v55 > v43 + p55) { + v55 = v43 + p55; + d55 = d43; + } + } + if (rc.onTheMap(l61)) { + p61 = Math.floor((1.0 + (double)rc.senseRubble(l61)/10.0)*cooldown); + if (v61 > v73 + p61) { + v61 = v73 + p61; + d61 = d73; + } + if (v61 > v60 + p61) { + v61 = v60 + p61; + d61 = d60; + } + if (v61 > v74 + p61) { + v61 = v74 + p61; + d61 = d74; + } + if (v61 > v47 + p61) { + v61 = v47 + p61; + d61 = d47; + } + } + if (rc.onTheMap(l107)) { + p107 = Math.floor((1.0 + (double)rc.senseRubble(l107)/10.0)*cooldown); + if (v107 > v95 + p107) { + v107 = v95 + p107; + d107 = d95; + } + if (v107 > v108 + p107) { + v107 = v108 + p107; + d107 = d108; + } + if (v107 > v94 + p107) { + v107 = v94 + p107; + d107 = d94; + } + } + if (rc.onTheMap(l113)) { + p113 = Math.floor((1.0 + (double)rc.senseRubble(l113)/10.0)*cooldown); + if (v113 > v99 + p113) { + v113 = v99 + p113; + d113 = d99; + } + if (v113 > v112 + p113) { + v113 = v112 + p113; + d113 = d112; + } + if (v113 > v100 + p113) { + v113 = v100 + p113; + d113 = d100; + } + } + if (rc.onTheMap(l121)) { + p121 = Math.floor((1.0 + (double)rc.senseRubble(l121)/10.0)*cooldown); + if (v121 > v109 + p121) { + v121 = v109 + p121; + d121 = d109; + } + if (v121 > v108 + p121) { + v121 = v108 + p121; + d121 = d108; + } + if (v121 > v122 + p121) { + v121 = v122 + p121; + d121 = d122; + } + if (v121 > v107 + p121) { + v121 = v107 + p121; + d121 = d107; + } + } + if (rc.onTheMap(l125)) { + p125 = Math.floor((1.0 + (double)rc.senseRubble(l125)/10.0)*cooldown); + if (v125 > v111 + p125) { + v125 = v111 + p125; + d125 = d111; + } + if (v125 > v112 + p125) { + v125 = v112 + p125; + d125 = d112; + } + if (v125 > v124 + p125) { + v125 = v124 + p125; + d125 = d124; + } + if (v125 > v113 + p125) { + v125 = v113 + p125; + d125 = d113; + } + } + if (rc.onTheMap(l32)) { + p32 = Math.floor((1.0 + (double)rc.senseRubble(l32)/10.0)*cooldown); + if (v32 > v45 + p32) { + v32 = v45 + p32; + d32 = d45; + } + if (v32 > v44 + p32) { + v32 = v44 + p32; + d32 = d44; + } + if (v32 > v46 + p32) { + v32 = v46 + p32; + d32 = d46; + } + } + if (rc.onTheMap(l80)) { + p80 = Math.floor((1.0 + (double)rc.senseRubble(l80)/10.0)*cooldown); + if (v80 > v81 + p80) { + v80 = v81 + p80; + d80 = d81; + } + if (v80 > v68 + p80) { + v80 = v68 + p80; + d80 = d68; + } + if (v80 > v94 + p80) { + v80 = v94 + p80; + d80 = d94; + } + } + if (rc.onTheMap(l88)) { + p88 = Math.floor((1.0 + (double)rc.senseRubble(l88)/10.0)*cooldown); + if (v88 > v87 + p88) { + v88 = v87 + p88; + d88 = d87; + } + if (v88 > v74 + p88) { + v88 = v74 + p88; + d88 = d74; + } + if (v88 > v100 + p88) { + v88 = v100 + p88; + d88 = d100; + } + } + if (rc.onTheMap(l136)) { + p136 = Math.floor((1.0 + (double)rc.senseRubble(l136)/10.0)*cooldown); + if (v136 > v123 + p136) { + v136 = v123 + p136; + d136 = d123; + } + if (v136 > v122 + p136) { + v136 = v122 + p136; + d136 = d122; + } + if (v136 > v124 + p136) { + v136 = v124 + p136; + d136 = d124; + } + } + if (rc.onTheMap(l31)) { + p31 = Math.floor((1.0 + (double)rc.senseRubble(l31)/10.0)*cooldown); + if (v31 > v45 + p31) { + v31 = v45 + p31; + d31 = d45; + } + if (v31 > v44 + p31) { + v31 = v44 + p31; + d31 = d44; + } + if (v31 > v43 + p31) { + v31 = v43 + p31; + d31 = d43; + } + if (v31 > v32 + p31) { + v31 = v32 + p31; + d31 = d32; + } + } + if (rc.onTheMap(l33)) { + p33 = Math.floor((1.0 + (double)rc.senseRubble(l33)/10.0)*cooldown); + if (v33 > v45 + p33) { + v33 = v45 + p33; + d33 = d45; + } + if (v33 > v46 + p33) { + v33 = v46 + p33; + d33 = d46; + } + if (v33 > v47 + p33) { + v33 = v47 + p33; + d33 = d47; + } + if (v33 > v32 + p33) { + v33 = v32 + p33; + d33 = d32; + } + } + if (rc.onTheMap(l67)) { + p67 = Math.floor((1.0 + (double)rc.senseRubble(l67)/10.0)*cooldown); + if (v67 > v81 + p67) { + v67 = v81 + p67; + d67 = d81; + } + if (v67 > v68 + p67) { + v67 = v68 + p67; + d67 = d68; + } + if (v67 > v55 + p67) { + v67 = v55 + p67; + d67 = d55; + } + if (v67 > v80 + p67) { + v67 = v80 + p67; + d67 = d80; + } + } + if (rc.onTheMap(l75)) { + p75 = Math.floor((1.0 + (double)rc.senseRubble(l75)/10.0)*cooldown); + if (v75 > v87 + p75) { + v75 = v87 + p75; + d75 = d87; + } + if (v75 > v74 + p75) { + v75 = v74 + p75; + d75 = d74; + } + if (v75 > v61 + p75) { + v75 = v61 + p75; + d75 = d61; + } + if (v75 > v88 + p75) { + v75 = v88 + p75; + d75 = d88; + } + } + if (rc.onTheMap(l93)) { + p93 = Math.floor((1.0 + (double)rc.senseRubble(l93)/10.0)*cooldown); + if (v93 > v81 + p93) { + v93 = v81 + p93; + d93 = d81; + } + if (v93 > v94 + p93) { + v93 = v94 + p93; + d93 = d94; + } + if (v93 > v107 + p93) { + v93 = v107 + p93; + d93 = d107; + } + if (v93 > v80 + p93) { + v93 = v80 + p93; + d93 = d80; + } + } + if (rc.onTheMap(l101)) { + p101 = Math.floor((1.0 + (double)rc.senseRubble(l101)/10.0)*cooldown); + if (v101 > v87 + p101) { + v101 = v87 + p101; + d101 = d87; + } + if (v101 > v100 + p101) { + v101 = v100 + p101; + d101 = d100; + } + if (v101 > v113 + p101) { + v101 = v113 + p101; + d101 = d113; + } + if (v101 > v88 + p101) { + v101 = v88 + p101; + d101 = d88; + } + } + if (rc.onTheMap(l135)) { + p135 = Math.floor((1.0 + (double)rc.senseRubble(l135)/10.0)*cooldown); + if (v135 > v123 + p135) { + v135 = v123 + p135; + d135 = d123; + } + if (v135 > v122 + p135) { + v135 = v122 + p135; + d135 = d122; + } + if (v135 > v121 + p135) { + v135 = v121 + p135; + d135 = d121; + } + if (v135 > v136 + p135) { + v135 = v136 + p135; + d135 = d136; + } + } + if (rc.onTheMap(l137)) { + p137 = Math.floor((1.0 + (double)rc.senseRubble(l137)/10.0)*cooldown); + if (v137 > v123 + p137) { + v137 = v123 + p137; + d137 = d123; + } + if (v137 > v124 + p137) { + v137 = v124 + p137; + d137 = d124; + } + if (v137 > v125 + p137) { + v137 = v125 + p137; + d137 = d125; + } + if (v137 > v136 + p137) { + v137 = v136 + p137; + d137 = d136; + } + } + if (rc.onTheMap(l42)) { + p42 = Math.floor((1.0 + (double)rc.senseRubble(l42)/10.0)*cooldown); + if (v42 > v56 + p42) { + v42 = v56 + p42; + d42 = d56; + } + if (v42 > v43 + p42) { + v42 = v43 + p42; + d42 = d43; + } + if (v42 > v55 + p42) { + v42 = v55 + p42; + d42 = d55; + } + } + if (rc.onTheMap(l48)) { + p48 = Math.floor((1.0 + (double)rc.senseRubble(l48)/10.0)*cooldown); + if (v48 > v60 + p48) { + v48 = v60 + p48; + d48 = d60; + } + if (v48 > v47 + p48) { + v48 = v47 + p48; + d48 = d47; + } + if (v48 > v61 + p48) { + v48 = v61 + p48; + d48 = d61; + } + } + if (rc.onTheMap(l120)) { + p120 = Math.floor((1.0 + (double)rc.senseRubble(l120)/10.0)*cooldown); + if (v120 > v108 + p120) { + v120 = v108 + p120; + d120 = d108; + } + if (v120 > v107 + p120) { + v120 = v107 + p120; + d120 = d107; + } + if (v120 > v121 + p120) { + v120 = v121 + p120; + d120 = d121; + } + } + if (rc.onTheMap(l126)) { + p126 = Math.floor((1.0 + (double)rc.senseRubble(l126)/10.0)*cooldown); + if (v126 > v112 + p126) { + v126 = v112 + p126; + d126 = d112; + } + if (v126 > v113 + p126) { + v126 = v113 + p126; + d126 = d113; + } + if (v126 > v125 + p126) { + v126 = v125 + p126; + d126 = d125; + } + } + if (rc.onTheMap(l30)) { + p30 = Math.floor((1.0 + (double)rc.senseRubble(l30)/10.0)*cooldown); + if (v30 > v44 + p30) { + v30 = v44 + p30; + d30 = d44; + } + if (v30 > v43 + p30) { + v30 = v43 + p30; + d30 = d43; + } + if (v30 > v31 + p30) { + v30 = v31 + p30; + d30 = d31; + } + if (v30 > v42 + p30) { + v30 = v42 + p30; + d30 = d42; + } + } + if (rc.onTheMap(l34)) { + p34 = Math.floor((1.0 + (double)rc.senseRubble(l34)/10.0)*cooldown); + if (v34 > v46 + p34) { + v34 = v46 + p34; + d34 = d46; + } + if (v34 > v47 + p34) { + v34 = v47 + p34; + d34 = d47; + } + if (v34 > v33 + p34) { + v34 = v33 + p34; + d34 = d33; + } + if (v34 > v48 + p34) { + v34 = v48 + p34; + d34 = d48; + } + } + if (rc.onTheMap(l54)) { + p54 = Math.floor((1.0 + (double)rc.senseRubble(l54)/10.0)*cooldown); + if (v54 > v68 + p54) { + v54 = v68 + p54; + d54 = d68; + } + if (v54 > v55 + p54) { + v54 = v55 + p54; + d54 = d55; + } + if (v54 > v67 + p54) { + v54 = v67 + p54; + d54 = d67; + } + if (v54 > v42 + p54) { + v54 = v42 + p54; + d54 = d42; + } + } + if (rc.onTheMap(l62)) { + p62 = Math.floor((1.0 + (double)rc.senseRubble(l62)/10.0)*cooldown); + if (v62 > v74 + p62) { + v62 = v74 + p62; + d62 = d74; + } + if (v62 > v61 + p62) { + v62 = v61 + p62; + d62 = d61; + } + if (v62 > v75 + p62) { + v62 = v75 + p62; + d62 = d75; + } + if (v62 > v48 + p62) { + v62 = v48 + p62; + d62 = d48; + } + } + if (rc.onTheMap(l106)) { + p106 = Math.floor((1.0 + (double)rc.senseRubble(l106)/10.0)*cooldown); + if (v106 > v94 + p106) { + v106 = v94 + p106; + d106 = d94; + } + if (v106 > v107 + p106) { + v106 = v107 + p106; + d106 = d107; + } + if (v106 > v93 + p106) { + v106 = v93 + p106; + d106 = d93; + } + if (v106 > v120 + p106) { + v106 = v120 + p106; + d106 = d120; + } + } + if (rc.onTheMap(l114)) { + p114 = Math.floor((1.0 + (double)rc.senseRubble(l114)/10.0)*cooldown); + if (v114 > v100 + p114) { + v114 = v100 + p114; + d114 = d100; + } + if (v114 > v113 + p114) { + v114 = v113 + p114; + d114 = d113; + } + if (v114 > v101 + p114) { + v114 = v101 + p114; + d114 = d101; + } + if (v114 > v126 + p114) { + v114 = v126 + p114; + d114 = d126; + } + } + if (rc.onTheMap(l134)) { + p134 = Math.floor((1.0 + (double)rc.senseRubble(l134)/10.0)*cooldown); + if (v134 > v122 + p134) { + v134 = v122 + p134; + d134 = d122; + } + if (v134 > v121 + p134) { + v134 = v121 + p134; + d134 = d121; + } + if (v134 > v135 + p134) { + v134 = v135 + p134; + d134 = d135; + } + if (v134 > v120 + p134) { + v134 = v120 + p134; + d134 = d120; + } + } + if (rc.onTheMap(l138)) { + p138 = Math.floor((1.0 + (double)rc.senseRubble(l138)/10.0)*cooldown); + if (v138 > v124 + p138) { + v138 = v124 + p138; + d138 = d124; + } + if (v138 > v125 + p138) { + v138 = v125 + p138; + d138 = d125; + } + if (v138 > v137 + p138) { + v138 = v137 + p138; + d138 = d137; + } + if (v138 > v126 + p138) { + v138 = v126 + p138; + d138 = d126; + } + } + int dx = target.x - l84.x; + int dy = target.y - l84.y; + switch (dx) { + case -4: + switch (dy) { + case -2: + return d54; + case -1: + return d67; + case 0: + return d80; + case 1: + return d93; + case 2: + return d106; + } + break; + case -3: + switch (dy) { + case -3: + return d42; + case -2: + return d55; + case -1: + return d68; + case 0: + return d81; + case 1: + return d94; + case 2: + return d107; + case 3: + return d120; + } + break; + case -2: + switch (dy) { + case -4: + return d30; + case -3: + return d43; + case -2: + return d56; + case -1: + return d69; + case 0: + return d82; + case 1: + return d95; + case 2: + return d108; + case 3: + return d121; + case 4: + return d134; + } + break; + case -1: + switch (dy) { + case -4: + return d31; + case -3: + return d44; + case -2: + return d57; + case -1: + return d70; + case 0: + return d83; + case 1: + return d96; + case 2: + return d109; + case 3: + return d122; + case 4: + return d135; + } + break; + case 0: + switch (dy) { + case -4: + return d32; + case -3: + return d45; + case -2: + return d58; + case -1: + return d71; + case 0: + return d84; + case 1: + return d97; + case 2: + return d110; + case 3: + return d123; + case 4: + return d136; + } + break; + case 1: + switch (dy) { + case -4: + return d33; + case -3: + return d46; + case -2: + return d59; + case -1: + return d72; + case 0: + return d85; + case 1: + return d98; + case 2: + return d111; + case 3: + return d124; + case 4: + return d137; + } + break; + case 2: + switch (dy) { + case -4: + return d34; + case -3: + return d47; + case -2: + return d60; + case -1: + return d73; + case 0: + return d86; + case 1: + return d99; + case 2: + return d112; + case 3: + return d125; + case 4: + return d138; + } + break; + case 3: + switch (dy) { + case -3: + return d48; + case -2: + return d61; + case -1: + return d74; + case 0: + return d87; + case 1: + return d100; + case 2: + return d113; + case 3: + return d126; + } + break; + case 4: + switch (dy) { + case -2: + return d62; + case -1: + return d75; + case 0: + return d88; + case 1: + return d101; + case 2: + return d114; + } + break; + } + Direction ans = null; + double bestEstimation = 0; + double initialDist = Math.sqrt(l84.distanceSquaredTo(target)); + double dist32 = (initialDist - Math.sqrt(l32.distanceSquaredTo(target))) / v32; + if (dist32 > bestEstimation) { + bestEstimation = dist32; + ans = d32; + } + double dist80 = (initialDist - Math.sqrt(l80.distanceSquaredTo(target))) / v80; + if (dist80 > bestEstimation) { + bestEstimation = dist80; + ans = d80; + } + double dist88 = (initialDist - Math.sqrt(l88.distanceSquaredTo(target))) / v88; + if (dist88 > bestEstimation) { + bestEstimation = dist88; + ans = d88; + } + double dist136 = (initialDist - Math.sqrt(l136.distanceSquaredTo(target))) / v136; + if (dist136 > bestEstimation) { + bestEstimation = dist136; + ans = d136; + } + double dist31 = (initialDist - Math.sqrt(l31.distanceSquaredTo(target))) / v31; + if (dist31 > bestEstimation) { + bestEstimation = dist31; + ans = d31; + } + double dist33 = (initialDist - Math.sqrt(l33.distanceSquaredTo(target))) / v33; + if (dist33 > bestEstimation) { + bestEstimation = dist33; + ans = d33; + } + double dist67 = (initialDist - Math.sqrt(l67.distanceSquaredTo(target))) / v67; + if (dist67 > bestEstimation) { + bestEstimation = dist67; + ans = d67; + } + double dist75 = (initialDist - Math.sqrt(l75.distanceSquaredTo(target))) / v75; + if (dist75 > bestEstimation) { + bestEstimation = dist75; + ans = d75; + } + double dist93 = (initialDist - Math.sqrt(l93.distanceSquaredTo(target))) / v93; + if (dist93 > bestEstimation) { + bestEstimation = dist93; + ans = d93; + } + double dist101 = (initialDist - Math.sqrt(l101.distanceSquaredTo(target))) / v101; + if (dist101 > bestEstimation) { + bestEstimation = dist101; + ans = d101; + } + double dist135 = (initialDist - Math.sqrt(l135.distanceSquaredTo(target))) / v135; + if (dist135 > bestEstimation) { + bestEstimation = dist135; + ans = d135; + } + double dist137 = (initialDist - Math.sqrt(l137.distanceSquaredTo(target))) / v137; + if (dist137 > bestEstimation) { + bestEstimation = dist137; + ans = d137; + } + double dist42 = (initialDist - Math.sqrt(l42.distanceSquaredTo(target))) / v42; + if (dist42 > bestEstimation) { + bestEstimation = dist42; + ans = d42; + } + double dist48 = (initialDist - Math.sqrt(l48.distanceSquaredTo(target))) / v48; + if (dist48 > bestEstimation) { + bestEstimation = dist48; + ans = d48; + } + double dist120 = (initialDist - Math.sqrt(l120.distanceSquaredTo(target))) / v120; + if (dist120 > bestEstimation) { + bestEstimation = dist120; + ans = d120; + } + double dist126 = (initialDist - Math.sqrt(l126.distanceSquaredTo(target))) / v126; + if (dist126 > bestEstimation) { + bestEstimation = dist126; + ans = d126; + } + double dist30 = (initialDist - Math.sqrt(l30.distanceSquaredTo(target))) / v30; + if (dist30 > bestEstimation) { + bestEstimation = dist30; + ans = d30; + } + double dist34 = (initialDist - Math.sqrt(l34.distanceSquaredTo(target))) / v34; + if (dist34 > bestEstimation) { + bestEstimation = dist34; + ans = d34; + } + double dist54 = (initialDist - Math.sqrt(l54.distanceSquaredTo(target))) / v54; + if (dist54 > bestEstimation) { + bestEstimation = dist54; + ans = d54; + } + double dist62 = (initialDist - Math.sqrt(l62.distanceSquaredTo(target))) / v62; + if (dist62 > bestEstimation) { + bestEstimation = dist62; + ans = d62; + } + double dist106 = (initialDist - Math.sqrt(l106.distanceSquaredTo(target))) / v106; + if (dist106 > bestEstimation) { + bestEstimation = dist106; + ans = d106; + } + double dist114 = (initialDist - Math.sqrt(l114.distanceSquaredTo(target))) / v114; + if (dist114 > bestEstimation) { + bestEstimation = dist114; + ans = d114; + } + double dist134 = (initialDist - Math.sqrt(l134.distanceSquaredTo(target))) / v134; + if (dist134 > bestEstimation) { + bestEstimation = dist134; + ans = d134; + } + double dist138 = (initialDist - Math.sqrt(l138.distanceSquaredTo(target))) / v138; + if (dist138 > bestEstimation) { + bestEstimation = dist138; + ans = d138; + } + return ans; + } + +} \ No newline at end of file diff --git a/src/rebutia_micro_heal/RANK.java b/src/rebutia_micro_heal/RANK.java new file mode 100644 index 0000000..8844b24 --- /dev/null +++ b/src/rebutia_micro_heal/RANK.java @@ -0,0 +1,11 @@ +package rebutia_micro_heal; + +public enum RANK { + DEFAULT(0), + DEFENDER(1), + MARTYR(2); + + private final int id; + RANK(int id) { this.id = id; } + public int getValue() { return id; } +} diff --git a/src/rebutia_micro_heal/RobotPlayer.java b/src/rebutia_micro_heal/RobotPlayer.java new file mode 100644 index 0000000..bc9c81a --- /dev/null +++ b/src/rebutia_micro_heal/RobotPlayer.java @@ -0,0 +1,102 @@ +package rebutia_micro_heal; + +import battlecode.common.*; +import java.util.Random; + +/** + * RobotPlayer is the class that describes your main robot strategy. + * The run() method inside this class is like your main function: this is what we'll call once your robot + * is created! + */ +public strictfp class RobotPlayer { + + /** + * We will use this variable to count the number of turns this robot has been alive. + * You can use static variables like this to save any information you want. Keep in mind that even though + * these variables are static, in Battlecode they aren't actually shared between your robots. + */ + static int turnCount = 0; + + /** + * run() is the method that is called when a robot is instantiated in the Battlecode world. + * It is like the main function for your robot. If this method returns, the robot dies! + * + * @param rc The RobotController object. You use it to perform actions from this robot, and to get + * information on its current status. Essentially your portal to interacting with the world. + **/ + @SuppressWarnings("unused") + public static void run(RobotController rc) throws GameActionException { + + // Hello world! Standard output is very useful for debugging. + // Everything you say here will be directly viewable in your terminal when you run a match! + //System.out.println("I'm a " + rc.getType() + " and I just got created! I have health " + rc.getHealth()); + + // You can also use indicators to save debug notes in replays. + rc.setIndicatorString("Hello world!"); + + Unit robot; + + switch (rc.getType()) { + case ARCHON: + robot = new Archon(rc); + break; + case MINER: + robot = new Miner(rc); + break; + case SOLDIER: + robot = new Soldier(rc); + break; + case LABORATORY: // Examplefuncsplayer doesn't use any of these robot types below. + robot = new Laboratory(rc); + case WATCHTOWER: // You might want to give them a try! + robot = new Watchtower(rc); + break; + case BUILDER: + robot = new Builder(rc); + break; + case SAGE: + robot = new Sage(rc); + break; + default: + robot = new Unit(rc); + break; + } + + while (true) { + // This code runs during the entire lifespan of the robot, which is why it is in an infinite + // loop. If we ever leave this loop and return from run(), the robot dies! At the end of the + // loop, we call Clock.yield(), signifying that we've done everything we want to do. + + turnCount += 1; // We have now been alive for one more turn! + // System.out.println("Age: " + turnCount + "; Location: " + rc.getLocation()); + // Try/catch blocks stop unhandled exceptions, which cause your robot to explode. + try { + // The same run() function is called for every robot on your team, even if they are + // different types. Here, we separate the control depending on the RobotType, so we can + // use different strategies on different robots. If you wish, you are free to rewrite + // this into a different control structure! + robot.run(); + } catch (GameActionException e) { + // Oh no! It looks like we did something illegal in the Battlecode world. You should + // handle GameActionExceptions judiciously, in case unexpected events occur in the game + // world. Remember, uncaught exceptions cause your robot to explode! + System.out.println(rc.getType() + " Exception"); + e.printStackTrace(); + + } catch (Exception e) { + // Oh no! It looks like our code tried to do something bad. This isn't a + // GameActionException, so it's more likely to be a bug in our code. + System.out.println(rc.getType() + " Exception"); + e.printStackTrace(); + + } finally { + // Signify we've done everything we want to do, thereby ending our turn. + // This will make our code wait until the next turn, and then perform this loop again. + Clock.yield(); + } + // End of loop: go back to the top. Clock.yield() has ended, so it's time for another turn! + } + + // Your code should never reach here (unless it's intentional)! Self-destruction imminent... + } +} \ No newline at end of file diff --git a/src/rebutia_micro_heal/Sage.java b/src/rebutia_micro_heal/Sage.java new file mode 100644 index 0000000..3e78b67 --- /dev/null +++ b/src/rebutia_micro_heal/Sage.java @@ -0,0 +1,273 @@ +package rebutia_micro_heal; + +import battlecode.common.*; +import java.util.*; + +public class Sage extends Unit { + int counter = 0; + int archon_index = -1; + double s_attraction = 0.5; + double m_attraction = 10.0; + double s_repulsion = 1; + double m_repulsion = 1/10; + + MapLocation target; + int[] exploratoryDir = getExploratoryDir(); + + public Sage(RobotController rc) throws GameActionException { + super(rc); + } + + @Override + public void run() throws GameActionException { + /* + if (isLowHealth()) { + fuzzyMove(homeArchon); + } + else if (isExploring()){ + moveInDirection(friendlyDir()); + if (rc.getLocation().isAdjacentTo(homeArchon)) { + // rc.setIndicatorString("moving away"); + moveInDirection(rc.getLocation().directionTo(homeArchon).opposite()); + } + else { + moveInDirection(friendlyDir()); + } + } + else if (archon_found) { + huntArchon(); + } + senseArchon(); + attemptAttack(); + detectArchon(); + counter += 1;*/ + } +/* + public boolean isExploring() throws GameActionException{ + if (archon_found) { + return false; + } + else { + return true; + } + } + + public void detectArchon() throws GameActionException { + // if archon still alive, don't do anything + int data = 0; + if (archon_found) { + // rc.setIndicatorString("archon already found"); + data = rc.readSharedArray(archon_index); + // rc.setIndicatorString("archon read: " + data); + if (data != 0) { + return; + } + else { + archon_found = false; + } + } + + // rc.setIndicatorString("finding new archon"); + // if archon dead, find new archon + for (int i = 0; i < 4; i++) { + data = rc.readSharedArray(i); + if (data != 0) { + // rc.setIndicatorString("archon found UWU"); + archon_index = i; + break; + } + } + data = rc.readSharedArray(archon_index); + if (data != 0) { + // rc.setIndicatorString("new archon found"); + archon_found = true; + int x = data / 1000; + int y = data % 1000; + target = new MapLocation(x, y); + } + else { + archon_found = false; + } + } + + public boolean isLowHealth() throws GameActionException { + if (rc.getHealth() < 20) { + return true; + } + else { + return false; + } + } + + public void huntArchon() throws GameActionException { + // if robot should be able to see archon but can't, inform everyone that archon is dead + if (rc.canSenseLocation(target)) { + if (!rc.canSenseRobotAtLocation(target)){ + int data = rc.readSharedArray(archon_index); + if (data != 0) { + rc.writeSharedArray(archon_index, 0); + } + archon_found = false; + return; + } + } + // if robot can't see archon, or sees archon, move towards it + fuzzyMove(target); + } + + public Direction friendlyDir() throws GameActionException { + + Direction d = usefulDir(); // placeholder + RobotInfo[] friendlyRobos = rc.senseNearbyRobots(-1, rc.getTeam()); + MapLocation loc = rc.getLocation(); + + // average position of soldiers and miners + double cxs = 0; + double cys = 0; + double cxm = 0; + double cym = 0; + + // repulsion from friendly robots + double dx2 = 0; + double dy2 = 0; + + double incrementx = 0; + double incrementy = 0; + + int num_miners = 0; + int far_miners = 0; + int num_soldiers = 0; + + for (RobotInfo robot: friendlyRobos) { + if (robot.type == RobotType.SOLDIER) { + incrementx = robot.location.x; + incrementy = robot.location.y; + + // increment repulsion + if ((Math.abs(robot.location.x - loc.x) + Math.abs(robot.location.y - loc.y)) <= 4) { + dx2 -= (loc.x - robot.location.x) * s_repulsion; + dy2 -= (loc.y - robot.location.y) * s_repulsion; + } + cxs += incrementx; + cys += incrementy; + num_soldiers += 1; + } + else if (robot.type == RobotType.MINER) { + if ((Math.abs(robot.location.x - loc.x) + Math.abs(robot.location.y - loc.y)) > 3) { + far_miners += 1; + } + incrementx = robot.location.x; + incrementy = robot.location.y; + // increment repulsion + if ((Math.abs(robot.location.x - loc.x) + Math.abs(robot.location.y - loc.y)) <= 2) { + dx2 -= (loc.x - robot.location.x) * m_repulsion; + dy2 -= (loc.y - robot.location.y) * m_repulsion; + } + cxm += incrementx; + cym += incrementy; + num_miners += 1; + } + } + // if there are no miners, explore. + if (num_miners == 0) { + return d; + } + + double dx1 = ((cxm / num_miners) - (double) loc.x) * m_attraction; + dx1 += ((cxs / num_soldiers) - (double) loc.x) * s_attraction; + double dy1 = ((cym / num_miners) - (double) loc.y) * m_attraction; + dy1 += ((cys / num_soldiers) - (double) loc.y) * s_attraction; + + double dx = dx1 + dx2; + double dy = dy1 + dy2; + // convert dx and dy to direction + // values are derived from tangent of 22.5 and 67.5 + if (dy > 0) { + if (dy > 2.4 * Math.abs(dx)) { + d = Direction.NORTH; + } + else if (dy > 0.4 * Math.abs(dx)) { + if (dx > 0) { + d = Direction.NORTHEAST; + } + else { + d = Direction.NORTHWEST; + } + } + else { + if (dx > 0) { + d = Direction.EAST; + } + else { + d = Direction.WEST; + } + } + } + else { + if (dy < -2.4 * Math.abs(dx)) { + d = Direction.SOUTH; + } + else if (dy < -0.4 * Math.abs(dx)) { + if (dx > 0) { + d = Direction.SOUTHEAST; + } + else { + d = Direction.SOUTHWEST; + } + } + } + rc.setIndicatorString("dir: " + d + "| attraction: " + Math.round(dx1) + ", " + Math.round(dy1) + " | repulsion: " + Math.round(dx2) + ", " + Math.round(dy2)); + // rc.setIndicatorString("vs: " + Math.round(cxs) + ", " + Math.round(cys) + " | vm: " + Math.round(cxm) + ", " + Math.round(cym)); + return d; + } + + public Direction usefulDir() throws GameActionException { + MapLocation cur = rc.getLocation(); + Direction d = rc.getLocation().directionTo(homeArchon); // placeholder + MapLocation center = new MapLocation(rc.getMapWidth()/2, rc.getMapHeight()/2); + if (center.x - cur.x > 0) { + if (center.y - cur.y > 0) { + d = Direction.NORTHEAST; + } else { + d = Direction.SOUTHEAST; + } + } else { + if (center.y - cur.y > 0) { + d = Direction.NORTHWEST; + } else { + d = Direction.SOUTHWEST; + } + } + rc.setIndicatorString(d.dx + " " + d.dy); + Direction[] dirs = {d, d.rotateLeft(), d.rotateRight()}; + return dirs[rng.nextInt(dirs.length)]; + } + + public void attemptAttack() throws GameActionException { + boolean enemy_soldiers = false; + RobotInfo[] nearbyBots = rc.senseNearbyRobots(RobotType.SOLDIER.actionRadiusSquared, rc.getTeam().opponent()); + // if there are any nearby enemy robots, attack the one with the least health + if (nearbyBots.length > 0) { + RobotInfo weakestBot = nearbyBots[0]; + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.SOLDIER) + if (bot.health < weakestBot.health) { + weakestBot = bot; + } + enemy_soldiers = true; + } + if (enemy_soldiers) { + rc.attack(weakestBot.location); + } + else { + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.MINER) + if (bot.health < weakestBot.health) { + weakestBot = bot; + } + } + rc.attack(weakestBot.location); + } + } + }*/ +} diff --git a/src/rebutia_micro_heal/Soldier.java b/src/rebutia_micro_heal/Soldier.java new file mode 100644 index 0000000..c3538ab --- /dev/null +++ b/src/rebutia_micro_heal/Soldier.java @@ -0,0 +1,522 @@ +package rebutia_micro_heal; + +import battlecode.common.*; + +import java.util.*; + +public class Soldier extends Unit { + + enum MODE { + EXPLORATORY, //at the start of the game, before anyone has found anything + HUNTING, + SEARCHING_ENEMIES, //when u have already found enemies + FLEE, + DEFENSIVE_RUSH, + DYING + ; + } + + boolean attacked = false; + int round_num = 0; + + RANK rank; + + MapLocation[] threatenedArchons; + + private int[] fleeDirection = {Integer.MAX_VALUE, Integer.MAX_VALUE}; + private int stopFleeingRound = -1; + private int DRUSH_RSQR = 400; + private int ARUSH_RSQR = 900; + + MODE mode; + + //for explore mode only + private MapLocation exploreLoc; + private int[] exploratoryDir; + + //for attacking and searching enemies modes + private MapLocation target = null; + private int[] lastAttackDir = null; + + public Soldier(RobotController rc) throws GameActionException { + super(rc); + initialize(); + exploreLoc = getInitialExploratoryLocation(); + } + @Override + public void run() throws GameActionException { + super.run(); + round_num = rc.getRoundNum(); + radio.updateCounter(); + attacked = attemptAttack(false); + findTargets(); + senseMiningArea(); + + mode = determineMode(); + visualize(); + switch (mode) { + case EXPLORATORY: + if (soldierBehindMe()) { + if (adjacentToEdge()){ + exploratoryDir = flip(exploratoryDir); + exploreLoc = scaleToEdge(exploratoryDir); + } + moveToLocation(exploreLoc); + } + break; + case HUNTING: + huntTarget(); + target = null; + break; + case SEARCHING_ENEMIES: + if (adjacentToEdge()) { //TODO: bots occasionally get stuck somehow + lastAttackDir = flip(lastAttackDir); + } + moveInDirection(lastAttackDir); + break; + case DEFENSIVE_RUSH: + defensiveMove(); + break; + case FLEE: + moveLowRubble(fleeDirection); + break; + default: + break; + } + + if (!attacked) attemptAttack(true); + } + + public void visualize() throws GameActionException { + rc.setIndicatorString("MODE: " + mode.toString()); + if (mode == MODE.EXPLORATORY){ + rc.setIndicatorDot(exploreLoc, 100, 100, 0); + } + else if (mode == MODE.HUNTING){ + rc.setIndicatorLine(rc.getLocation(), target, 0, 100, 0); + } + else if (mode == MODE.SEARCHING_ENEMIES){ + rc.setIndicatorString("MODE: " + mode.toString() + " DIR: " + lastAttackDir[0] + " " + lastAttackDir[1]); + } + else if (target != null) { + if (mode != MODE.FLEE) rc.setIndicatorString("TARGET: " + target.toString() + " MODE: " + mode.toString()); + else rc.setIndicatorString("TARGET: " + target.toString() + " MODE: FLEE " + "FLEEROUND: " + stopFleeingRound); + rc.setIndicatorLine(rc.getLocation(), target, 0, 0, 100); + } + else { + if (mode != MODE.FLEE) rc.setIndicatorString("TARGET: null MODE: " + mode.toString()); + else rc.setIndicatorString("TARGET: null MODE: FLEE " + "FLEEROUND: " + stopFleeingRound); + } + } + + public MODE determineMode() throws GameActionException { + + // Priority 1 - Defend. + threatenedArchons = findThreatenedArchons(); + if (threatenedArchons != null) { + for (MapLocation archon: threatenedArchons) { + if (rc.getLocation().distanceSquaredTo(archon) <= DRUSH_RSQR) { + return MODE.DEFENSIVE_RUSH; + } + } + } + + // Priority 2 - Don't die. + int[] potFleeDir = fleeDirection(); + boolean validFlee = (potFleeDir[0] != Integer.MAX_VALUE && potFleeDir[1] != Integer.MAX_VALUE); + if (!validFlee && stopFleeingRound == round_num) { + exploreLoc = getInitialExploratoryLocation(); + lastAttackDir = null; + } + if (validFlee || stopFleeingRound > round_num) { + if (validFlee) fleeDirection = potFleeDir; + // keep fleeing for two moves (2 rounds per move) + if (stopFleeingRound <= round_num) { + stopFleeingRound = round_num + 6; + } + return MODE.FLEE; + } + + // Priority 3 - Hunt enemies. + if (target != null) { + return MODE.HUNTING; + } + else if (lastAttackDir != null){ + return MODE.SEARCHING_ENEMIES; + } + else return MODE.EXPLORATORY; + } + + /** + * getInitialExploratoryLocation() gets the location when you extend the vector from your location + * to the center to the edge + **/ + public MapLocation getInitialExploratoryLocation(){ + MapLocation my = rc.getLocation(); + MapLocation center = new MapLocation(rc.getMapWidth()/2, rc.getMapHeight()/2); + exploratoryDir = new int[]{center.x - my.x, center.y - my.y}; + if (!my.equals(center)){ + return scaleToEdge(exploratoryDir); + } + else { + System.out.println("YOU REACHED A CASE THAT SHOULD BE IMPLEMENTED"); + return null; //TODO + } + } + + public boolean isBehind(MapLocation loc){ + MapLocation my = rc.getLocation(); + int[] v = new int[]{loc.x - my.x, loc.y - my.y}; + int dotProduct = v[0]*exploratoryDir[0] + v[1]*exploratoryDir[1]; + return (dotProduct < 0); + } + + public boolean soldierBehindMe(){ + RobotInfo[] nearbyBots = rc.senseNearbyRobots(15, rc.getTeam()); + for (RobotInfo r : nearbyBots){ + if (r.type == RobotType.SOLDIER){ + if (isBehind(r.location)) return true; + } + } + return false; + } + + public int[] fleeDirection() throws GameActionException{ + MapLocation cur = rc.getLocation(); + RobotInfo[] nearbyBots = rc.senseNearbyRobots(-1); + double cxse = 0; + double cyse = 0; + int numEnemies = 0; + int numEnemyHits = 0; + int numFriendHits = (rc.getHealth() + 2) / 3; + int numFriends = 0; + for (RobotInfo bot: nearbyBots) { + if (bot.team == rc.getTeam()) { + if (bot.type == RobotType.SOLDIER) { + numFriendHits += ((bot.health + 2) / 3); + numFriends++; + } + } + else if (bot.team == rc.getTeam().opponent()) + if (bot.type == RobotType.SOLDIER) { + cxse += bot.location.x; + cyse += bot.location.y; + numEnemyHits += ((bot.health + 2) / 3); + numEnemies++; + } + } + if (numEnemies == 0) return new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE}; + + if (numEnemies > 0) { + cxse /= numEnemies; + cyse /= numEnemies; + } + + double unit_difference = (double) (numFriends + 1 - numEnemies); + double ratio; + + if (((numFriends + 1) / numEnemies) > 1) { + ratio = ((numFriends + 1) / numEnemies); + } + else { + ratio = numEnemies / (numFriends + 1); + } + + double a = 6 * ratio; + int unit_advantage = (int) (a * Math.pow(unit_difference,2) * Math.signum(unit_difference)); + + // System.out.println("Unit advantage: " + unit_advantage + " Ratio: " + ratio + " numFriendHits " + numFriendHits + " numEnemyHits " + numEnemyHits + "round_num " + round_num); + + if (numFriendHits + unit_advantage < numEnemyHits) { + double dx = -(cxse - cur.x) * 3; + double dy = -(cyse - cur.y) * 3; + // more attracted + // dx = 0.7 * dx + 0.3 * (cxsf - cur.x); + // dy = 0.7 * dx + 0.3 * (cysf - cur.y); + return new int[]{(int) dx, (int) dy}; + } + return new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE}; + } + + public RANK findRankSoldier() throws GameActionException{ + RANK new_rank = findRank(); + if (new_rank != RANK.DEFENDER && new_rank != RANK.DEFAULT) { + return RANK.DEFAULT; + } + else { + return new_rank; + } + } + + public void findTargets() throws GameActionException { + int data; + int closestDist = 100000; + MapLocation cur = rc.getLocation(); + MapLocation closestTarget = null; + for (int i = 0; i < CHANNEL.NUM_TARGETS; i++) { + data = rc.readSharedArray(CHANNEL.TARGET.getValue() + i); + if (data != 0) { + int x = data/64; + int y = data%64; + // System.out.println("I received an enemy at " + x*4 + " " + y*4 + " on round " + round_num); + MapLocation potentialTarget = new MapLocation(x, y); + if (cur.distanceSquaredTo(potentialTarget) < closestDist) { + closestDist = cur.distanceSquaredTo(potentialTarget); + closestTarget = potentialTarget; + } + } + } + + // finds closest target, and advances towards it. + if (closestTarget != null) { + if (cur.distanceSquaredTo(closestTarget) <= mapArea / 8) { + target = closestTarget; + } + lastAttackDir = new int[]{closestTarget.x - cur.x, closestTarget.y - cur.y}; + lastAttackDir = scaleToSize(lastAttackDir); + // wanders in direction of target + } + } + + public void huntTarget() throws GameActionException { + MapLocation cur = rc.getLocation(); + if (rc.getLocation().distanceSquaredTo(target) <= 13) { + // check for low rubble squares to move to + moveLowRubble(new int[] {-target.x + cur.x, -target.y + cur.y}, 20); + } + else if (rc.getLocation().distanceSquaredTo(target) <= 25) { + moveLowRubble(new int[] {target.x - cur.x, target.y - cur.y}, 15); + } + else { + moveToLocation(target); + } + } + + public Direction findLowRubble() throws GameActionException { + MapLocation cur = rc.getLocation(); + int lowest_rubble = 1 + rc.senseRubble(cur) / 10; + int rubble; + Direction bestDir = null; + for (int i = 0; i < 8; i++) { + if (!rc.canMove(directions[i])) continue; + rubble = 1 + rc.senseRubble(cur.add(directions[i])) / 10; + if (rubble < lowest_rubble && rc.canMove(directions[i])) { + lowest_rubble = rubble; + bestDir = directions[i]; + } + } + return bestDir; + } + + public void moveLowRubble(int[] dir) throws GameActionException { + moveLowRubble(dir, 20); + } + + public void moveLowRubble(int[] dir, int threshold) throws GameActionException { + MapLocation cur = rc.getLocation(); + Direction d = cur.directionTo(new MapLocation(cur.x + dir[0], cur.y + dir[1])); + Direction[] sorted_dirs = {d, d.rotateLeft(), d.rotateRight(), d.rotateLeft().rotateLeft(), d.rotateRight().rotateRight(), d.opposite().rotateRight(), d.opposite().rotateLeft(), d.opposite()}; + int a = 6; + int lowestCost = a * (1 + (rc.senseRubble(rc.getLocation()) / 10)) + threshold; + Direction bestDir = null; + for (int i = 0; i < 8; i++) { + if (!rc.canMove(sorted_dirs[i])) continue; + MapLocation loc = cur.add(sorted_dirs[i]); + + int cost = 0; + cost += (int) a * (1 + (rc.senseRubble(loc) / 10)) ; + // Preference tier for moving towards target + if (i >=1){ + cost+=5; + } + if (i >= 3) { + cost += 15; + } + if (i >=5){ + cost+=30; + } + if (cost < lowestCost) { + lowestCost = cost; + bestDir = sorted_dirs[i]; + } + } + if (bestDir != null) rc.move(bestDir); + } + + public void defensiveMove() throws GameActionException{ + MapLocation closest = threatenedArchons[0]; + int min_dist = Integer.MAX_VALUE; + // only find closest archon if there is more then one + if (threatenedArchons.length > 1) { + for (MapLocation loc: threatenedArchons) { + if (loc.distanceSquaredTo(rc.getLocation()) < min_dist) { + min_dist = loc.distanceSquaredTo(rc.getLocation()); + closest = loc; + } + } + } + // if you don't see the enemy, and you're not close to the archon, move towards it + if (rc.getLocation().distanceSquaredTo(closest) > 36 || target == null) { + moveToLocation(closest); + } + else { + huntTarget(); + } + } + + public boolean archonDied() throws GameActionException{ + RobotInfo home; + if (rc.canSenseLocation(homeArchon)) { + home = rc.senseRobotAtLocation(homeArchon); + return (home == null || home.type != RobotType.ARCHON); + } + return false; + } + + public MapLocation[] findThreatenedArchons() throws GameActionException { + int data; + MapLocation[] archons = new MapLocation[4]; + int numThreatenedArchons = 0; + for (int i = 0; i < 4; i++) { + // rc.writeSharedArray(, value); + data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); + // go through channels until you find an empty one to communicate with. + if (data != 0) { + int x = data / 64; + int y = data % 64; + if (validCoords(x, y)) { + archons[numThreatenedArchons] = new MapLocation(x, y); + numThreatenedArchons++; + } + } + } + + if (numThreatenedArchons == 0) { + return null; + } + else { + // only return threatened archons. + MapLocation[] threatenedArchons = new MapLocation[numThreatenedArchons]; + for (int i = 0; i < numThreatenedArchons; i++) { + threatenedArchons[i] = archons[i]; + } + return threatenedArchons; + } + } + + public boolean isLowHealth() throws GameActionException { + if (rc.getHealth() < 20) { + return true; + } + else { + return false; + } + } + + public boolean attemptAttack(boolean attackMiners) throws GameActionException { + RobotInfo[] nearbyBots = rc.senseNearbyRobots(RobotType.SOLDIER.actionRadiusSquared, rc.getTeam().opponent()); + int weakestSoldierHealth = 100000; + int weakestMinerHealth = 100000; + int weakestSageHealth = 100000; + int weakestTowerHealth = 100000; + int weakestBuilerHealth = 100000; + RobotInfo weakestSoldier = null; + RobotInfo weakestTower = null; + RobotInfo weakestSage = null; + RobotInfo weakestMiner = null; + RobotInfo weakestBuilder = null; + RobotInfo archon = null; + // if there are any nearby enemy robots, attack the one with the least health + if (nearbyBots.length > 0) { + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.SOLDIER) { + if (bot.health < weakestSoldierHealth) { + weakestSoldier = bot; + weakestSoldierHealth = bot.health; + } + } + if (bot.type == RobotType.MINER) { + if (bot.health < weakestMinerHealth) { + weakestMiner = bot; + weakestMinerHealth = bot.health; + } + } + if (bot.type == RobotType.WATCHTOWER) { + if (bot.health < weakestTowerHealth) { + weakestTower = bot; + weakestTowerHealth = bot.health; + } + } + if (bot.type == RobotType.SAGE) { + if (bot.health < weakestSageHealth) { + weakestSage = bot; + weakestSageHealth = bot.health; + } + } + if (bot.type == RobotType.BUILDER) { + if (bot.health < weakestBuilerHealth) { + weakestBuilder = bot; + weakestBuilerHealth = bot.health; + } + } + if (bot.type == RobotType.ARCHON) { + archon = bot; + } + } + // make more conditional, like damaging which one would give the biggest advantage + if (weakestSage != null) { + if (rc.canAttack(weakestSage.location)) { + rc.attack(weakestSage.location); + target = weakestSage.location; + broadcastTarget(weakestSage.location); + return true; + } + } + else if (weakestSoldier != null) { + if (rc.canAttack(weakestSoldier.location)) { + rc.attack(weakestSoldier.location); + target = weakestSoldier.location; + broadcastTarget(weakestSoldier.location); + return true; + } + } + else if (weakestTower != null) { + if (rc.canAttack(weakestTower.location)) { + rc.attack(weakestTower.location); + target = weakestTower.location; + broadcastTarget(weakestTower.location); + return true; + } + } + else if (weakestMiner != null && attackMiners) { + if (rc.canAttack(weakestMiner.location)) { + rc.attack(weakestMiner.location); + target = weakestMiner.location; + broadcastTarget(weakestMiner.location); + return true; + } + } + else if (weakestBuilder != null && attackMiners) { + if (rc.canAttack(weakestBuilder.location)) { + rc.attack(weakestBuilder.location); + target = weakestBuilder.location; + broadcastTarget(weakestBuilder.location); + return true; + } + } + else if (archon != null) { + if (rc.canAttack(archon.location)) { + rc.attack(archon.location); + broadcastTarget(archon.location); + return true; + } + } + } + return false; + } + + public void initialize() { + DRUSH_RSQR = (int) ((double) mapArea / 9.0); + ARUSH_RSQR = (int) ((double) mapArea / 4.0); + } +} diff --git a/src/rebutia_micro_heal/Unit.java b/src/rebutia_micro_heal/Unit.java new file mode 100644 index 0000000..dd6ed11 --- /dev/null +++ b/src/rebutia_micro_heal/Unit.java @@ -0,0 +1,563 @@ +package rebutia_micro_heal; + +import battlecode.common.*; +import java.util.*; + +// shared code across the units +public class Unit { + Comms radio; + RobotController rc; + int archon_index = -1; + RANK[] rank_map = initializeRankMap(); + final Random rng = new Random(); + static final int goldToLeadConversionRate = 200; + static final int minerToLeadRate = 250; + int seed_increment = 4; + MapLocation homeArchon; + public MapLocation archon_target; + public int mapArea; + /** Array containing all the possible movement directions. */ + static final Direction[] directions = { + Direction.NORTH, + Direction.NORTHEAST, + Direction.EAST, + Direction.SOUTHEAST, + Direction.SOUTH, + Direction.SOUTHWEST, + Direction.WEST, + Direction.NORTHWEST, + }; + + static Navigation mover; + + public Unit(RobotController robotController) throws GameActionException { + rc = robotController; + rng.setSeed((long) rc.getID() + seed_increment); + homeArchon = findHomeArchon(); + initializeRankMap(); + mapArea = getMapArea(); + radio = new Comms(rc); + mover = new Navigation(rc); + } + + /** + * run() is a placeholder implemented in the specific files + **/ + public void run() throws GameActionException { + radio.init(); + } + + // when you sense or detect, you get an archon_index + /** + * detectArchon() looks through the archon positions for a new one, then stores + * it in archon_index + * + * @return true if it found an archon + **/ + public boolean detectArchon() throws GameActionException { + if (archon_index != -1) { + int data = rc.readSharedArray(CHANNEL.ARCHON_LOC_1.getValue() + archon_index); + if (data != 0) { + rc.setIndicatorString("archon found UWU1 " + archon_index); + assert (archon_index != -1); + int x = data / 64; + int y = data % 64; + archon_target = new MapLocation(x, y); + return true; + } + } + for (int i = 0; i < 4; i++) { + int data = rc.readSharedArray(CHANNEL.ARCHON_LOC_1.getValue() + i); + if (data != 0) { + rc.setIndicatorString("archon found UWU2 " + archon_index); + archon_index = i; + assert (archon_index != -1); + int x = data / 64; + int y = data % 64; + archon_target = new MapLocation(x, y); + return true; + } + } + return false; + } + + /** + * checks if any of the nearby robots are enemy archons, if so broadcasts it + * + * @return true if archon was found, false otherwise + **/ + public boolean senseArchon() throws GameActionException { + RobotInfo[] nearbyBots = rc.senseNearbyRobots(-1, rc.getTeam().opponent()); + // if there are any nearby enemy robots, attack the one with the least health + boolean found = false; + if (nearbyBots.length > 0) { + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.ARCHON) { + int ind = broadcastArchon(bot.location); + archon_target = bot.location; + // store index of last archon sensed + archon_index = ind; + found = true; + } + } + } + return found; + } + + public int broadcastArchon(MapLocation loc) throws GameActionException { + // check that the loc is not already broadcasted + int indToPut = 0; // where to put the archon (if all spots are filled, it will be put at 0) + for (int i = 0; i < 4; i++) { + int data = rc.readSharedArray(CHANNEL.ARCHON_LOC_1.getValue() + i); + int x = data / 64; + int y = data % 64; + if (loc.x == x && loc.y == y) { + return i; // already broadcasted, return index where it is stored + } + if (data == 0) { + indToPut = i; + } + } + int loc_int = locationToInt(loc); + rc.writeSharedArray(indToPut, loc_int); + // rc.setIndicatorString("broadcasting succesful, archon_index " + + // available_index); + return indToPut; + } + + /** + * approachArchon() moves towards the archon specified by archon_index + * + * @return false is the archon is not longer there, true otherwise + **/ + public boolean approachArchon() throws GameActionException { + int data = rc.readSharedArray(archon_index); + if (data != 0) { + int x = data / 64; + int y = data % 64; + MapLocation target = new MapLocation(x, y); + if (rc.canSenseLocation(target)) { + RobotInfo r = rc.senseRobotAtLocation(target); + if (r == null || r.type != RobotType.ARCHON) { + rc.writeSharedArray(archon_index, 0); + archon_index = -1; + return false; + } + + } + moveToLocation(target); + return true; + } else { + archon_index = -1; + return false; // no longer there + } + } + + public boolean transformInto(RobotMode mode) throws GameActionException { + if (rc.getMode() == mode) { + return true; + } + + if (rc.canTransform()) { + rc.transform(); + return true; + } + + return false; + } + + public boolean turret() throws GameActionException { + return transformInto(RobotMode.TURRET); + } + + public boolean attack() throws GameActionException { + return transformInto(RobotMode.PORTABLE); + } + + public Direction getLeastRubbleBuildableDirection(RobotType robotType) throws GameActionException { + int bestDirectionIdx = -1; + int bestDirectionRubble = 100000; + MapLocation me = rc.getLocation(); + for (int i = 0; i < directions.length; i++) { + int rubbleHere = rc.senseRubble(me.add(directions[i])); + if (rubbleHere < bestDirectionRubble && rc.canBuildRobot(robotType, directions[i])) { + bestDirectionRubble = rubbleHere; + bestDirectionIdx = i; + } + } + + if (bestDirectionIdx == -1) { + return null; + } else { + return directions[bestDirectionIdx]; + } + } + public int numFriendlyMiners() { + return numFriendlyMiners(-1); + } + + public int numFriendlyMiners(int rsqr) { + RobotInfo[] allies = rc.senseNearbyRobots(rsqr, rc.getTeam()); + int c = 0; + for (RobotInfo r : allies) { + if (r.type == RobotType.MINER) + c++; + } + return c; + } + + public int senseMiningArea() throws GameActionException { + int value = 0; + int cx = 0; + int cy = 0; + for (MapLocation loc : rc.senseNearbyLocationsWithGold()) { + int margin = rc.senseGold(loc) * goldToLeadConversionRate; + value += margin; + cx += margin * loc.x; + cy += margin * loc.y; + } + for (MapLocation loc : rc.senseNearbyLocationsWithLead()) { + int margin = rc.senseLead(loc) - 1; + value += margin; + cx += margin * loc.x; + cy += margin * loc.y; + } + + if (value >= 25) { + MapLocation dest = new MapLocation(cx / value, cy / value); + // demand disabled for now + int demand = value / minerToLeadRate - numFriendlyMiners(); + if (demand > 0) { + broadcastMiningArea(dest, demand); + } + } + return value; + } + + public void broadcastMiningArea(MapLocation loc, int demand) throws GameActionException { + int indToPut = 0; // where to put the archon (if all spots are filled, it will be put at 0) + // fuzzy location + int x_loc = Math.min((int) Math.round((double) loc.x / 4.0), 15); + int y_loc = Math.min((int) Math.round((double) loc.y / 4.0), 15); + for (int i = 0; i < 5; i++) { + int data = rc.readSharedArray(CHANNEL.MINING1.getValue() + i); + int x = (data >> 4) & 15; + int y = data & 15; + if (x_loc == x && y_loc == y) { + return; + } + if (data == 0) { + indToPut = i; + } + } + int value = (demand << 8) + (x_loc << 4) + y_loc; + rc.setIndicatorDot(new MapLocation(x_loc * 4, y_loc * 4), 255, 0, 0); + // System.out.println("Broadcasting miner request " + x_loc*4 + " " + y_loc*4 + + // " " + demand + " " + rc.getRoundNum()); + rc.writeSharedArray(CHANNEL.MINING1.getValue() + indToPut, value); + } + + public MapLocation findNearestArchon() throws GameActionException { + int min_dist = Integer.MAX_VALUE; + MapLocation closest = null; + for (int i = 0; i < 4; i++) { + int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); + if (data != 0) { + int w = data / 4096; + int x = (data - w * 4096) / 64; + int y = data % 64; + MapLocation loc = new MapLocation(x, y); + int dist = loc.distanceSquaredTo(rc.getLocation()); + if (dist < min_dist) { + min_dist = dist; + closest = loc; + } + } + } + return closest; + } + + /** + * validCoords() check if the x and y are on the map + * + * @return bool, true if on the map + **/ + public boolean validCoords(int x_coord, int y_coord) { + return x_coord >= 0 && x_coord < rc.getMapWidth() && y_coord >= 0 && y_coord < rc.getMapHeight(); + } + + // pathfinding strategies + /** + * moveToLocation() is the moving function that will actually be used by the + * bots (made a separate function for + * easy replacement) + * + * @param loc is where to go + **/ + public void moveToLocation(MapLocation loc) throws GameActionException { + Direction d = mover.getBestDir(loc); + if (d != null && rc.canMove(d)) { + rc.move(d); + } + } + + public void moveInDirection(int[] toDest) throws GameActionException { + MapLocation loc = rc.getLocation(); + MapLocation dest = new MapLocation(loc.x + toDest[0], loc.y + toDest[1]); + Direction d = mover.getBestDir(dest); + // System.out.println(d); + if (d != null) { + if (rc.canMove(d)) rc.move(d); + } + // fuzzyMove(dest); + // rc.setIndicatorString("I JUST MOVED TO " + toDest[0] + " " + toDest[1]); + } + + public MapLocation scaleToEdge(int[] toDest) { + MapLocation loc = rc.getLocation(); + // scaling this directional vector so that it reaches the edge + double scaleFactor = 1000; + if (toDest[0] > 0) { + scaleFactor = Math.min(scaleFactor, ((double) (rc.getMapWidth() - 1 - loc.x)) / ((double) toDest[0])); + } else if (toDest[0] < 0) { + scaleFactor = Math.min(scaleFactor, ((double) (loc.x)) / ((double) -1 * toDest[0])); + } + if (toDest[1] > 0) { + scaleFactor = Math.min(scaleFactor, ((double) (rc.getMapHeight() - 1 - loc.y)) / ((double) toDest[1])); + } else if (toDest[1] < 0) { + scaleFactor = Math.min(scaleFactor, ((double) (loc.y)) / ((double) -1 * toDest[1])); + } + assert (scaleFactor >= 0); + int nx = loc.x + (int) (scaleFactor * (double) toDest[0]); + nx = Math.min(nx, rc.getMapWidth() - 1); + nx = Math.max(nx, 0); + int ny = loc.y + (int) (scaleFactor * (double) toDest[1]); + ny = Math.min(ny, rc.getMapHeight() - 1); + ny = Math.max(ny, 0); + return new MapLocation(nx, ny); + } + + public int[] scaleToSize(int[] toDest) { + return scaleToSize(toDest, 12.0); + } + + public int[] scaleToSize(int[] toDest, double desiredLength) { + double len = Math.sqrt(Math.pow(toDest[0], 2) + Math.pow(toDest[1], 2)); + double scaleFactor = desiredLength / len; + int[] newDir = new int[] { (int) (toDest[0] * scaleFactor), (int) (toDest[1] * scaleFactor) }; + return newDir; + } + + public int cooldown(MapLocation loc) throws GameActionException { + // returns cooldown of movement + return (int) Math.floor((1 + rc.senseRubble(loc) / 10.0) * rc.getType().movementCooldown); + } + + public double cooldownMultiplier(MapLocation loc) throws GameActionException{ + return (1.0+(double)rc.senseRubble(loc)/10.0); + } + + public int[] getExploratoryDir() { + return getExploratoryDir(5, new MapLocation(rc.getMapWidth() / 2, rc.getMapHeight() / 2)); + } + + public int[] getExploratoryDir(int span) { + return getExploratoryDir(span, new MapLocation(rc.getMapWidth() / 2, rc.getMapHeight() / 2)); + } + + public int[] getExploratoryDir(int span, MapLocation loc) { + // presumes span is odd. + int[] dir; + MapLocation cur = rc.getLocation(); + if (loc.x - cur.x > 0) { + if (loc.y - cur.y > 0) { + dir = new int[] { 8, 8 }; + } else { + dir = new int[] { 8, -8 }; + } + } else { + if (loc.y - cur.y > 0) { + dir = new int[] { -8, 8 }; + } else { + dir = new int[] { -8, -8 }; + } + } + int[][] dirs = new int[span][2]; + int counter = 0; + + int increment; + int init_val; + if (dir[0] < 0) { + increment = -4; + init_val = -8 + ((((span + 1) / 2) - 1) * -increment); + } else { + increment = 4; + init_val = 8 + ((((span + 1) / 2) - 1) * -increment); + } + + for (int i = init_val; i != dir[0]; i += increment) { + dirs[counter] = new int[] { i, dir[1] }; + counter += 1; + } + + if (dir[1] < 0) { + increment = -4; + init_val = -8 + ((((span + 1) / 2) - 1) * -increment); + ; + } else { + increment = 4; + init_val = 8 + ((((span + 1) / 2) - 1) * -increment); + ; + } + + for (int i = init_val; i != dir[1]; i += increment) { + dirs[counter] = new int[] { dir[0], i }; + counter += 1; + } + + dirs[dirs.length - 1] = dir; + // print directions + // rc.setIndicatorString("dirs: " + dirs[0][0] + " " + dirs[0][1] + " " + + // dirs[1][0] + " " + dirs[1][1] + " " + dirs[2][0] + " " + dirs[2][1] + " " + + // dirs[3][0] + " " + dirs[3][1] + " " + dirs[4][0] + " " + dirs[4][1] + " | " + + // (center.x - cur.x) + " " + (center.y - cur.y) + " | " + center.x + " " + + // center.y + " | " + cur.x + " " + cur.y); + + return dirs[rng.nextInt(dirs.length)]; + } + + public boolean adjacentToEdge() throws GameActionException { + MapLocation cur = rc.getLocation(); + int mapheight = rc.getMapHeight(); + int mapwidth = rc.getMapWidth(); + if (mapheight - cur.y < 3 || cur.y < 3 || cur.x < 3 || mapwidth - cur.x < 3) { + return true; + } + return false; + } + + public int[] flip(int[] dir) {// directional vector input + assert (dir.length == 2); + MapLocation loc = rc.getLocation(); + int[] ret = new int[2]; + ret[0] = dir[0]; + ret[1] = dir[1]; + if (loc.x < 5 && ret[0] < 0) { + ret[0] = -1 * ret[0]; + } + if (loc.y < 5 && ret[1] < 0) { + ret[1] = -1 * ret[1]; + } + if (rc.getMapWidth() - loc.x < 5 && ret[0] > 0) { + ret[0] = -1 * ret[0]; + } + if (rc.getMapHeight() - loc.y < 5 && ret[1] > 0) { + ret[1] = -1 * ret[1]; + } + return ret; + } + + public MapLocation findHomeArchon() throws GameActionException { + if (rc.getType() == RobotType.ARCHON) { + return rc.getLocation(); + } + RobotInfo[] nearbyBots = rc.senseNearbyRobots(1, rc.getTeam()); + // if there are any nearby enemy robots, attack the one with the least health + if (nearbyBots.length > 0) { + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.ARCHON) { + return bot.location; + } + } + } + return rc.getLocation(); + } + + public int locationToInt(MapLocation loc) { + return 64 * loc.x + loc.y; + } + + public RANK[] initializeRankMap() { + RANK[] map = new RANK[64]; + RANK[] ranks = RANK.values(); + for (int i = 0; i < ranks.length; i++) { + map[ranks[i].getValue()] = ranks[i]; + } + return map; + } + + public RANK getRank(int index) { + return rank_map[index]; + } + + public RANK findRank() throws GameActionException { + rc.setIndicatorString("READY TO READ"); + int data; + // check all channels to see if you've received a rank + for (int i = 0; i < 2; i++) { + if (i == 0) { + data = rc.readSharedArray(CHANNEL.SEND_RANKS1.getValue()); + } else { + data = rc.readSharedArray(CHANNEL.SEND_RANKS2.getValue()); + } + + int status = data / 4096; + int x = (data - (4096 * status)) / 64; + int y = (data - (4096 * status) - (x * 64)); + + // only set rank if instructed to. + if (homeArchon.equals(new MapLocation(x, y))) { + return getRank(status); + } + } + return RANK.DEFAULT; + } + + public int getMapArea() { + return rc.getMapHeight() * rc.getMapWidth(); + } + + // should add channels for each unit... + public void updateCount() throws GameActionException { + RobotType r = rc.getType(); + switch (r) { + case MINER: + int num = rc.readSharedArray(CHANNEL.MINERS_ALIVE.getValue()); + rc.writeSharedArray(CHANNEL.MINERS_ALIVE.getValue(), num + 1); + case SOLDIER: + num = rc.readSharedArray(CHANNEL.SOLDIERS_ALIVE.getValue()); + rc.writeSharedArray(CHANNEL.SOLDIERS_ALIVE.getValue(), num + 1); + case BUILDER: + num = rc.readSharedArray(CHANNEL.BUILDERS_ALIVE.getValue()); + rc.writeSharedArray(CHANNEL.BUILDERS_ALIVE.getValue(), num + 1); + default: + break; + + } + } + + public void broadcastTarget(MapLocation enemy) throws GameActionException { + int indToPut = 0; // where to put the archon (if all spots are filled, it will be put at 0) + // fuzzy location + int x_loc = enemy.x; + int y_loc = enemy.y; + for (int i = 0; i < CHANNEL.NUM_TARGETS; i++) { + int data = rc.readSharedArray(CHANNEL.TARGET.getValue() + i); + int x = (data >> 4) & 15; + int y = data & 15; + if (x_loc == x && y_loc == y) { + return; + } + MapLocation loc = new MapLocation(x, y); + // don't store closeby targets + if (loc.distanceSquaredTo(enemy) < 6) return; + if (data == 0) { + indToPut = i; + } + } + int value = x_loc * 64 + y_loc; + rc.setIndicatorDot(new MapLocation(x_loc, y_loc), 0, 100, 0); + rc.writeSharedArray(CHANNEL.TARGET.getValue() + indToPut, value); + // System.out.println("I broadcasted an enemy at " + enemy.toString()); + } +} diff --git a/src/rebutia_micro_heal/Watchtower.java b/src/rebutia_micro_heal/Watchtower.java new file mode 100644 index 0000000..5df2311 --- /dev/null +++ b/src/rebutia_micro_heal/Watchtower.java @@ -0,0 +1,499 @@ +package rebutia_micro_heal; + +import java.util.Comparator; +import java.util.PriorityQueue; + +import battlecode.common.Direction; +import battlecode.common.GameActionException; +import battlecode.common.MapLocation; +import battlecode.common.RobotController; +import battlecode.common.RobotInfo; +import battlecode.common.RobotMode; +import battlecode.common.RobotType; + +public class Watchtower extends Unit { + + enum MODE { + BRANCH_OUT, + SEEKING, + RETURNING, + DEFENDING, + NONE; + } + + boolean attacked = false; + boolean anchored = false; + + int round_num = 0; + + MapLocation[] threatenedArchons; + MapLocation baseArchonLocation; + MapLocation anchorLocation; + PriorityQueue enemyQueue = new PriorityQueue(10, new Comparator() { + public int compare(RobotInfo r1, RobotInfo r2) { + return r1.health - r2.health; + } + }); + + // up to 10 manhattan distance yk + public static final int ANCHOR_DISTANCE = 3; + + MODE mode; + + // for attacking and searching enemies modes + private MapLocation target = null; + private int[] lastAttackDir = null; + + public Watchtower(RobotController rc) throws GameActionException { + super(rc); + initialize(); + } + + public void run() throws GameActionException { + super.run(); + round_num = rc.getRoundNum(); + radio.updateCounter(); + attacked = attemptAttack(false); + senseMiningArea(); + + mode = determineMode(); + // moved visualize() to bottom + switch (mode) { + case SEEKING: + if (this.transformInto(RobotMode.TURRET)) { + if (target != null) { + huntTarget(); + } else { + moveInDirection(lastAttackDir); + } + } + target = null; + break; + case BRANCH_OUT: + // Choose an anchor location + if (anchorLocation == null) { + // this may return null + anchorLocation = chooseAnchorLocation(); + } + if (anchorLocation != null) { + if (this.transformInto(RobotMode.PORTABLE)) { + Direction dir = rc.getLocation().directionTo(anchorLocation); + if (!rc.canMove(dir)) { + // it's okay to anchor if the space is occupied and we're within two squares of + // it + if (rc.getLocation().isWithinDistanceSquared(anchorLocation, 2)) { + anchored = true; + break; + } + } else { + moveToLocation(anchorLocation); + } + } + } + break; + case DEFENDING: + this.transformInto(RobotMode.TURRET); + + // Use a priority queue for enemies + // This queue is based on the health of the enemy + while (!this.enemyQueue.isEmpty()) { + RobotInfo enemy = this.enemyQueue.poll(); + while (rc.canAttack(enemy.location)) { + rc.attack(enemy.location); + } + } + break; + case RETURNING: + moveToLocation(anchorLocation); + break; + case NONE: + break; + } + + visualize(); + + } + + public boolean isMapLocationValid(MapLocation loc) { + return loc.x >= 0 && loc.x < rc.getMapWidth() && loc.y >= 0 && loc.y < rc.getMapHeight(); + } + + public MapLocation chooseAnchorLocation() { + if (baseArchonLocation == null) { + return null; + } + MapLocation me = rc.getLocation(); + MapLocation anchorLocation; + int minDistanceSquared = ANCHOR_DISTANCE * ANCHOR_DISTANCE; + for (Direction d : Direction.values()) { + // branch out in all 8 directions, look for the best place to anchor + anchorLocation = new MapLocation(me.x + d.dx * ANCHOR_DISTANCE, me.y + d.dy * ANCHOR_DISTANCE); + if (isMapLocationValid(anchorLocation) + && anchorLocation.distanceSquaredTo(baseArchonLocation) >= minDistanceSquared) { + return anchorLocation; + } + } + return null; + } + + public void visualize() throws GameActionException { + String indicator = ""; + if (rc.getMode() == RobotMode.TURRET) { + indicator += "T."; + } else { + indicator += "P."; + } + + indicator += " " + mode.toString(); + + if (mode == MODE.BRANCH_OUT) { + indicator += " to " + anchorLocation.toString(); + } else if (mode == MODE.SEEKING) { + if (target != null) { + rc.setIndicatorLine(rc.getLocation(), target, 255, 0, 0); + } + } + + if (target != null) { + indicator += " target " + target.toString(); + rc.setIndicatorLine(rc.getLocation(), target, 0, 0, 100); + } + + rc.setIndicatorString(indicator); + } + + public MODE determineMode() throws GameActionException { + this.enemyQueue.clear(); + + // If there are nearby enemies, attack them + for (RobotInfo ri : rc.senseNearbyRobots(-1, rc.getTeam().opponent())) { + if (ri.type == RobotType.SOLDIER) { + this.enemyQueue.add(ri); + } + } + + if (!this.enemyQueue.isEmpty()) { + return MODE.DEFENDING; + } + + // At the start of the game, branch out from the Archon + // Make sure always 10 units^2 away from the Archon + // Branch out + if (!anchored) { + if (baseArchonLocation == null) { + RobotInfo[] nearby = rc.senseNearbyRobots(10, rc.getTeam()); + for (RobotInfo ri : nearby) { + if (ri.type == RobotType.ARCHON) { + baseArchonLocation = ri.location; + return MODE.BRANCH_OUT; + } + } + } else if (baseArchonLocation.isWithinDistanceSquared(rc.getLocation(), 10)) { + return MODE.BRANCH_OUT; + } + } + + // // Priority 3 - Hunt enemies. + // findTargets(); + // if (target != null) { + // if (rc.getLocation().distanceSquaredTo(target) > 40) { + // return MODE.SEEKING; + // } else { + // Direction lowRubble = findLowRubble(); + // if (lowRubble != null) + // rc.move(lowRubble); + // if (rc.getMode() == RobotMode.PORTABLE && rc.canTransform()) + // rc.transform(); + // return MODE.DEFENDING; + // } + // } else if (lastAttackDir != null) { + // return MODE.SEEKING; + // } + + if (rc.getLocation().distanceSquaredTo(anchorLocation) > 2) { + return MODE.RETURNING; + } + return MODE.NONE; + } + + public int[] fleeDirection() throws GameActionException { + MapLocation cur = rc.getLocation(); + RobotInfo[] nearbyBots = rc.senseNearbyRobots(-1); + double cxse = 0; + double cyse = 0; + int numEnemies = 0; + int numEnemyHits = 0; + int numFriendHits = (rc.getHealth() + 2) / 3; + int numFriends = 0; + for (RobotInfo bot : nearbyBots) { + if (bot.team == rc.getTeam()) { + if (bot.type == RobotType.SOLDIER) { + numFriendHits += ((bot.health + 2) / 3); + numFriends++; + } + } else if (bot.team == rc.getTeam().opponent()) + if (bot.type == RobotType.SOLDIER) { + cxse += bot.location.x; + cyse += bot.location.y; + numEnemyHits += ((bot.health + 2) / 3); + numEnemies++; + } + } + if (numEnemies == 0) + return new int[] { Integer.MAX_VALUE, Integer.MAX_VALUE }; + + if (numEnemies > 0) { + cxse /= numEnemies; + cyse /= numEnemies; + } + + double unit_difference = (double) (numFriends + 1 - numEnemies); + double ratio; + + if (((numFriends + 1) / numEnemies) > 1) { + ratio = ((numFriends + 1) / numEnemies); + } else { + ratio = numEnemies / (numFriends + 1); + } + + double a = 6 * ratio; + int unit_advantage = (int) (a * Math.pow(unit_difference, 2) * Math.signum(unit_difference)); + + // System.out.println("Unit advantage: " + unit_advantage + " Ratio: " + ratio + + // " numFriendHits " + numFriendHits + " numEnemyHits " + numEnemyHits + + // "round_num " + round_num + " id " + rc.getID()); + + if (numFriendHits + unit_advantage < numEnemyHits) { + double dx = -(cxse - cur.x) * 3; + double dy = -(cyse - cur.y) * 3; + // more attracted + // dx = 0.7 * dx + 0.3 * (cxsf - cur.x); + // dy = 0.7 * dx + 0.3 * (cysf - cur.y); + return new int[] { (int) dx, (int) dy }; + } + return new int[] { Integer.MAX_VALUE, Integer.MAX_VALUE }; + } + + public void findTargets() throws GameActionException { + int data; + int closestDist = 100000; + MapLocation cur = rc.getLocation(); + MapLocation closestTarget = null; + for (int i = 0; i < CHANNEL.NUM_TARGETS; i++) { + data = rc.readSharedArray(CHANNEL.TARGET.getValue() + i); + if (data != 0) { + int x = (data >> 4) & 15; + int y = data & 15; + // System.out.println("I received an enemy at " + x*4 + " " + y*4 + " on round " + // + round_num); + MapLocation potentialTarget = new MapLocation(x * 4, y * 4); + if (cur.distanceSquaredTo(potentialTarget) < closestDist) { + closestDist = cur.distanceSquaredTo(potentialTarget); + closestTarget = potentialTarget; + } + } + } + + // finds closest target, and advances towards it. + if (closestTarget != null) { + target = closestTarget; + lastAttackDir = new int[] { closestTarget.x - cur.x, closestTarget.y - cur.y }; + lastAttackDir = scaleToSize(lastAttackDir); + // wanders in direction of target + } + } + + public void huntTarget() throws GameActionException { + // if target is within 3 tiles, do not move closer, otherwise move closer + // check if it's in turret mode + if (rc.getMode() == RobotMode.TURRET) + return; + moveToLocation(target); + lastAttackDir = new int[] { target.x - rc.getLocation().x, target.y - rc.getLocation().y }; + if (rc.getLocation().distanceSquaredTo(target) <= 20) { + // check for low rubble squares to move to + Direction lowRubble = findLowRubble(); + if (lowRubble != null) + rc.move(lowRubble); + } else + moveInDirection(lastAttackDir); + } + + public Direction findLowRubble() throws GameActionException { + MapLocation cur = rc.getLocation(); + int lowest_rubble = 1 + rc.senseRubble(cur) / 10; + int rubble; + Direction bestDir = null; + for (int i = 0; i < 8; i++) { + if (!rc.canMove(directions[i])) + continue; + rubble = 1 + rc.senseRubble(cur.add(directions[i])) / 10; + if (rubble < lowest_rubble && rc.canMove(directions[i])) { + lowest_rubble = rubble; + bestDir = directions[i]; + } + } + return bestDir; + } + + public void defensiveMove() throws GameActionException { + MapLocation closest = threatenedArchons[0]; + int min_dist = Integer.MAX_VALUE; + // only find closest archon if there is more then one + if (threatenedArchons.length > 1) { + for (MapLocation loc : threatenedArchons) { + if (loc.distanceSquaredTo(rc.getLocation()) < min_dist) { + min_dist = loc.distanceSquaredTo(rc.getLocation()); + closest = loc; + } + } + } + // if you don't see the enemy, and you're not close to the archon, move towards + // it + if (rc.getLocation().distanceSquaredTo(closest) > 36 || target == null) { + moveToLocation(closest); + } else { + huntTarget(); + } + } + + public boolean archonDied() throws GameActionException { + RobotInfo home; + if (rc.canSenseLocation(homeArchon)) { + home = rc.senseRobotAtLocation(homeArchon); + return (home == null || home.type != RobotType.ARCHON); + } + return false; + } + + public MapLocation[] findThreatenedArchons() throws GameActionException { + int data; + MapLocation[] archons = new MapLocation[4]; + int numThreatenedArchons = 0; + for (int i = 0; i < 4; i++) { + // rc.writeSharedArray(, value); + data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); + // go through channels until you find an empty one to communicate with. + if (data != 0) { + int x = data / 64; + int y = data % 64; + if (validCoords(x, y)) { + archons[numThreatenedArchons] = new MapLocation(x, y); + numThreatenedArchons++; + } + } + } + + if (numThreatenedArchons == 0) { + return null; + } else { + // only return threatened archons. + MapLocation[] threatenedArchons = new MapLocation[numThreatenedArchons]; + for (int i = 0; i < numThreatenedArchons; i++) { + threatenedArchons[i] = archons[i]; + } + return threatenedArchons; + } + } + + public boolean attemptAttack(boolean attackMiners) throws GameActionException { + RobotInfo[] nearbyBots = rc.senseNearbyRobots(RobotType.SOLDIER.actionRadiusSquared, rc.getTeam().opponent()); + int weakestSoldierHealth = 100000; + int weakestMinerHealth = 100000; + int weakestSageHealth = 100000; + int weakestTowerHealth = 100000; + int weakestBuilerHealth = 100000; + RobotInfo weakestSoldier = null; + RobotInfo weakestTower = null; + RobotInfo weakestSage = null; + RobotInfo weakestMiner = null; + RobotInfo weakestBuilder = null; + RobotInfo archon = null; + // if there are any nearby enemy robots, attack the one with the least health + if (nearbyBots.length > 0) { + for (RobotInfo bot : nearbyBots) { + if (bot.type == RobotType.SOLDIER) { + if (bot.health < weakestSoldierHealth) { + weakestSoldier = bot; + weakestSoldierHealth = bot.health; + } + } + if (bot.type == RobotType.MINER) { + if (bot.health < weakestMinerHealth) { + weakestMiner = bot; + weakestMinerHealth = bot.health; + } + } + if (bot.type == RobotType.WATCHTOWER) { + if (bot.health < weakestTowerHealth) { + weakestTower = bot; + weakestTowerHealth = bot.health; + } + } + if (bot.type == RobotType.SAGE) { + if (bot.health < weakestSageHealth) { + weakestSage = bot; + weakestSageHealth = bot.health; + } + } + if (bot.type == RobotType.BUILDER) { + if (bot.health < weakestBuilerHealth) { + weakestBuilder = bot; + weakestBuilerHealth = bot.health; + } + } + if (bot.type == RobotType.ARCHON) { + archon = bot; + } + } + // make more conditional, like damaging which one would give the biggest + // advantage + if (weakestSage != null) { + if (rc.canAttack(weakestSage.location)) { + rc.attack(weakestSage.location); + target = weakestSage.location; + broadcastTarget(weakestSage.location); + return true; + } + } else if (weakestSoldier != null) { + if (rc.canAttack(weakestSoldier.location)) { + rc.attack(weakestSoldier.location); + target = weakestSoldier.location; + broadcastTarget(weakestSoldier.location); + return true; + } + } else if (weakestTower != null) { + if (rc.canAttack(weakestTower.location)) { + rc.attack(weakestTower.location); + target = weakestTower.location; + broadcastTarget(weakestTower.location); + return true; + } + } else if (weakestMiner != null && attackMiners) { + if (rc.canAttack(weakestMiner.location)) { + rc.attack(weakestMiner.location); + target = weakestMiner.location; + broadcastTarget(weakestMiner.location); + return true; + } + } else if (weakestBuilder != null && attackMiners) { + if (rc.canAttack(weakestBuilder.location)) { + rc.attack(weakestBuilder.location); + target = weakestBuilder.location; + broadcastTarget(weakestBuilder.location); + return true; + } + } else if (archon != null) { + if (rc.canAttack(archon.location)) { + rc.attack(archon.location); + broadcastTarget(archon.location); + return true; + } + } + } + return false; + } + + public void initialize() { + } +} \ No newline at end of file From 8086b0571f744c99a92e65f3d0e578e8b7d1f9d7 Mon Sep 17 00:00:00 2001 From: 2022tgoel Date: Sun, 23 Jan 2022 19:41:28 -0500 Subject: [PATCH 2/6] soldier healing --- src/rebutia_micro_heal/Archon.java | 1 + src/rebutia_micro_heal/CHANNEL.java | 2 +- src/rebutia_micro_heal/Comms.java | 20 +++++++++++-- src/rebutia_micro_heal/Soldier.java | 46 +++++++++++++++++++++++++++-- 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/rebutia_micro_heal/Archon.java b/src/rebutia_micro_heal/Archon.java index d28ad28..bf5a592 100644 --- a/src/rebutia_micro_heal/Archon.java +++ b/src/rebutia_micro_heal/Archon.java @@ -60,6 +60,7 @@ public void run() throws GameActionException { updateAmountMined(); archonNumber = radio.getArchonNum(); + radio.postArchonLocation(archonNumber); troopCounter = new int[] { radio.readCounter(RobotType.MINER), diff --git a/src/rebutia_micro_heal/CHANNEL.java b/src/rebutia_micro_heal/CHANNEL.java index 8e1e70d..7fb1b68 100644 --- a/src/rebutia_micro_heal/CHANNEL.java +++ b/src/rebutia_micro_heal/CHANNEL.java @@ -22,7 +22,7 @@ public enum CHANNEL { MINING1(30), TARGET(35), ARCHON_MODE(40), - + ARCHON_POSITION(44), //44-47 ORDERS(61), SEND_RANKS1(62), SEND_RANKS2(63), diff --git a/src/rebutia_micro_heal/Comms.java b/src/rebutia_micro_heal/Comms.java index 30bc94a..92797c8 100644 --- a/src/rebutia_micro_heal/Comms.java +++ b/src/rebutia_micro_heal/Comms.java @@ -120,7 +120,8 @@ public BOT getPreviousBuild() throws GameActionException { public void clearThreat() throws GameActionException { if (round_num % 15 == 0) { for (int i = 0; i < 4; i++) { - rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i, 0); + int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); + rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i, data%4096); } } } @@ -146,7 +147,8 @@ public void initalizeArchonLoc(int archonIndex, MapLocation loc) throws GameActi rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + archonIndex, locInt); } - public MapLocation[] getFriendlyArchons(int num_archons) throws GameActionException { + public MapLocation[] getFriendlyArchons(int num_archons) throws GameActionException { + //THIS DOES NOT WORK, fARCHON does not contain the correct values MapLocation[] locs = new MapLocation[num_archons]; for (int i = 0; i < num_archons; i++) { int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); @@ -240,6 +242,20 @@ public int getArchonNum() throws GameActionException { return archonNumber; } + public void postArchonLocation(int archonNumber)throws GameActionException{ + MapLocation my = rc.getLocation(); + int data = my.x*64 + my.y; + rc.writeSharedArray(CHANNEL.ARCHON_POSITION.getValue() + archonNumber, data); + } + + public MapLocation readArchonLocation(int archonNumber) throws GameActionException{ + int data = rc.readSharedArray(CHANNEL.ARCHON_POSITION.getValue() + archonNumber); + if (data == 0){ + System.out.println("this archon position has not been updated yet"); + } + return new MapLocation(data/64, data%64); + } + public void postRank(RANK rank) throws GameActionException { MapLocation loc = rc.getLocation(); int loc_int; diff --git a/src/rebutia_micro_heal/Soldier.java b/src/rebutia_micro_heal/Soldier.java index c3538ab..7619bcf 100644 --- a/src/rebutia_micro_heal/Soldier.java +++ b/src/rebutia_micro_heal/Soldier.java @@ -12,7 +12,7 @@ enum MODE { SEARCHING_ENEMIES, //when u have already found enemies FLEE, DEFENSIVE_RUSH, - DYING + HEALING ; } @@ -38,10 +38,12 @@ enum MODE { private MapLocation target = null; private int[] lastAttackDir = null; + Comms comms; public Soldier(RobotController rc) throws GameActionException { super(rc); initialize(); exploreLoc = getInitialExploratoryLocation(); + comms = new Comms(rc); } @Override public void run() throws GameActionException { @@ -55,6 +57,8 @@ public void run() throws GameActionException { mode = determineMode(); visualize(); switch (mode) { + case HEALING: + moveToArchon(); case EXPLORATORY: if (soldierBehindMe()) { if (adjacentToEdge()){ @@ -98,6 +102,9 @@ else if (mode == MODE.HUNTING){ else if (mode == MODE.SEARCHING_ENEMIES){ rc.setIndicatorString("MODE: " + mode.toString() + " DIR: " + lastAttackDir[0] + " " + lastAttackDir[1]); } + else if (mode == MODE.HEALING){ + rc.setIndicatorLine(rc.getLocation(), closestArchon, 0, 0, 255); + } else if (target != null) { if (mode != MODE.FLEE) rc.setIndicatorString("TARGET: " + target.toString() + " MODE: " + mode.toString()); else rc.setIndicatorString("TARGET: " + target.toString() + " MODE: FLEE " + "FLEEROUND: " + stopFleeingRound); @@ -110,7 +117,9 @@ else if (target != null) { } public MODE determineMode() throws GameActionException { - + //Priority 0 - Heal + if (shouldHeal()) return MODE.HEALING; + // Priority 1 - Defend. threatenedArchons = findThreatenedArchons(); if (threatenedArchons != null) { @@ -147,6 +156,39 @@ else if (lastAttackDir != null){ else return MODE.EXPLORATORY; } + MapLocation closestArchon = null; + public boolean shouldHeal() throws GameActionException{ + if (closestArchon!=null && rc.getHealth() < rc.getType().health){ + return true; + } + else if (rc.getHealth() <= 15){ // toggle to is healing + MapLocation my = rc.getLocation(); + closestArchon = null; + for (int i = 0; i < rc.getArchonCount(); i++) { + MapLocation archonLoc = comms.readArchonLocation(i); + System.out.println(archonLoc.toString()); + if (my.distanceSquaredTo(archonLoc) <= 300 ){ + if (closestArchon == null) + closestArchon = archonLoc; + else if (my.distanceSquaredTo(archonLoc) < my.distanceSquaredTo(closestArchon)) + closestArchon = archonLoc; + } + } + if (closestArchon!=null) { + return true; + } + } + //toggle off + closestArchon = null; + return false; + } + + public void moveToArchon() throws GameActionException{ + if (!rc.canSenseLocation(closestArchon)){ + moveToLocation(closestArchon); + } + } + /** * getInitialExploratoryLocation() gets the location when you extend the vector from your location * to the center to the edge From ab0e8123b69e5d19cb41d3d25893305cbad6dd51 Mon Sep 17 00:00:00 2001 From: 2022tgoel Date: Sun, 23 Jan 2022 19:52:44 -0500 Subject: [PATCH 3/6] healing forks off the new rebutia_micro_new --- src/{rebutia_micro_heal => rebutia_heal}/Archon.java | 2 +- src/{rebutia_micro_heal => rebutia_heal}/BOT.java | 2 +- .../BiCHANNEL.java | 2 +- .../Builder.java | 2 +- .../CHANNEL.java | 2 +- .../CONSTANTS.java | 2 +- src/{rebutia_micro_heal => rebutia_heal}/Comms.java | 12 +++++------- .../Laboratory.java | 2 +- src/{rebutia_micro_heal => rebutia_heal}/Miner.java | 2 +- .../MinerNav.java | 2 +- .../Navigation.java | 2 +- src/{rebutia_micro_heal => rebutia_heal}/RANK.java | 2 +- .../RobotPlayer.java | 2 +- src/{rebutia_micro_heal => rebutia_heal}/Sage.java | 2 +- .../Soldier.java | 12 ++++++------ src/{rebutia_micro_heal => rebutia_heal}/Unit.java | 2 +- .../Watchtower.java | 2 +- 17 files changed, 26 insertions(+), 28 deletions(-) rename src/{rebutia_micro_heal => rebutia_heal}/Archon.java (99%) rename src/{rebutia_micro_heal => rebutia_heal}/BOT.java (89%) rename src/{rebutia_micro_heal => rebutia_heal}/BiCHANNEL.java (96%) rename src/{rebutia_micro_heal => rebutia_heal}/Builder.java (99%) rename src/{rebutia_micro_heal => rebutia_heal}/CHANNEL.java (96%) rename src/{rebutia_micro_heal => rebutia_heal}/CONSTANTS.java (92%) rename src/{rebutia_micro_heal => rebutia_heal}/Comms.java (97%) rename src/{rebutia_micro_heal => rebutia_heal}/Laboratory.java (89%) rename src/{rebutia_micro_heal => rebutia_heal}/Miner.java (99%) rename src/{rebutia_micro_heal => rebutia_heal}/MinerNav.java (98%) rename src/{rebutia_micro_heal => rebutia_heal}/Navigation.java (99%) rename src/{rebutia_micro_heal => rebutia_heal}/RANK.java (86%) rename src/{rebutia_micro_heal => rebutia_heal}/RobotPlayer.java (99%) rename src/{rebutia_micro_heal => rebutia_heal}/Sage.java (99%) rename src/{rebutia_micro_heal => rebutia_heal}/Soldier.java (99%) rename src/{rebutia_micro_heal => rebutia_heal}/Unit.java (99%) rename src/{rebutia_micro_heal => rebutia_heal}/Watchtower.java (99%) diff --git a/src/rebutia_micro_heal/Archon.java b/src/rebutia_heal/Archon.java similarity index 99% rename from src/rebutia_micro_heal/Archon.java rename to src/rebutia_heal/Archon.java index bf5a592..030cf2f 100644 --- a/src/rebutia_micro_heal/Archon.java +++ b/src/rebutia_heal/Archon.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; import java.util.*; diff --git a/src/rebutia_micro_heal/BOT.java b/src/rebutia_heal/BOT.java similarity index 89% rename from src/rebutia_micro_heal/BOT.java rename to src/rebutia_heal/BOT.java index 0d3f740..3984b55 100644 --- a/src/rebutia_micro_heal/BOT.java +++ b/src/rebutia_heal/BOT.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; public enum BOT { NONE(0), diff --git a/src/rebutia_micro_heal/BiCHANNEL.java b/src/rebutia_heal/BiCHANNEL.java similarity index 96% rename from src/rebutia_micro_heal/BiCHANNEL.java rename to src/rebutia_heal/BiCHANNEL.java index 60aabaa..8fb8d06 100644 --- a/src/rebutia_micro_heal/BiCHANNEL.java +++ b/src/rebutia_heal/BiCHANNEL.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; /** * For BiCHANNEL communications using one-round lagging updates. diff --git a/src/rebutia_micro_heal/Builder.java b/src/rebutia_heal/Builder.java similarity index 99% rename from src/rebutia_micro_heal/Builder.java rename to src/rebutia_heal/Builder.java index b754976..171b3a7 100644 --- a/src/rebutia_micro_heal/Builder.java +++ b/src/rebutia_heal/Builder.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; import java.util.*; diff --git a/src/rebutia_micro_heal/CHANNEL.java b/src/rebutia_heal/CHANNEL.java similarity index 96% rename from src/rebutia_micro_heal/CHANNEL.java rename to src/rebutia_heal/CHANNEL.java index 7fb1b68..c31b9ea 100644 --- a/src/rebutia_micro_heal/CHANNEL.java +++ b/src/rebutia_heal/CHANNEL.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; public enum CHANNEL { ROUND_NUM(0), diff --git a/src/rebutia_micro_heal/CONSTANTS.java b/src/rebutia_heal/CONSTANTS.java similarity index 92% rename from src/rebutia_micro_heal/CONSTANTS.java rename to src/rebutia_heal/CONSTANTS.java index d7fa1f0..f3a11cd 100644 --- a/src/rebutia_micro_heal/CONSTANTS.java +++ b/src/rebutia_heal/CONSTANTS.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.Direction; diff --git a/src/rebutia_micro_heal/Comms.java b/src/rebutia_heal/Comms.java similarity index 97% rename from src/rebutia_micro_heal/Comms.java rename to src/rebutia_heal/Comms.java index 92797c8..7dfb20d 100644 --- a/src/rebutia_micro_heal/Comms.java +++ b/src/rebutia_heal/Comms.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; @@ -120,8 +120,7 @@ public BOT getPreviousBuild() throws GameActionException { public void clearThreat() throws GameActionException { if (round_num % 15 == 0) { for (int i = 0; i < 4; i++) { - int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); - rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i, data%4096); + rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i, 0); } } } @@ -147,8 +146,7 @@ public void initalizeArchonLoc(int archonIndex, MapLocation loc) throws GameActi rc.writeSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + archonIndex, locInt); } - public MapLocation[] getFriendlyArchons(int num_archons) throws GameActionException { - //THIS DOES NOT WORK, fARCHON does not contain the correct values + public MapLocation[] getFriendlyArchons(int num_archons) throws GameActionException { MapLocation[] locs = new MapLocation[num_archons]; for (int i = 0; i < num_archons; i++) { int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); @@ -186,7 +184,7 @@ public int sendThreatAlert() throws GameActionException { int data = rc.readSharedArray(CHANNEL.fARCHON_STATUS1.getValue() + i); // go through channels until you find an empty one to communicate with. int w = data / 4096; - int x = data / 64; + int x = (data - w * 4096) / 64; int y = data % 64; // already alerted. if (w == 1 && x == my.x && y == my.y) { @@ -255,7 +253,7 @@ public MapLocation readArchonLocation(int archonNumber) throws GameActionExcepti } return new MapLocation(data/64, data%64); } - + public void postRank(RANK rank) throws GameActionException { MapLocation loc = rc.getLocation(); int loc_int; diff --git a/src/rebutia_micro_heal/Laboratory.java b/src/rebutia_heal/Laboratory.java similarity index 89% rename from src/rebutia_micro_heal/Laboratory.java rename to src/rebutia_heal/Laboratory.java index 2519bd3..86713c1 100644 --- a/src/rebutia_micro_heal/Laboratory.java +++ b/src/rebutia_heal/Laboratory.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; import java.util.*; diff --git a/src/rebutia_micro_heal/Miner.java b/src/rebutia_heal/Miner.java similarity index 99% rename from src/rebutia_micro_heal/Miner.java rename to src/rebutia_heal/Miner.java index ebdb1e2..7f25cfe 100644 --- a/src/rebutia_micro_heal/Miner.java +++ b/src/rebutia_heal/Miner.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; import java.util.*; diff --git a/src/rebutia_micro_heal/MinerNav.java b/src/rebutia_heal/MinerNav.java similarity index 98% rename from src/rebutia_micro_heal/MinerNav.java rename to src/rebutia_heal/MinerNav.java index 6ad1234..6bb499f 100644 --- a/src/rebutia_micro_heal/MinerNav.java +++ b/src/rebutia_heal/MinerNav.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; public class MinerNav { diff --git a/src/rebutia_micro_heal/Navigation.java b/src/rebutia_heal/Navigation.java similarity index 99% rename from src/rebutia_micro_heal/Navigation.java rename to src/rebutia_heal/Navigation.java index 709d39f..88cded1 100644 --- a/src/rebutia_micro_heal/Navigation.java +++ b/src/rebutia_heal/Navigation.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; public class Navigation { static RobotController rc; diff --git a/src/rebutia_micro_heal/RANK.java b/src/rebutia_heal/RANK.java similarity index 86% rename from src/rebutia_micro_heal/RANK.java rename to src/rebutia_heal/RANK.java index 8844b24..67a8625 100644 --- a/src/rebutia_micro_heal/RANK.java +++ b/src/rebutia_heal/RANK.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; public enum RANK { DEFAULT(0), diff --git a/src/rebutia_micro_heal/RobotPlayer.java b/src/rebutia_heal/RobotPlayer.java similarity index 99% rename from src/rebutia_micro_heal/RobotPlayer.java rename to src/rebutia_heal/RobotPlayer.java index bc9c81a..ab7d4e1 100644 --- a/src/rebutia_micro_heal/RobotPlayer.java +++ b/src/rebutia_heal/RobotPlayer.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; import java.util.Random; diff --git a/src/rebutia_micro_heal/Sage.java b/src/rebutia_heal/Sage.java similarity index 99% rename from src/rebutia_micro_heal/Sage.java rename to src/rebutia_heal/Sage.java index 3e78b67..528daa4 100644 --- a/src/rebutia_micro_heal/Sage.java +++ b/src/rebutia_heal/Sage.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; import java.util.*; diff --git a/src/rebutia_micro_heal/Soldier.java b/src/rebutia_heal/Soldier.java similarity index 99% rename from src/rebutia_micro_heal/Soldier.java rename to src/rebutia_heal/Soldier.java index 7619bcf..8d638b9 100644 --- a/src/rebutia_micro_heal/Soldier.java +++ b/src/rebutia_heal/Soldier.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; @@ -45,6 +45,7 @@ public Soldier(RobotController rc) throws GameActionException { exploreLoc = getInitialExploratoryLocation(); comms = new Comms(rc); } + @Override public void run() throws GameActionException { super.run(); @@ -59,6 +60,7 @@ public void run() throws GameActionException { switch (mode) { case HEALING: moveToArchon(); + break; case EXPLORATORY: if (soldierBehindMe()) { if (adjacentToEdge()){ @@ -102,9 +104,6 @@ else if (mode == MODE.HUNTING){ else if (mode == MODE.SEARCHING_ENEMIES){ rc.setIndicatorString("MODE: " + mode.toString() + " DIR: " + lastAttackDir[0] + " " + lastAttackDir[1]); } - else if (mode == MODE.HEALING){ - rc.setIndicatorLine(rc.getLocation(), closestArchon, 0, 0, 255); - } else if (target != null) { if (mode != MODE.FLEE) rc.setIndicatorString("TARGET: " + target.toString() + " MODE: " + mode.toString()); else rc.setIndicatorString("TARGET: " + target.toString() + " MODE: FLEE " + "FLEEROUND: " + stopFleeingRound); @@ -119,7 +118,7 @@ else if (target != null) { public MODE determineMode() throws GameActionException { //Priority 0 - Heal if (shouldHeal()) return MODE.HEALING; - + // Priority 1 - Defend. threatenedArchons = findThreatenedArchons(); if (threatenedArchons != null) { @@ -189,6 +188,7 @@ public void moveToArchon() throws GameActionException{ } } + /** * getInitialExploratoryLocation() gets the location when you extend the vector from your location * to the center to the edge @@ -402,7 +402,7 @@ public void defensiveMove() throws GameActionException{ moveToLocation(closest); } else { - huntTarget(); + if (target != null) huntTarget(); } } diff --git a/src/rebutia_micro_heal/Unit.java b/src/rebutia_heal/Unit.java similarity index 99% rename from src/rebutia_micro_heal/Unit.java rename to src/rebutia_heal/Unit.java index dd6ed11..ac22cad 100644 --- a/src/rebutia_micro_heal/Unit.java +++ b/src/rebutia_heal/Unit.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import battlecode.common.*; import java.util.*; diff --git a/src/rebutia_micro_heal/Watchtower.java b/src/rebutia_heal/Watchtower.java similarity index 99% rename from src/rebutia_micro_heal/Watchtower.java rename to src/rebutia_heal/Watchtower.java index 5df2311..d1579b8 100644 --- a/src/rebutia_micro_heal/Watchtower.java +++ b/src/rebutia_heal/Watchtower.java @@ -1,4 +1,4 @@ -package rebutia_micro_heal; +package rebutia_heal; import java.util.Comparator; import java.util.PriorityQueue; From c5825b2e7e7ff1174d5bf7919b804dbe5370eeab Mon Sep 17 00:00:00 2001 From: 2022tgoel Date: Sun, 23 Jan 2022 20:00:59 -0500 Subject: [PATCH 4/6] heals one at a time --- src/rebutia_heal/Archon.java | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/rebutia_heal/Archon.java b/src/rebutia_heal/Archon.java index 030cf2f..856daed 100644 --- a/src/rebutia_heal/Archon.java +++ b/src/rebutia_heal/Archon.java @@ -381,32 +381,22 @@ public int[] chooseInitialBuildOrder() throws GameActionException { public void attemptHeal() throws GameActionException { RobotInfo[] nearbyBots = rc.senseNearbyRobots(rc.getType().actionRadiusSquared, rc.getTeam()); // if there are any nearby enemy robots, attack the one with the least health + RobotType[] repairOrder = new RobotType[]{RobotType.SOLDIER, RobotType.MINER}; if (nearbyBots.length > 0) { - RobotInfo weakestBot = null; - for (RobotInfo bot : nearbyBots) { - if (bot.type == RobotType.SOLDIER) - if ((weakestBot == null && bot.health < RobotType.SOLDIER.health) || - (weakestBot != null && bot.health < weakestBot.health)) { - weakestBot = bot; - } - } - if (weakestBot != null) { - if (rc.canRepair(weakestBot.location)) { - // rc.setIndicatorString("Succesful Heal!"); - rc.repair(weakestBot.location); - } - } else { + RobotInfo healthiestBot = null; + for (RobotType curType : repairOrder){ for (RobotInfo bot : nearbyBots) { - if (bot.type == RobotType.MINER) - if ((weakestBot == null && bot.health < RobotType.MINER.health) || - (weakestBot != null && bot.health < weakestBot.health)) { - weakestBot = bot; + if (bot.type == curType) + if (bot.health < curType.health && (healthiestBot == null || bot.health > healthiestBot.health )) { + healthiestBot = bot; } } - if (weakestBot != null) { - if (rc.canRepair(weakestBot.location)) { - rc.repair(weakestBot.location); + if (healthiestBot != null) { + if (rc.canRepair(healthiestBot.location)) { + // rc.setIndicatorString("Succesful Heal!"); + rc.repair(healthiestBot.location); } + return; } } } From 5972822e9bc18908676c4be6ede441e274673af8 Mon Sep 17 00:00:00 2001 From: 2022tgoel Date: Sun, 23 Jan 2022 23:46:01 -0500 Subject: [PATCH 5/6] soldier boo-boos are adressed --- src/rebutia_heal/Archon.java | 25 ++++++++++++++++++------- src/rebutia_heal/Soldier.java | 4 ++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/rebutia_heal/Archon.java b/src/rebutia_heal/Archon.java index 856daed..0906d3a 100644 --- a/src/rebutia_heal/Archon.java +++ b/src/rebutia_heal/Archon.java @@ -381,20 +381,31 @@ public int[] chooseInitialBuildOrder() throws GameActionException { public void attemptHeal() throws GameActionException { RobotInfo[] nearbyBots = rc.senseNearbyRobots(rc.getType().actionRadiusSquared, rc.getTeam()); // if there are any nearby enemy robots, attack the one with the least health + //Watch Centaurworld strat + // if there's a bot with less than 20 health, repair the weakest + // otherwise repair the strongest RobotType[] repairOrder = new RobotType[]{RobotType.SOLDIER, RobotType.MINER}; if (nearbyBots.length > 0) { - RobotInfo healthiestBot = null; for (RobotType curType : repairOrder){ + RobotInfo botToHeal = null; + boolean repairingWeakest = false; for (RobotInfo bot : nearbyBots) { - if (bot.type == curType) - if (bot.health < curType.health && (healthiestBot == null || bot.health > healthiestBot.health )) { - healthiestBot = bot; + if (bot.type == curType) { + if (bot.health >= curType.health) continue; + if (bot.health < 20){ + repairingWeakest = true; } + if (botToHeal == null) botToHeal = bot; + else if (repairingWeakest && bot.health < botToHeal.health) { + botToHeal = bot; + } + else if (!repairingWeakest && bot.health > botToHeal.health) botToHeal = bot; + } } - if (healthiestBot != null) { - if (rc.canRepair(healthiestBot.location)) { + if (botToHeal != null) { + if (rc.canRepair(botToHeal.location)) { // rc.setIndicatorString("Succesful Heal!"); - rc.repair(healthiestBot.location); + rc.repair(botToHeal.location); } return; } diff --git a/src/rebutia_heal/Soldier.java b/src/rebutia_heal/Soldier.java index 8d638b9..34e0eee 100644 --- a/src/rebutia_heal/Soldier.java +++ b/src/rebutia_heal/Soldier.java @@ -160,13 +160,13 @@ public boolean shouldHeal() throws GameActionException{ if (closestArchon!=null && rc.getHealth() < rc.getType().health){ return true; } - else if (rc.getHealth() <= 15){ // toggle to is healing + else if (rc.getHealth() <= 20){ // toggle to is healing MapLocation my = rc.getLocation(); closestArchon = null; for (int i = 0; i < rc.getArchonCount(); i++) { MapLocation archonLoc = comms.readArchonLocation(i); System.out.println(archonLoc.toString()); - if (my.distanceSquaredTo(archonLoc) <= 300 ){ + if (my.distanceSquaredTo(archonLoc) <= 200 ){ if (closestArchon == null) closestArchon = archonLoc; else if (my.distanceSquaredTo(archonLoc) < my.distanceSquaredTo(closestArchon)) From 9903b7e8ef9988e521c1225b1acc1e22f32a27b6 Mon Sep 17 00:00:00 2001 From: 2022tgoel Date: Sun, 23 Jan 2022 23:57:08 -0500 Subject: [PATCH 6/6] stop being stupidly conservative about healing --- src/rebutia_heal/Archon.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/rebutia_heal/Archon.java b/src/rebutia_heal/Archon.java index 0906d3a..b4f6a0a 100644 --- a/src/rebutia_heal/Archon.java +++ b/src/rebutia_heal/Archon.java @@ -305,9 +305,10 @@ public double getAvgMined() { public boolean checkForResources(int buildCost) throws GameActionException { // CHANGE TO INCORPORATE GOLD ONCE WE // USE SAGES - if (curLead >= buildCost || round_num < 20) { + if (curLead >= buildCost ) {//|| round_num < 20) { return true; } else { + /* int numTurnsToResources = (int) (((double) buildCost - (double) curLead) / Math.max(getAvgMined(), 2.0)); int numTurnsToAct = rc.getActionCooldownTurns() + (int) ((cooldownMultiplier(rc.getLocation()) * rc.getType().actionCooldown) / 10); @@ -318,6 +319,8 @@ public boolean checkForResources(int buildCost) throws GameActionException { // return false; } else return true; + */ + return false; } }