diff --git a/backend/README.md b/backend/README.md index 2c9d9515..6262cbcd 100644 --- a/backend/README.md +++ b/backend/README.md @@ -86,6 +86,20 @@ Always commit the most recent `requirements.txt`. ## Deployment +#### Steps + +1. Push to master. +2. Go to [Cloud Build Triggers](https://console.cloud.google.com/cloud-build/triggers?project=battlecode18) on Google Cloud. +3. Click "Run trigger" under the `battlecode/battlecode20` trigger. +4. Go to [Cloud Build History](https://console.cloud.google.com/cloud-build/builds?project=battlecode18). You should see a spinning blue icon next to a recently started build, which should reference the most recent commit ID on master on this repo. Wait until the spinning icon turns into a green checkmark (this usually takes 2-3 minutes). +5. Go to the [battlecode20-backend-true](https://console.cloud.google.com/compute/instanceGroups/details/us-east1-b/battlecode20-backend-true?project=battlecode18) instance group in the Compute Engine. Press `Rolling Restart/Replace`. +6. Change operation from `Restart` to `Replace`. Let maximum surge be 1 and **maximum unavailable be 0** (we don't want our server to go down). +7. Wait until all spinning blue icons have turned into green checkmarks (this takes like 10 minutes I think). + +This procedure is currently very long and requires too much manual intervention. We should write a script that does all of this for us (which shouldn't be too hard). + +#### Setup + A database should be created. We currently have continuous builds triggered by pushes to master. Therefore, make sure that everything is actually working before pushing. Also, make sure that any new database migrations are also applied to the production server before deploying. A good way to ensure this is to always test locally with the production database, before committing and pushing to master. @@ -94,4 +108,4 @@ The images are then deployed as an instance group on GCE. To update the instance Pls pls use SHA256 digests in the `Dockerfile`. Otherwise, the image might be rebuilt, from the same commit tag as before, but not working anymore (this happened, and it was not fun). -Ideally, we would like to move to Kubernetes for everything, as that would make everything much easier, but it doesn't currently support having a load balancer that also points to storage buckets. This is a deal-breaker, since the frontend is static. \ No newline at end of file +Ideally, we would like to move to Kubernetes for everything, as that would make everything much easier, but it doesn't currently support having a load balancer that also points to storage buckets. This is a deal-breaker, since the frontend is static. diff --git a/backend/api/views.py b/backend/api/views.py index fe85d8f7..fad26c93 100644 --- a/backend/api/views.py +++ b/backend/api/views.py @@ -42,39 +42,48 @@ def callback(api_future): raise return callback -def pub(project_id, topic_name, data=""): +def pub(project_id, topic_name, data="", num_retries=5): """Publishes a message to a Pub/Sub topic.""" - # Initialize a Publisher client. - # credentials must be loaded from a file, so we temporarily create ibe - with open('gcloud-key.json', 'w') as outfile: - outfile.write(settings.GOOGLE_APPLICATION_CREDENTIALS) - outfile.close() - credentials = service_account.Credentials. from_service_account_file('gcloud-key.json') - client = pubsub_v1.PublisherClient(credentials=credentials) - os.remove('gcloud-key.json') # important!!! - - # Create a fully qualified identifier in the form of - # `projects/{project_id}/topics/{topic_name}` - topic_path = client.topic_path(project_id, topic_name) - - # Data sent to Cloud Pub/Sub must be a bytestring. - #data = b"examplefuncs" - if data == "": - data = b"sample pub/sub message" - - # Keep track of the number of published messages. - ref = dict({"num_messages": 0}) - - # When you publish a message, the client returns a future. - api_future = client.publish(topic_path, data=data) - api_future.add_done_callback(get_callback(api_future, data, ref)) - - # Keep the main thread from exiting while the message future - # gets resolved in the background. - while api_future.running(): - time.sleep(0.5) - # print("Published {} message(s).".format(ref["num_messages"])) + # Repeat while this fails, because the data is already in the + # database. The pub/sub message needs to be enqueued to ensure the + # request is complete. + for i in range(num_retries): + try: + # Initialize a Publisher client. + # credentials must be loaded from a file, so we temporarily create ibe + with open('gcloud-key.json', 'w') as outfile: + outfile.write(settings.GOOGLE_APPLICATION_CREDENTIALS) + outfile.close() + credentials = service_account.Credentials. from_service_account_file('gcloud-key.json') + client = pubsub_v1.PublisherClient(credentials=credentials) + os.remove('gcloud-key.json') # important!!! + + # Create a fully qualified identifier in the form of + # `projects/{project_id}/topics/{topic_name}` + topic_path = client.topic_path(project_id, topic_name) + + # Data sent to Cloud Pub/Sub must be a bytestring. + #data = b"examplefuncs" + if data == "": + data = b"sample pub/sub message" + + # Keep track of the number of published messages. + ref = dict({"num_messages": 0}) + + # When you publish a message, the client returns a future. + api_future = client.publish(topic_path, data=data) + api_future.add_done_callback(get_callback(api_future, data, ref)) + + # Keep the main thread from exiting while the message future + # gets resolved in the background. + while api_future.running(): + time.sleep(0.5) + # print("Published {} message(s).".format(ref["num_messages"])) + except: + pass + else: + break def scrimmage_pub_sub_call(red_submission_id, blue_submission_id, red_team_name, blue_team_name, scrimmage_id, scrimmage_replay, map_ids=None): diff --git a/backend/settings.py b/backend/settings.py index 746c0a4a..dabe7663 100644 --- a/backend/settings.py +++ b/backend/settings.py @@ -42,12 +42,14 @@ "WaterBot", "CentralSoup", "ChristmasInJuly", + "CosmicBackgroundRadiation", "ClearlyTwelveHorsesInASalad", "CowFarm", "DidAMonkeyMakeThis", "GSF", "Hills", "InADitch", + "Infinity", "Islands", "IsThisProcedural", "OmgThisIsProcedural", diff --git a/client/visualizer/src/config.ts b/client/visualizer/src/config.ts index d9e04ed8..9d3946b9 100644 --- a/client/visualizer/src/config.ts +++ b/client/visualizer/src/config.ts @@ -115,7 +115,7 @@ export enum Mode { export function defaults(supplied?: any): Config { supplied = supplied || {}; return { - gameVersion: supplied.gameVersion || "2020.1.1.2", //TODO: Change this on each release! + gameVersion: supplied.gameVersion || "2020.2.0.0", //TODO: Change this on each release! fullscreen: supplied.fullscreen || false, width: supplied.width || 600, height: supplied.height || 600, diff --git a/client/visualizer/src/constants.ts b/client/visualizer/src/constants.ts index d0183818..c4787c18 100644 --- a/client/visualizer/src/constants.ts +++ b/client/visualizer/src/constants.ts @@ -57,12 +57,14 @@ export const SERVER_MAPS: Map = new Map([ ["WaterBot", MapType.DEFAULT], ["CentralSoup", MapType.DEFAULT], ["ChristmasInJuly", MapType.SPRINT], + ["CosmicBackgroundRadiation", MapType.SPRINT], ["ClearlyTwelveHorsesInASalad", MapType.SPRINT], ["CowFarm", MapType.SPRINT], ["DidAMonkeyMakeThis", MapType.SPRINT], ["GSF", MapType.SPRINT], ["Hills", MapType.SPRINT], ["InADitch", MapType.SPRINT], + ["Infinity", MapType.SPRINT], ["Islands", MapType.SPRINT], ["IsThisProcedural", MapType.SPRINT], ["OmgThisIsProcedural", MapType.SPRINT], diff --git a/engine/src/main/battlecode/common/GameActionExceptionType.java b/engine/src/main/battlecode/common/GameActionExceptionType.java index 53151ed7..617e3449 100644 --- a/engine/src/main/battlecode/common/GameActionExceptionType.java +++ b/engine/src/main/battlecode/common/GameActionExceptionType.java @@ -45,9 +45,9 @@ public enum GameActionExceptionType { */ NO_ROBOT_THERE, /** - * Indicates when a robot tries to send too many messages to the blockchain. + * Indicates when a robot tries to messages of an incorrect size to the blockchain. */ - TOO_LONG_BLOCKCHAIN_TRANSACTION, + INCORRECT_BLOCKCHAIN_TRANSACTION_LENGTH, /** * Indicates when round number is out of range. */ diff --git a/engine/src/main/battlecode/common/GameConstants.java b/engine/src/main/battlecode/common/GameConstants.java index b0cbf1d4..df02ed41 100644 --- a/engine/src/main/battlecode/common/GameConstants.java +++ b/engine/src/main/battlecode/common/GameConstants.java @@ -112,7 +112,7 @@ public static float getWaterLevel(int roundNumber) { // ********************************* /** The maximum number of integers that can be sent in one message. */ - public static final int MAX_BLOCKCHAIN_TRANSACTION_LENGTH = 7; + public static final int BLOCKCHAIN_TRANSACTION_LENGTH = 7; /** The number of transactions that get broadcasted every round. */ public static final int NUMBER_OF_TRANSACTIONS_PER_BLOCK = 7; diff --git a/engine/src/main/battlecode/common/RobotController.java b/engine/src/main/battlecode/common/RobotController.java index 9e12744b..92d08a15 100644 --- a/engine/src/main/battlecode/common/RobotController.java +++ b/engine/src/main/battlecode/common/RobotController.java @@ -34,17 +34,6 @@ public strictfp interface RobotController { */ int getTeamSoup(); - /** - * Returns the number of robots on your team (including your HQ). - * If this number ever reaches zero, the opposing team will automatically - * win by destruction (because your HQ is dead). - * - * @return the number of robots on your team - * - * @battlecode.doc.costlymethod - */ - int getRobotCount(); - /** * Returns the width of the map. * @@ -150,16 +139,15 @@ public strictfp interface RobotController { // *********************************** /** - * Senses whether a MapLocation is on the map. Will throw an exception if - * the location is not within the sensor range. + * Senses whether a MapLocation is on the map. + * This is different from before sprint rebalancing. * * @param loc the location to check * @return true if the location is on the map; false otherwise. - * @throws GameActionException if the location is not within sensor range. * * @battlecode.doc.costlymethod */ - boolean onTheMap(MapLocation loc) throws GameActionException; + boolean onTheMap(MapLocation loc); /** * Senses whether the given location is within the robot's sensor range, and if it is on the map. @@ -270,7 +258,7 @@ public strictfp interface RobotController { * increasing distance from the specified center. * * @param center center of the given search radius - * @param radius return robots this distance away from the given center + * @param radiusSquared return robots this distance squared away from the given center * location. If -1 is passed, all robots within sense radius are returned * @param team filter game objects by the given team. If null is passed, * objects from all teams are returned @@ -278,7 +266,45 @@ public strictfp interface RobotController { * * @battlecode.doc.costlymethod */ - RobotInfo[] senseNearbyRobots(MapLocation center, int radius, Team team); + RobotInfo[] senseNearbyRobots(MapLocation center, int radiusSquared, Team team); + + /** + * Returns all map locations containing soup within sense radius. The + * locations are returned in no particular order. + * + * @return array of map locations that can be sensed containing soup + * + * @battlecode.doc.costlymethod + */ + MapLocation[] senseNearbySoup(); + + /** + * Returns all map locations that can be sensed containing soup within + * specified radius. The locations are returned in no particular order. + * + * @param radiusSquared return soup locations this distance away from the center of + * this robot. If -1 is passed, all locations with soup within sense radius are returned + * @return array of map locations that can be sensed within the + * specified radius containing soup + * + * @battlecode.doc.costlymethod + */ + MapLocation[] senseNearbySoup(int radiusSquared); + + /** + * Returns all map locations that can be sensed containing soup within + * specified radius of specified location. The locations are returned in no + * particular order. + * + * @param center center of the given search radius + * @param radiusSquared return soup locations this distance away from the center of + * this robot. If -1 is passed, all locations with soup within sense radius are returned + * @return array of map locations that can be sensed within the + * specified radius containing soup + * + * @battlecode.doc.costlymethod + */ + MapLocation[] senseNearbySoup(MapLocation center, int radiusSquared); /** * Returns the crude soup count at a given location, if the location is @@ -637,6 +663,13 @@ public strictfp interface RobotController { // ****** OTHER ACTION METHODS ******* // *********************************** + /** + * Causes the robot to die. + * + * @battlecode.doc.costlymethod + */ + void disintegrate() throws GameActionException; + /** * Causes your team to lose the game. It's like typing "gg." * @@ -649,11 +682,11 @@ public strictfp interface RobotController { // *********************************** /** - * Tests if the robot can submit a transaction + * Checks that the robot can submit a transaction * to the blockchain at the indicated cost. Tests if the team has enough soup, - * that the provided cost is positive, and that the message doesn't exceed the limit. + * that the provided cost is positive, and that the message contains exactly 7 integers. * - * @param message the list of ints to send (at most of GameConstants.MAX_BLOCKCHAIN_TRANSACTION_LENGTH many). + * @param message the list of ints to send (exactly GameConstants.BLOCKCHAIN_TRANSACTION_LENGTH of them). * @param cost the price that the unit is willing to pay for the message, in soup * * @return whether the transaction can be submitted or not @@ -664,12 +697,13 @@ public strictfp interface RobotController { /** * Submits a transaction to the transaction pool at the indicated cost. + * The transaction messages needs to be exactly 7 integers. * * @param message the list of ints to send. * @param cost the price that the unit is willing to pay for the message * * @throws GameActionException if the team does not have enough soup to cover the cost, - * if the message exceeds the allowed limit, or if the cost is negative + * if the message is not of the right size, or if the cost is negative * * @battlecode.doc.costlymethod */ @@ -678,7 +712,8 @@ public strictfp interface RobotController { /** * Get the block of messages that was approved at a given round. - * The block will contain a list of transactions. + * The block will contain a list of transactions, and each transaction + * message will have exactly 7 integers. * * @param roundNumber the round index. * @return an array of Transactions that were accepted into the blockchain diff --git a/engine/src/main/battlecode/common/RobotInfo.java b/engine/src/main/battlecode/common/RobotInfo.java index dd8d1555..daadaa33 100644 --- a/engine/src/main/battlecode/common/RobotInfo.java +++ b/engine/src/main/battlecode/common/RobotInfo.java @@ -22,27 +22,64 @@ public class RobotInfo { */ public final RobotType type; + /** - * The current location of the robot. + * The dirt carried by a landscaper, or the dirt on top of a building. 0 if + * the robot is neither a landscaper or a building. */ - public final MapLocation location; + public final int dirtCarrying; - public int getID() { - return this.ID; - } + /** + * A boolean indicating whether the robot is currently holding a unit. Always false + * for robots that are not delivery drones. + */ + public final boolean currentlyHoldingUnit; - public MapLocation getLocation() { - return this.location; - } + /** + * The ID of the unit that the robot is currently holding. -1 if currentlyHoldingUnit + * is false. + */ + public final int heldUnitID; + + /** + * The amount of soup carried by the robot. Works for miners and refineries (HQs). + */ + public final int soupCarrying; - public RobotInfo(int ID, Team team, RobotType type, MapLocation location) { + /** + * The cooldown of the robot. + */ + public final float cooldownTurns; + + /** + * The current location of the robot. + */ + public final MapLocation location; + + public RobotInfo(int ID, Team team, RobotType type, int dirtCarrying, + boolean currentlyHoldingUnit, int heldUnitID, int soupCarrying, + float cooldownTurns, MapLocation location) { super(); this.ID = ID; this.team = team; this.type = type; + this.dirtCarrying = dirtCarrying; + this.currentlyHoldingUnit = currentlyHoldingUnit; + this.heldUnitID = heldUnitID; + this.soupCarrying = soupCarrying; + this.cooldownTurns = cooldownTurns; this.location = location; } + /** + * Returns the ID of this robot. + * + * @return + */ + public int getID() { + return this.ID; + } + /** * Returns the team that this robot is on. * @@ -61,6 +98,62 @@ public RobotType getType() { return type; } + /** + * Returns the dirt carried by the robot. + * + * @return the dirt carried by the robot. + */ + public int getDirtCarrying() { + return dirtCarrying; + } + + /** + * Returns whether the robot is currently holding a unit. + * + * @return whether the robot is currently holding a unit. + */ + public boolean isCurrentlyHoldingUnit() { + return currentlyHoldingUnit; + } + + /** + * Returns the ID of the unit that the robot is holding, if it + * is holding one. Returns -1 if isCurrentlyHoldingUnit() is false. + * + * @return the ID of the unit held. + */ + public int getHeldUnitID() { + return heldUnitID; + } + + /** + * Returns the soup carried by the robot (miner or refinery (or HQ), 0 + * for other robots). + * + * @return the soup amount. + */ + public int getSoupCarrying() { + return soupCarrying; + } + + /** + * Returns the cooldown turns of the robot. + * + * @return the cooldown. + */ + public float getCooldownTurns() { + return cooldownTurns; + } + + /** + * Returns the location of this robot. + * + * @return the location. + */ + public MapLocation getLocation() { + return this.location; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -71,6 +164,11 @@ public boolean equals(Object o) { if (ID != robotInfo.ID) return false; if (team != robotInfo.team) return false; if (type != robotInfo.type) return false; + if (dirtCarrying != robotInfo.dirtCarrying) return false; + if (currentlyHoldingUnit != robotInfo.currentlyHoldingUnit) return false; + if (heldUnitID != robotInfo.heldUnitID) return false; + if (soupCarrying != robotInfo.soupCarrying) return false; + if (Math.abs(cooldownTurns - robotInfo.cooldownTurns) > 0.000001) return false; return location.equals(robotInfo.location); } @@ -82,6 +180,11 @@ public int hashCode() { result = ID; result = 31 * result + team.hashCode(); result = 31 * result + type.hashCode(); + result = 31 * result + dirtCarrying; + result = 31 * result + (currentlyHoldingUnit ? 1 : 0); + result = 31 * result + heldUnitID; + result = 31 * result + soupCarrying; + result = 31 * result + (int) Math.ceil(cooldownTurns); result = 31 * result + location.hashCode(); return result; } @@ -92,6 +195,11 @@ public String toString() { "ID=" + ID + ", team=" + team + ", type=" + type + + ", dirtCarrying=" + dirtCarrying + + ", currentlyHoldingUnit=" + currentlyHoldingUnit + + ", heldUnitID=" + heldUnitID + + ", soupCarrying=" + soupCarrying + + ", cooldownTurns=" + cooldownTurns + ", location=" + location + '}'; } diff --git a/engine/src/main/battlecode/common/RobotType.java b/engine/src/main/battlecode/common/RobotType.java index 4c6de5aa..f66c139c 100644 --- a/engine/src/main/battlecode/common/RobotType.java +++ b/engine/src/main/battlecode/common/RobotType.java @@ -29,7 +29,7 @@ public enum RobotType { * Vaporators condense soup from the air, reducing pollution. * @battlecode.doc.robottype */ - VAPORATOR (MINER, 1000, 15, 0, 1, 24, 35, 0, 0.67f, -1, 7, 5000), + VAPORATOR (MINER, 500, 15, 0, 1, 24, 35, 0, 0.80f, -1, 2, 5000), // SS C DL SL AC SR PR PA PM GP MS BL /** * Design schools create landscapers. diff --git a/engine/src/main/battlecode/instrumenter/bytecode/resources/MethodCosts.txt b/engine/src/main/battlecode/instrumenter/bytecode/resources/MethodCosts.txt index df846509..4bca704d 100644 --- a/engine/src/main/battlecode/instrumenter/bytecode/resources/MethodCosts.txt +++ b/engine/src/main/battlecode/instrumenter/bytecode/resources/MethodCosts.txt @@ -49,7 +49,6 @@ battlecode/common/RobotController/getID 1 true battlecode/common/RobotController/getLocation 1 true battlecode/common/RobotController/getMapWidth 1 true battlecode/common/RobotController/getMapHeight 1 true -battlecode/common/RobotController/getRobotCount 20 true battlecode/common/RobotController/getRoundNum 1 true battlecode/common/RobotController/getTeam 1 true battlecode/common/RobotController/getTeamSoup 1 true @@ -66,6 +65,7 @@ battlecode/common/RobotController/resign 0 true battlecode/common/RobotController/senseElevation 1 true battlecode/common/RobotController/senseFlooding 1 true battlecode/common/RobotController/senseNearbyRobots 100 true +battlecode/common/RobotController/senseNearbySoup 100 true battlecode/common/RobotController/sensePollution 1 true battlecode/common/RobotController/senseRobot 25 true battlecode/common/RobotController/senseRobotAtLocation 20 true diff --git a/engine/src/main/battlecode/world/BuildMaps.java b/engine/src/main/battlecode/world/BuildMaps.java index 1bcd061a..8745fb7c 100644 --- a/engine/src/main/battlecode/world/BuildMaps.java +++ b/engine/src/main/battlecode/world/BuildMaps.java @@ -23,6 +23,7 @@ public static void main(String[] args) { CentralSoup.main(args); ChristmasInJuly.main(args); ClearlyTwelveHorsesInASalad.main(args); + CosmicBackgroundRadiation.main(args); CowFarm.main(args); DidAMonkeyMakeThis.main(args); FourLakeLand.main(args); diff --git a/engine/src/main/battlecode/world/GameMapIO.java b/engine/src/main/battlecode/world/GameMapIO.java index 9f29c1e6..7f83633a 100644 --- a/engine/src/main/battlecode/world/GameMapIO.java +++ b/engine/src/main/battlecode/world/GameMapIO.java @@ -338,7 +338,10 @@ private static void initInitialBodiesFromSchemaBodyTable(SpawnedBodyTable bodyTa int bodyY = locs.ys(i); Team bodyTeam = TeamMapping.team(bodyTable.teamIDs(i)); if (bodyType != null) - initialBodies.add(new RobotInfo(bodyID, bodyTeam, bodyType, new MapLocation(bodyX, bodyY))); + initialBodies.add(new RobotInfo(bodyID, bodyTeam, bodyType, 0, + false, -1, 0, GameConstants.INITIAL_COOLDOWN_TURNS, + new MapLocation(bodyX, bodyY))); + // ^^ note that only id, team, type and loc will be used when creating real robots } } } diff --git a/engine/src/main/battlecode/world/InternalRobot.java b/engine/src/main/battlecode/world/InternalRobot.java index 22c5b9f1..02850be7 100644 --- a/engine/src/main/battlecode/world/InternalRobot.java +++ b/engine/src/main/battlecode/world/InternalRobot.java @@ -30,11 +30,6 @@ public strictfp class InternalRobot { private boolean blocked; // when picked up by a delivery drone - /** - * Used to avoid recreating the same RobotInfo object over and over. - */ - private RobotInfo cachedRobotInfo; - /** * Create a new internal representation of a robot * @@ -134,15 +129,8 @@ public boolean isBlocked() { } public RobotInfo getRobotInfo() { - if (this.cachedRobotInfo != null - && this.cachedRobotInfo.ID == ID - && this.cachedRobotInfo.team == team - && this.cachedRobotInfo.type == type - && this.cachedRobotInfo.location.equals(location)) { - return this.cachedRobotInfo; - } - return this.cachedRobotInfo = new RobotInfo( - ID, team, type, location); + return new RobotInfo(ID, team, type, dirtCarrying, currentlyHoldingUnit, idOfUnitCurrentlyHeld, + soupCarrying, cooldownTurns, location); } public void pickUpUnit(int id) { diff --git a/engine/src/main/battlecode/world/MapBuilder.java b/engine/src/main/battlecode/world/MapBuilder.java index 6c7f689e..7cdcc8a9 100644 --- a/engine/src/main/battlecode/world/MapBuilder.java +++ b/engine/src/main/battlecode/world/MapBuilder.java @@ -68,12 +68,9 @@ public void addRobot(int id, Team team, RobotType type, MapLocation loc){ throw new RuntimeException("CANNOT ADD ROBOT TO SAME LOCATION AS OTHER ROBOT"); } } - bodies.add(new RobotInfo( - id, - team, - type, - loc - )); + bodies.add(new RobotInfo(id, team, type, 0, false, -1, + 0, GameConstants.INITIAL_COOLDOWN_TURNS, loc)); + // ^^ note that only id, team, type and loc will be saved in the actual map file } public void addHQ(int x, int y, Team team) { diff --git a/engine/src/main/battlecode/world/RobotControllerImpl.java b/engine/src/main/battlecode/world/RobotControllerImpl.java index 2209b844..17fa9dbb 100644 --- a/engine/src/main/battlecode/world/RobotControllerImpl.java +++ b/engine/src/main/battlecode/world/RobotControllerImpl.java @@ -88,12 +88,7 @@ public int getRoundNum() { public int getTeamSoup() { return gameWorld.getTeamInfo().getSoup(getTeam()); } - - @Override - public int getRobotCount() { - return gameWorld.getObjectInfo().getRobotCount(getTeam()); - } - + @Override public int getMapWidth() { return gameWorld.getGameMap().getWidth(); @@ -159,9 +154,8 @@ private InternalRobot getRobotByID(int id) { // *********************************** @Override - public boolean onTheMap(MapLocation loc) throws GameActionException { + public boolean onTheMap(MapLocation loc) { assertNotNull(loc); - assertCanSenseLocation(loc); return gameWorld.getGameMap().onTheMap(loc); } @@ -233,9 +227,8 @@ public RobotInfo[] senseNearbyRobots(int radiusSquared, Team team) { @Override public RobotInfo[] senseNearbyRobots(MapLocation center, int radiusSquared, Team team) { assertNotNull(center); - int sensorRadiusSquaredUpperBound = (int) Math.ceil(this.robot.getCurrentSensorRadiusSquared()); - InternalRobot[] allSensedRobots = gameWorld.getAllRobotsWithinRadiusSquared(center, - radiusSquared == -1 ? sensorRadiusSquaredUpperBound : Math.min(radiusSquared, sensorRadiusSquaredUpperBound)); + if (radiusSquared == -1) radiusSquared = (int) Math.ceil(this.robot.getCurrentSensorRadiusSquared()); + InternalRobot[] allSensedRobots = gameWorld.getAllRobotsWithinRadiusSquared(center, radiusSquared); List validSensedRobots = new ArrayList<>(); for(InternalRobot sensedRobot : allSensedRobots){ // check if this robot @@ -252,6 +245,34 @@ public RobotInfo[] senseNearbyRobots(MapLocation center, int radiusSquared, Team return validSensedRobots.toArray(new RobotInfo[validSensedRobots.size()]); } + @Override + public MapLocation[] senseNearbySoup() { + return senseNearbySoup(-1); + } + + @Override + public MapLocation[] senseNearbySoup(int radiusSquared) { + return senseNearbySoup(getLocation(), radiusSquared); + } + + @Override + public MapLocation[] senseNearbySoup(MapLocation center, int radiusSquared) { + assertNotNull(center); + if (radiusSquared == -1) radiusSquared = (int) Math.ceil(this.robot.getCurrentSensorRadiusSquared()); + MapLocation[] allSensedLocs = gameWorld.getAllLocationsWithinRadiusSquared(center, radiusSquared); + List soupLocations = new ArrayList(); + for(MapLocation loc : allSensedLocs){ + // check if can sense + if (!canSenseLocation(loc)) + continue; + // check if there is soup + if (gameWorld.getSoup(loc) <= 0) + continue; + soupLocations.add(loc); + } + return soupLocations.toArray(new MapLocation[soupLocations.size()]); + } + @Override public int senseSoup(MapLocation loc) throws GameActionException { assertCanSenseLocation(loc); @@ -909,10 +930,11 @@ public void shootUnit(int id) throws GameActionException { // ****** OTHER ACTION METHODS ******* // *********************************** - /** This used to be public, but is not public in 2020 because - * a robot can simply instead walk into water, which is more fun. + /** + * This is public again. Allows a robot to commit suicide. */ - private void disintegrate(){ + @Override + public void disintegrate(){ throw new RobotDeathException(); } @@ -931,9 +953,9 @@ public void resign(){ // *********************************** private void assertCanSubmitTransaction(int[] message, int cost) throws GameActionException { - if (message.length > GameConstants.MAX_BLOCKCHAIN_TRANSACTION_LENGTH) - throw new GameActionException(TOO_LONG_BLOCKCHAIN_TRANSACTION, - "Can only send " + Integer.toString(GameConstants.MAX_BLOCKCHAIN_TRANSACTION_LENGTH) + + if (message.length != GameConstants.BLOCKCHAIN_TRANSACTION_LENGTH) + throw new GameActionException(INCORRECT_BLOCKCHAIN_TRANSACTION_LENGTH, + "Must send exactly " + Integer.toString(GameConstants.BLOCKCHAIN_TRANSACTION_LENGTH) + " integers in one message, not " + Integer.toString(message.length) + "."); int teamSoup = gameWorld.getTeamInfo().getSoup(getTeam()); if (gameWorld.getTeamInfo().getSoup(getTeam()) < cost) diff --git a/engine/src/main/battlecode/world/TestMapBuilder.java b/engine/src/main/battlecode/world/TestMapBuilder.java index 14a9b3f8..fde845ca 100644 --- a/engine/src/main/battlecode/world/TestMapBuilder.java +++ b/engine/src/main/battlecode/world/TestMapBuilder.java @@ -37,12 +37,9 @@ public TestMapBuilder(String name, MapLocation origin, int width, int height, in } public TestMapBuilder addRobot(int id, Team team, RobotType type, MapLocation loc){ - bodies.add(new RobotInfo( - id, - team, - type, - loc - )); + bodies.add(new RobotInfo(id, team, type, 0, false, -1, + 0, GameConstants.INITIAL_COOLDOWN_TURNS, loc)); + // ^^ note that only id, team, type and loc will be saved in the actual map file return this; } diff --git a/engine/src/main/battlecode/world/maps/InADitch.java b/engine/src/main/battlecode/world/maps/InADitch.java index e970140a..1fba20a8 100644 --- a/engine/src/main/battlecode/world/maps/InADitch.java +++ b/engine/src/main/battlecode/world/maps/InADitch.java @@ -51,7 +51,7 @@ public static int loc2index(int x, int y) { public static void makeSimple() throws IOException { - String ds = "50\t37\th\t111\t630\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n" + + String ds = "50\t37\th\t150\t630\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n" + "11\t11\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\n" + "11\t11\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\n" + "11\t11\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\t5\n" + diff --git a/engine/src/main/battlecode/world/maps/WateredDown.java b/engine/src/main/battlecode/world/maps/WateredDown.java index 96b1b091..4e471d8c 100644 --- a/engine/src/main/battlecode/world/maps/WateredDown.java +++ b/engine/src/main/battlecode/world/maps/WateredDown.java @@ -51,7 +51,7 @@ public static int loc2index(int x, int y) { public static void makeSimple() throws IOException { - String ds = "32 32 h 100 300 \n"+ + String ds = "32 32 h 200 300 \n"+ "2 2 2 4 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 4\n"+ "2 2 3 5 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2\n"+ "2 2 3 c4 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 ws-4 ws-4 ws-4 2 2 c3 2 2 2\n"+ diff --git a/engine/src/main/battlecode/world/resources/InADitch.map20 b/engine/src/main/battlecode/world/resources/InADitch.map20 index e384c723..631ce776 100644 Binary files a/engine/src/main/battlecode/world/resources/InADitch.map20 and b/engine/src/main/battlecode/world/resources/InADitch.map20 differ diff --git a/engine/src/main/battlecode/world/resources/WateredDown.map20 b/engine/src/main/battlecode/world/resources/WateredDown.map20 index f167c1ce..d5ae43b9 100644 Binary files a/engine/src/main/battlecode/world/resources/WateredDown.map20 and b/engine/src/main/battlecode/world/resources/WateredDown.map20 differ diff --git a/engine/src/test/battlecode/world/TestMapBuilder.java b/engine/src/test/battlecode/world/TestMapBuilder.java index c59d7cd8..50035936 100644 --- a/engine/src/test/battlecode/world/TestMapBuilder.java +++ b/engine/src/test/battlecode/world/TestMapBuilder.java @@ -37,13 +37,9 @@ public TestMapBuilder(String name, MapLocation origin, int width, int height, in } public TestMapBuilder addRobot(int id, Team team, RobotType type, MapLocation loc){ - bodies.add(new RobotInfo( - id, - team, - type, - loc - )); - + bodies.add(new RobotInfo(id, team, type, 0, false, -1, + 0, GameConstants.INITIAL_COOLDOWN_TURNS, loc)); + // ^^ note that only id, team, type and loc will be saved in the actual map file return this; } diff --git a/frontend/public/bc20/bundle.js b/frontend/public/bc20/bundle.js index 270372bd..092aa877 100644 --- a/frontend/public/bc20/bundle.js +++ b/frontend/public/bc20/bundle.js @@ -1,11 +1,11 @@ -!function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(r,i,function(e){return t[e]}.bind(null,i));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/bc20/",n(n.s=77)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r,i=n(11),o=n(39);e.MINER=i.schema.BodyType.MINER,e.LANDSCAPER=i.schema.BodyType.LANDSCAPER,e.DRONE=i.schema.BodyType.DELIVERY_DRONE,e.NET_GUN=i.schema.BodyType.NET_GUN,e.COW=i.schema.BodyType.COW,e.REFINERY=i.schema.BodyType.REFINERY,e.VAPORATOR=i.schema.BodyType.VAPORATOR,e.HQ=i.schema.BodyType.HQ,e.DESIGN_SCHOOL=i.schema.BodyType.DESIGN_SCHOOL,e.FULFILLMENT_CENTER=i.schema.BodyType.FULFILLMENT_CENTER,e.INDICATOR_DOT_SIZE=.3,e.INDICATOR_LINE_WIDTH=.3,e.SIGHT_RADIUS_LINE_WIDTH=.15,e.HIGH_SPEED_THRESH=16-1e-5,e.MED_SPEED_THRESH=4-1e-5,e.DELTA=1e-4,e.MIN_DIMENSION=30,e.MAX_DIMENSION=100,e.NUMBER_OF_TEAMS=2,e.MAX_ROUND_NUM=3e3,function(t){t[t.DEFAULT=0]="DEFAULT",t[t.SPRINT=1]="SPRINT",t[t.SEEDING=2]="SEEDING",t[t.QUALIFYING=3]="QUALIFYING",t[t.FINAL=4]="FINAL",t[t.CUSTOM=5]="CUSTOM"}(r=e.MapType||(e.MapType={})),e.SERVER_MAPS=new Map([["FourLakeLand",r.DEFAULT],["CentralLake",r.DEFAULT],["ALandDivided",r.DEFAULT],["SoupOnTheSide",r.DEFAULT],["TwoForOneAndTwoForAll",r.DEFAULT],["WaterBot",r.DEFAULT],["CentralSoup",r.DEFAULT]]),e.bodyTypeToString=function(t){switch(t){case e.MINER:return"miner";case e.LANDSCAPER:return"landscaper";case e.DRONE:return"drone";case e.NET_GUN:return"netGun";case e.COW:return"cow";case e.REFINERY:return"refinery";case e.VAPORATOR:return"vaporator";case e.HQ:return"HQ";case e.DESIGN_SCHOOL:return"designSchool";case e.FULFILLMENT_CENTER:return"fulfillmentCenter";default:throw new Error("invalid body type")}},e.symmetryToString=function(t){switch(t){case o.Symmetry.ROTATIONAL:return"Rotational";case o.Symmetry.HORIZONTAL:return"Horizontal";case o.Symmetry.VERTICAL:return"Vertical";default:throw new Error("invalid symmetry")}},e.radiusFromBodyType=function(t){switch(t){case e.MINER:case e.LANDSCAPER:case e.DRONE:case e.NET_GUN:case e.COW:case e.REFINERY:case e.VAPORATOR:case e.HQ:case e.DESIGN_SCHOOL:case e.FULFILLMENT_CENTER:return 1;default:throw new Error("invalid body type")}}},function(t,e,n){(function(e){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof e&&e)||Function("return this")()}).call(this,n(23))},function(t,e,n){var r=n(1),i=n(48),o=n(3),s=n(29),a=n(55),c=n(93),u=i("wks"),h=r.Symbol,d=c?h:s;t.exports=function(t){return o(u,t)||(a&&o(h,t)?u[t]=h[t]:u[t]=d("Symbol."+t)),u[t]}},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(8),i=n(44),o=n(10),s=n(43),a=Object.defineProperty;e.f=r?a:function(t,e,n){if(o(t),e=s(e,!0),o(n),i)try{return a(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},function(t,e,n){"use strict";var r="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;function i(t,e){return Object.prototype.hasOwnProperty.call(t,e)}e.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var n=e.shift();if(n){if("object"!=typeof n)throw new TypeError(n+"must be non-object");for(var r in n)i(n,r)&&(t[r]=n[r])}}return t},e.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var o={arraySet:function(t,e,n,r,i){if(e.subarray&&t.subarray)t.set(e.subarray(n,n+r),i);else for(var o=0;ot&&(this.x*=e),Math.abs(this.y)>t&&(this.y*=e),this},n.prototype.randomize=function(t,e){return this.randomizeX(t,e),this.randomizeY(t,e),this},n.prototype.randomizeX=function(t,e){var n=Math.min(t.x,e.x),r=Math.max(t.x,e.x);return this.x=i(n,r),this},n.prototype.randomizeY=function(t,e){var n=Math.min(t.y,e.y),r=Math.max(t.y,e.y);return this.y=i(n,r),this},n.prototype.randomizeAny=function(t,e){return Math.round(Math.random())?this.randomizeX(t,e):this.randomizeY(t,e),this},n.prototype.unfloat=function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},n.prototype.toFixed=function(t){return void 0===t&&(t=8),this.x=this.x.toFixed(t),this.y=this.y.toFixed(t),this},n.prototype.mixX=function(t,e){return void 0===e&&(e=.5),this.x=(1-e)*this.x+e*t.x,this},n.prototype.mixY=function(t,e){return void 0===e&&(e=.5),this.y=(1-e)*this.y+e*t.y,this},n.prototype.mix=function(t,e){return this.mixX(t,e),this.mixY(t,e),this},n.prototype.clone=function(){return new n(this.x,this.y)},n.prototype.copyX=function(t){return this.x=t.x,this},n.prototype.copyY=function(t){return this.y=t.y,this},n.prototype.copy=function(t){return this.copyX(t),this.copyY(t),this},n.prototype.zero=function(){return this.x=this.y=0,this},n.prototype.dot=function(t){return this.x*t.x+this.y*t.y},n.prototype.cross=function(t){return this.x*t.y-this.y*t.x},n.prototype.projectOnto=function(t){var e=(this.x*t.x+this.y*t.y)/(t.x*t.x+t.y*t.y);return this.x=e*t.x,this.y=e*t.y,this},n.prototype.horizontalAngle=function(){return Math.atan2(this.y,this.x)},n.prototype.horizontalAngleDeg=function(){return o(this.horizontalAngle())},n.prototype.verticalAngle=function(){return Math.atan2(this.x,this.y)},n.prototype.verticalAngleDeg=function(){return o(this.verticalAngle())},n.prototype.angle=n.prototype.horizontalAngle,n.prototype.angleDeg=n.prototype.horizontalAngleDeg,n.prototype.direction=n.prototype.horizontalAngle,n.prototype.rotate=function(t){var e=this.x*Math.cos(t)-this.y*Math.sin(t),n=this.x*Math.sin(t)+this.y*Math.cos(t);return this.x=e,this.y=n,this},n.prototype.rotateDeg=function(t){return t=s(t),this.rotate(t)},n.prototype.rotateTo=function(t){return this.rotate(t-this.angle())},n.prototype.rotateToDeg=function(t){return t=s(t),this.rotateTo(t)},n.prototype.rotateBy=function(t){var e=this.angle()+t;return this.rotate(e)},n.prototype.rotateByDeg=function(t){return t=s(t),this.rotateBy(t)},n.prototype.distanceX=function(t){return this.x-t.x},n.prototype.absDistanceX=function(t){return Math.abs(this.distanceX(t))},n.prototype.distanceY=function(t){return this.y-t.y},n.prototype.absDistanceY=function(t){return Math.abs(this.distanceY(t))},n.prototype.distance=function(t){return Math.sqrt(this.distanceSq(t))},n.prototype.distanceSq=function(t){var e=this.distanceX(t),n=this.distanceY(t);return e*e+n*n},n.prototype.length=function(){return Math.sqrt(this.lengthSq())},n.prototype.lengthSq=function(){return this.x*this.x+this.y*this.y},n.prototype.magnitude=n.prototype.length,n.prototype.isZero=function(){return 0===this.x&&0===this.y},n.prototype.isEqualTo=function(t){return this.x===t.x&&this.y===t.y},n.prototype.toString=function(){return"x:"+this.x+", y:"+this.y},n.prototype.toArray=function(){return[this.x,this.y]},n.prototype.toObject=function(){return{x:this.x,y:this.y}};var r=180/Math.PI;function i(t,e){return Math.floor(Math.random()*(e-t+1)+t)}function o(t){return t*r}function s(t){return t/r}},function(t,e,n){var r=n(83),i=n(25);t.exports=function(t){return r(i(t))}},function(t,e,n){var r,i,o,s=n(84),a=n(1),c=n(5),u=n(9),h=n(3),d=n(27),l=n(17),f=a.WeakMap;if(s){var p=new f,b=p.get,m=p.has,y=p.set;r=function(t,e){return y.call(p,t,e),e},i=function(t){return b.call(p,t)||{}},o=function(t){return m.call(p,t)}}else{var g=d("state");l[g]=!0,r=function(t,e){return u(t,g,e),e},i=function(t){return h(t,g)?t[g]:{}},o=function(t){return h(t,g)}}t.exports={set:r,get:i,has:o,enforce:function(t){return o(t)?i(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!c(e)||(n=i(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e){t.exports={}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(117).battlecode.schema;e.schema=r;var i=n(118);e.flatbuffers=i.flatbuffers},function(t,e,n){"use strict";var r;Object.defineProperty(e,"__esModule",{value:!0}),function(t){t[t.GAME=0]="GAME",t[t.HELP=1]="HELP",t[t.LOGS=2]="LOGS",t[t.RUNNER=3]="RUNNER",t[t.QUEUE=4]="QUEUE",t[t.MAPEDITOR=5]="MAPEDITOR"}(r=e.Mode||(e.Mode={})),e.defaults=function(t){return{gameVersion:(t=t||{}).gameVersion||"2020.1.1.1",fullscreen:t.fullscreen||!1,width:t.width||600,height:t.height||600,defaultTPS:t.defaultTPS||20,websocketURL:t.websocketURL||null,matchFileURL:t.matchFileURL||null,pollEvery:t.pollEvery||500,interpolate:t.interpolate||!1,circleBots:t.circleBots||!1,indicators:t.indicators||!0,mode:t.mode||r.QUEUE,splash:t.splash||null==t.matchFileURL||!0,sightRadius:t.sightRadius||!1,showGrid:t.showGrid||!1,viewDirt:t.viewDirt||!0,viewWater:t.viewDirt||!0,viewPoll:t.viewDirt||!0,shorterLogHeader:t.shorterLogHeader||!1}}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=function(){return null}.apply(e,[]),i=function(){return null}.apply(e,[]),o=function(){return null}.apply(e,[]),s=function(){return null}.apply(e,[]),a=function(){return null}.apply(e,[]),c=function(){return null}.apply(e,[]);e.electron=r,e.os=i,e.fs=o,e.path=s,e.child_process=a,e.http=c,e.default={electron:r,os:i,fs:o,path:s,child_process:a,http:c}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const r=n(22),i=n(18),o=n(119),s=n(120);class a{constructor(t){this.meta=t,this.diedBodies=new r.default({id:new Int32Array(0),x:new Int32Array(0),y:new Int32Array(0)},"id"),this.bodies=new r.default({id:new Int32Array(0),team:new Int8Array(0),type:new Int8Array(0),x:new Int32Array(0),y:new Int32Array(0),onDirt:new Int32Array(0),carryDirt:new Int32Array(0),cargo:new Int32Array(0),isCarried:new Uint8Array(0),bytecodesUsed:new Int32Array(0)},"id"),this.teamStats=new Map;for(let t in this.meta.teams){var e=this.meta.teams[t].teamID;this.teamStats.set(e,{soup:0,robots:[0,0,0,0,0,0,0,0,0,0,0]})}this.mapStats={name:"????",minCorner:new o(0,0),maxCorner:new o(0,0),bodies:new i.schema.SpawnedBodyTable,randomSeed:0,flooded:new Int8Array(0),dirt:new Int32Array(0),globalPollution:0,localPollutions:new i.schema.LocalPollutionTable,pollution:new Int32Array(0),soup:new Int32Array(0),getIdx:(t,e)=>0,getLoc:t=>new o(0,0)},this.indicatorDots=new r.default({id:new Int32Array(0),x:new Int32Array(0),y:new Int32Array(0),red:new Int32Array(0),green:new Int32Array(0),blue:new Int32Array(0)},"id"),this.indicatorLines=new r.default({id:new Int32Array(0),startX:new Int32Array(0),startY:new Int32Array(0),endX:new Int32Array(0),endY:new Int32Array(0),red:new Int32Array(0),green:new Int32Array(0),blue:new Int32Array(0)},"id"),this.turn=0,this.minCorner=new o(0,0),this.maxCorner=new o(0,0),this.mapName="????",this._bodiesSlot=new i.schema.SpawnedBodyTable,this._vecTableSlot1=new i.schema.VecTable,this._vecTableSlot2=new i.schema.VecTable,this._rgbTableSlot=new i.schema.RGBTable}loadFromMatchHeader(t){const e=t.map();e.name()&&(this.mapName=e.name(),this.mapStats.name=e.name());const n=e.minCorner();this.minCorner.x=n.x(),this.minCorner.y=n.y(),this.mapStats.minCorner.x=n.x(),this.mapStats.minCorner.y=n.y();const r=e.maxCorner();this.maxCorner.x=r.x(),this.maxCorner.y=r.y(),this.mapStats.maxCorner.x=r.x(),this.mapStats.maxCorner.y=r.y();const i=e.bodies(this._bodiesSlot);i&&i.robotIDsLength&&this.insertBodies(i),this.mapStats.randomSeed=e.randomSeed(),this.mapStats.flooded=Int8Array.from(e.waterArray()),this.mapStats.dirt=Int32Array.from(e.dirtArray()),this.mapStats.soup=Int32Array.from(e.soupArray()),this.mapStats.pollution=Int32Array.from(e.pollutionArray()),this.pollutionNeedsUpdate=!1;const s=r.x()-n.x();this.mapStats.getIdx=(t,e)=>Math.floor(e)*s+Math.floor(t),this.mapStats.getLoc=t=>new o(t%s,Math.floor(t/s))}copy(){const t=new a(this.meta);return t.copyFrom(this),t}copyFrom(t){this.turn=t.turn,this.minCorner=t.minCorner,this.maxCorner=t.maxCorner,this.mapName=t.mapName,this.diedBodies.copyFrom(t.diedBodies),this.bodies.copyFrom(t.bodies),this.indicatorDots.copyFrom(t.indicatorDots),this.indicatorLines.copyFrom(t.indicatorLines),this.teamStats=new Map,t.teamStats.forEach((t,e)=>{this.teamStats.set(e,s(t))}),this.mapStats=s(t.mapStats)}processDelta(t){if(t.roundID()!=this.turn+1)throw new Error(`Bad Round: this.turn = ${this.turn}, round.roundID() = ${t.roundID()}`);for(var e=0;e0){var s=this.bodies.lookupIndices(t.diedIDsArray());for(let e=0;e0){const e=this.bodies.arrays;for(let n=0;n0&&this.bodies.alterBulk({id:t.bytecodeIDsArray(),bytecodesUsed:t.bytecodesUsedArray()})}distanceSquared(t,e,n,r){return(t-n)*(t-n)+(e-r)*(e-r)}calculatePollutionIfNeeded(){if(!this.pollutionNeedsUpdate)return;console.log("calculating pollution!!");let t=this.mapStats.maxCorner.x-this.mapStats.minCorner.x,e=this.mapStats.maxCorner.y-this.mapStats.minCorner.y;for(let n=0;n0){const e=t.indicatorDotLocs(this._vecTableSlot1),n=t.indicatorDotRGBs(this._rgbTableSlot);this.indicatorDots.insertBulk({id:t.indicatorDotIDsArray(),x:e.xsArray(),y:e.ysArray(),red:n.redArray(),green:n.greenArray(),blue:n.blueArray()})}}insertIndicatorLines(t){if(this.indicatorLines.clear(),t.indicatorLineIDsLength()>0){const e=t.indicatorLineStartLocs(this._vecTableSlot1),n=t.indicatorLineEndLocs(this._vecTableSlot2),r=t.indicatorLineRGBs(this._rgbTableSlot);this.indicatorLines.insertBulk({id:t.indicatorLineIDsArray(),startX:e.xsArray(),startY:e.ysArray(),endX:n.xsArray(),endY:n.ysArray(),red:r.redArray(),green:r.greenArray(),blue:r.blueArray()})}}isBuilding(t){return t==i.schema.BodyType.DESIGN_SCHOOL||t==i.schema.BodyType.FULFILLMENT_CENTER||t==i.schema.BodyType.HQ||t==i.schema.BodyType.NET_GUN||t==i.schema.BodyType.REFINERY||t==i.schema.BodyType.VAPORATOR}insertBodies(t){var e=t.teamIDsArray(),n=t.typesArray();for(let r=0;r{r.default.fill(t,0,s,this.bodies.length)})}}e.default=a},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const r=n(79);class i{constructor(t,e){if(!o(t,String(e)))throw new Error(`Primary key must exist, '${e}' not found`);this.arrays=Object.create(null),this._length=t[e].length,this._capacity=this._length,this._fieldNames=new Array,this._primLookup=new r,this._primary=e,this._indexBuffer=void 0;for(const e in t)if(o(t,e)){const n=t[e];this.arrays[e]=new n.constructor(this._capacity),this.arrays[e].set(n.slice(0,this._length)),this._fieldNames.push(e)}this._refreshPrimariesLookup(this._length)}copy(){return new i(this.arrays,this._primary)}copyFrom(t){if(this._length=t.length,this._capacitythis._capacity){this._capacity=i._capacityForLength(t);for(const t in this.arrays){const e=this.arrays[t],n=new e.constructor(this._capacity);n.set(e),this.arrays[t]=n}}this._length=t}static _capacityForLength(t){return t<=0?0:0==(t&t-1)?t:(t--,t|=t>>1,t|=t>>2,t|=t>>4,t|=t>>8,t|=t>>16,++t)}assertValid(){const t=this.arrays[this._primary];for(let e=0;et-e},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){var r=n(1),i=n(9);t.exports=function(t,e){try{i(r,t,e)}catch(n){r[t]=e}return e}},function(t,e,n){var r=n(48),i=n(29),o=r("keys");t.exports=function(t){return o[t]||(o[t]=i(t))}},function(t,e){t.exports=!1},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++n+r).toString(36)}},function(t,e,n){var r=n(49),i=n(1),o=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?o(r[t])||o(i[t]):r[t]&&r[t][e]||i[t]&&i[t][e]}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(t,e,n){var r={};r[n(2)("toStringTag")]="z",t.exports="[object z]"===String(r)},function(t,e,n){var r=n(6).f,i=n(3),o=n(2)("toStringTag");t.exports=function(t,e,n){t&&!i(t=n?t:t.prototype,o)&&r(t,o,{configurable:!0,value:e})}},function(t,e,n){var r,i=n(10),o=n(101),s=n(32),a=n(17),c=n(103),u=n(45),h=n(27),d=h("IE_PROTO"),l=function(){},f=function(t){return"