# **Formal specification** _This is the formal specification of the Battlecode 2024 game._ Current version: *3.0.5* **Welcome to Battlecode 2024: Breadwars.** This is a high-level overview of this year's game. It is highly recommended to read this entire document before you begin writing bots. _This document and the game it describes may be tweaked as the competition progresses. We'll try to keep changes to a minimum, but may have to make modifications to keep the game balanced. Any changes will be announced in the official Discord channel. You may find a Changelog at the bottom of this document._ # **Background** Flowers blossom and snowfall melts. Civilization has eroded away after millenia, giving way to a beautiful oceanic world teeming with life. Hiding away on an unnamed island is a lake where a great city once stood – for thousands of years in this lake, the last remaining magical and mutant robots of the past have slowly evolved to suit their surroundings. But where could they be? Amongst the chatter, a pair of loud quacks ring out. Small feet splash through the water and metallic feathers fall as the robots, now two opposing flocks of avian adversaries, prepare to fight. Spring is coming, and with it, the annual avian bread battles. Scramble, scamper, swerve, and swim as you dodge your opponents to steal their bread and put your flock on top. # **Objective** In Battlecode: Breadwars, your goal is to capture the opponent’s flags. The first team to capture all 3 flags wins the game. **Setup Phase** The two teams will be separated by an impassable dam during the first **200** rounds of the game. Teams will use this period to collect resources, modify the terrain, and set up defenses for their flags. After the setup phase, the dam will collapse and allow both teams to move freely. Each team has **3** flags. When the game starts, flags are located at the centers of each team’s three spawn zones. Any unit can pick up and place a flag at any time during the setup phase. When the setup phase ends, the new locations of the flags will become the default flag locations for the remainder of the game. If a flag is being carried, it will be automatically dropped at the robot’s location. Default flag placements must be a minimum distance of **$\sqrt{36}$** units apart on the map. If two flags are less than this distance apart at the end of the setup phase, all flags for the team will be teleported back to the spawn zones, which will become their default locations. **Tiebreakers** If neither team has captured all 3 flags after 2000 rounds, the game will end immediately. The following tiebreakers are applied in order to determine the winning team: * Number of flags captured * Sum of all unit levels across all skills * Amount of crumbs * A uniformly random team will be selected # **Map** Each Battlecode game will be played on a map. The map is a discrete 2-dimensional rectangular grid of size ranging between 30×30 and 60×60 inclusive. The bottom-left corner of the map will have coordinates (0, 0); coordinates increase East (right) and North (up). Coordinates on the map are represented as MapLocation objects holding the x and y coordinates of the location. In order to prevent maps from favoring one player over another, it is guaranteed that the world is symmetric either by rotation or reflection. **Spawn zones** Each team has **3** spawn zones, which are 3x3 in size and pre-placed on the map. The zones cannot be moved, destroyed, or covered with water. The centers of spawn zones for each team will be at least **$\sqrt{36}$** units apart. **Resources** Building, digging, and filling all require spending crumbs. Each game will start with a finite amount of crumbs scattered around the map. Either team can access the crumbs and collect them for their own use. A bot collects crumbs by simply moving onto the tile. Upon collection, the crumbs are immediately added to the team’s global resource pool. No additional crumbs will spawn on the map, but each team will passively gain **10** crumbs at the beginning of every round. Teams start with **400** crumbs before collecting any crumbs from the map. **Passability and Visibility** Walls may be sparingly scattered around the map and will be impassable to either team’s robots. Walls will remain fixed throughout the game and cannot be destroyed. Patches of water may also be scattered around the map. These tiles are also impassable by default, but can be built over using the fill action. Water can also be created by performing the dig action. Robots can always sense map features and other robots up to $\sqrt{20}$ units away, regardless of the presence of walls or water. # **Units** The game is turn-based and divided into rounds. In each round, every robot gets a turn in which it gets a chance to run code and take actions. Code that a robot runs costs bytecodes, a measure of computational resources. A robot only has a predetermined amount of bytecodes available per turn, after which the robot's turn is immediately ended and computations are resumed on its next turn. If your robot has finished its turn, it should call Clock.yield() to wait for the next turn to begin. All robots have **1000** HP (also known as hitpoints, health, life, or such). When a robot's HP reaches zero, the robot is sent to jail (described below). Robots are assigned unique random IDs no smaller than 10,000. Robots interact with only their nearby surroundings through sensing, moving, and other actions. Each robot runs an independent copy of your code. Robots will be unable to share static variables (they will each have their own copy), because they are run in separate JVMs. Every unit is initially identical with the same base stats and attributes. Each team always has **50** robots, although robots are not all necessarily spawned into the game at all times. **Spawning** At the start of the game, no units are present on the map. All units must be manually spawned in by specifying a location in one of the spawn zones. All 50 robots still run their code once per turn regardless of if they are spawned, but all actions besides spawning are impossible when not spawned. **Specializations** Specializations allow robots to become more powerful in specific skills. When a unit attacks, heals, or builds (including building traps and digging), it gains one experience point in that skill. When experience reaches a certain threshold, the skill is automatically upgraded to the next level. Once a unit reaches the **fourth level** of any specialization, the unit gains “mastery” in that action. This means that only this action is allowed to progress to the fifth and sixth levels of specialization, and every other action is capped at level three. Specialization stats are provided in the Specialization Stats section. **Jail** Once a unit reaches health <= 0, it immediately leaves the map and goes to ‘jail.’ It must wait for **25** rounds before it can be respawned at a spawn zone. The unit also receives a penalty to their highest level specialization (tiebreakers resolved from left to right as indicated in the destruction penalty table). **Communication** Units can only see their immediate surroundings and are independently controlled by copies of your code, making coordination very challenging. You will be unable to share any variables between them; note that even static variables will not be shared, as each unit will receive its own copy. However, robotic voice boxes programmed with the team’s dialect allow each unit to quack to all other ducks in their language from anywhere on the map. To communicate, units can read and write from a shared array of 64 non-negative integers strictly less than 216. Array values persist across turns; ie. they are not reset. # **Actions** The following are all actions that a robot can perform. Robots are only allowed to perform actions when the corresponding cooldown value is **< 10**. Movement has its own cooldown counter, while all other types of actions share a single cooldown counter. Both cooldown counters decrease by **10** each turn. **Movement** Each unit can move by one tile in any unobstructed and unoccupied direction. Units can move in all 4 cardinal directions and diagonally. After moving, the movement cooldown counter is increased by **+10**. When carrying a flag, this cooldown cost is increased to **+20.** **Attacking** Robots can attack enemy robots within **$\sqrt{4}$** tiles. Robots may only attack tiles that contain an enemy robot (no missed attacks are allowed). Attacking incurs a base health penalty of **-150** points to the enemy robot and adds **+20** to the attacking robot’s action cooldown. If your robot kills an enemy robot while your robot is in enemy territory, your team gains **30** crumbs. Enemy territory consists of all tiles that were originally accessible to the enemy during the setup phase. **Healing** Heals a friendly unit within **$\sqrt{4}$** tiles. Healing is only allowed when the friendly unit is below max health, and can only heal the unit up to the maximum health. Healing increases health by **+80** and has a cooldown cost of **+30**. Units cannot heal themselves. **Building** Uses crumbs to build a trap at a location at most **$\sqrt{2}$** units away from the robot. The trap is constructed immediately. Traps cannot be built on a tile occupied by or adjacent to an enemy robot or a tile that already has a trap. The cooldown and crumb cost depend on the trap and are specified in the Traps section. **Pickup/Drop Flag** A robot can pick up or drop a flag at a location at most **$\sqrt{2}$** units away. During the setup phase, robots can carry flags from their own team, but after the setup phase robots may only pick up flags from the enemy team. Flags cannot be dropped on water, walls, or the dam. More details on flag mechanics are specified in the Flags section. Action cooldown cost is **+10**, and dropping the flag also increases the movement cooldown by **+10**. **Digging** Digs at a location up to **$\sqrt{2}$** units away, creating water on the tile. Robots cannot dig on water tiles, walls, spawn zones, or tiles occupied by other robots or flags. Digging on an explosive trap will activate the trap. Digging costs **20** crumbs and has a base cooldown of **+20**. **Filling** Fills at a location up to **$\sqrt{2}$** units away, converting water to land. Filling costs **30** crumbs and has a base cooldown of **+30**. # **Flags** The goal of attacking is to retrieve your opponent’s flags and bring them to your side. To retrieve this flag, your robots must first find the opponent's flag. Robots can sense all flags within vision radius at all times, including flags that are picked up by other robots. Additionally, at the end of the setup phase, dropped enemy flags start broadcasting their approximate locations, which serves as a hint for seeking them out. Robots can sense locations of dropped enemy flags outside of vision radius that are accurate within a radius of **$\sqrt{100}$** cells. Every **100** turns, the broadcast location is updated to a new random location within that radius. Robots can pick up and drop flags as described in the actions section. While holding a flag, robots cannot perform any actions besides movement, and robots may carry only one flag at a time. If your robot enters a friendly spawn zone while carrying an enemy flag, your team captures the flag and it is permanently removed from the game. Flags cannot be captured by being dropped into the spawn zone. If a robot dies while carrying a flag, the flag is immediately dropped on the ground at the robot’s location. The defenders must prevent the flag from being reacquired. If the flag remains on the ground for a base of **4** rounds, it instantly returns to its default location as described in the Setup section. Flags can potentially be stacked on the same tile if two units carrying flags are jailed in the same location. Both flags will maintain independent timers before they return to their original locations. When performing a pickup on that tile, the oldest dropped flag will be picked up first. # **Traps** **Your team can place traps to help defend your flags**. No friendly traps are triggered by friendly units. No traps can be built on any tile occupied by or adjacent to an enemy robot, but the traps can be built anywhere on the map. Friendly traps can be sensed, but enemy traps are invisible. | Name | Cost | Function | Action cooldown | --- | --- | --- | --- | Explosive trap | 200 crumbs | Can be built on land or in water. When an opponent robot enters the cell containing this trap, it explodes dealing **750** damage to all opponent robots within a radius of $\sqrt{4}$ cells. When an opponent robot digs, fills, or builds on the trap, it explodes dealing **200** damage to all opponent robots within a radius of $\sqrt{2}$ cells. The build will fail when this happens, while dig and fill will succeed. | 5 | Water trap | 100 crumbs | Can only be built on land. Digs all non-occupied land in a radius of $\sqrt{9}$ when an opponent robot enters a tile within $\sqrt{2}$ units of the trap. | 5 | Stun trap | 100 crumbs | Can only be built on land. Stuns all enemy robots in a radius of $\sqrt{13}$ when an opponent enters a tile within $\sqrt{2}$ units of the trap, setting all of those robots’ movement and action cooldowns to **40**. | 5 # **Global Upgrades** Every **600** rounds, each team is awarded one upgrade point. These points can be spent on global upgrades that apply to all units on the team. Each upgrade has a maximum of one level and can only be activated once. | Name | Function | --- | --- | | Attack Upgrade - Swift Beaks | Increases base attack by **+60**. | Healing Upgrade - Down Feathers | Increases base heal by **+50** health points. | Capturing Upgrade - Thin Slices | Increases the dropped flag return delay of the other team’s flag to **25** rounds. Decreases movement cooldown when carrying the flag to **+12**. # **Specialization Stats** **Level requirements (# of actions)** | Level | Attack Exp | Build Exp | Heal Exp | --- | --- | --- | --- | 0 | 0 | 0 | 0 | 1 | 15 | 5 | 20 | 2 | 30 | 10 | 40 | 3 | 45 | 15 | 70 | 4 | 75 | 20 | 100 | 5 | 110 | 25 | 140 | 6 | 150 | 30 | 180 **Specialization Jailed Penalty** | Level | Attack | Build | Heal | --- | --- | --- | --- | 0 | -1 | -1 | -1 | 1 | -2 | -2 | -5 | 2 | -2 | -2 | -5 | 3 | -5 | -3 | -10 | 4 | -5 | -3 | -10 | 5 | -10 | -4 | -15 | 6 | -12 | -6 | -18 **Specialization Effects Per Action** | Level | Attack | Build | Heal | --- | --- | --- | --- | 0 | Base | Base | Base | 1 | -5% Cooldown Cost
+5% Damage | -5% Cooldown
-10% Cost | -5% Cooldown
+3% Heal | 2 | -7% Cooldown Cost
+7% Damage | -10% Cooldown
-15% Cost | -10% Cooldown
+5% Heal | 3 | -10% Cooldown Cost
+10% Damage | -15% Cooldown
-20% Cost | -15% Cooldown
+7% Heal | 4 | -20% Cooldown Cost
+30% Damage | -20% Cooldown
-30% Cost | -15% Cooldown
+10% Heal | 5 | -35% Cooldown Cost
+35% Damage | -30% Cooldown
-40% Cost | -15% Cooldown
+15% Heal | 6 | -60% Cooldown Cost
+60% Damage | -50% Cooldown
-50% Cost | -25% Cooldown
+25% Heal # **Bytecode limits** Robots are also very limited in the amount of computation they are allowed to perform per turn. Bytecodes are a convenient measure of computation in languages like Java, where one Java bytecode corresponds roughly to one basic operation such as “subtract” or “get field”, and a single line of code generally contains several bytecodes (for details see[ here](http://en.wikipedia.org/wiki/Java_bytecode)). Because bytecodes are a feature of the compiled code itself, the same program will always compile to the same bytecodes and thus take the same amount of computation on the same inputs. This is great, because it allows us to avoid using time as a measure of computation, which leads to problems such as nondeterminism. With bytecode cutoffs, re-running the same match between the same bots produces exactly the same results - a feature you will find very useful for debugging. Every round each robot sequentially takes its turn. If a robot attempts to exceed its bytecode limit (usually unexpectedly, if you have too big of a loop or something), its computation will be paused and then resumed at exactly that point next turn. The code will resume running just fine, but this can cause problems if, for example, you check if a tile is empty, then the robot is cut off and the others take their turns, and then you attempt to move into a now-occupied tile. Instead, use the Clock.yield() function to end a robot's turn. This will pause computation where you choose, and resume on the next line next turn. The bytecode limit for all units is **25,000**. Some standard functions such as the math library and sensing functions have fixed bytecode costs, available [here](https://github.com/battlecode/battlecode24/blob/master/engine/src/main/battlecode/instrumenter/bytecode/resources/MethodCosts.txt). More details on this at the end of the spec. # **Appendix: Other resources and utilities** ## **Sample player** examplefuncsplayer, a simple player which performs various game actions, is included with battlecode. It includes helpful comments and is a template you can use to see what RobotPlayer files should look like. If you are interested, you may find the full game engine implementation [here](https://github.com/battlecode/battlecode24/tree/master/engine). This is not at all required, but may be helpful if you are curious about the engine's implementation specifics. ## **Debugging** Debugging is extremely important. See the debugging tips to learn about our useful debug tools. ## **Monitoring** The Clock class provides a way to identify the current round (rc.getRoundNum()), and how many bytecodes have been executed during the current round (Clock.getBytecodeNum()). ## **GameActionExceptions** GameActionExceptions are thrown when something cannot be done. It is often the result of illegal actions such as moving onto another robot, or an unexpected round change in your code. Thus, you must write your player defensively and handle GameActionExceptions judiciously. You should also be prepared for any ability to fail and make sure that this has as little effect as possible on the control flow of your program. Throwing any Exceptions cause a bytecode penalty of 500 bytecodes. Unhandled exceptions may paralyze your robot. ## **Complete documentation** Every function you could possibly use to interact with the game can be found in our javadocs. # **Appendix: Other restrictions** ## **Java language usage** Players may use classes from any of the packages listed in AllowedPackages.txt, except for classes listed in DisallowedPackages.txt. These files can be found [here](https://github.com/battlecode/battlecode24/tree/engine-functional/engine/src/main/battlecode/instrumenter/bytecode/resources). Furthermore, the following restrictions apply: Object.wait, Object.notify, Object.notifyAll, Class.forName, and String.intern are not allowed. java.lang.System only supports out, arraycopy, and getProperty. Furthermore, getProperty can only be used to get properties with names beginning with "bc.testing.". java.io.PrintStream may not be used to open files. Note that violating any of the above restrictions will cause the robots to explode when run, even if the source files compile without problems. ## **Memory usage** Robots must keep their memory usage reasonable. If a robot uses more than 8 Mb of heap space during a tournament or scrimmage match, the robot may explode. ## **More information on bytecode costs** Classes in java.util, java.math, and scala and their subpackages are bytecode counted as if they were your own code. The following functions in java.lang are also bytecode counted as if they were your own code. `Math.random StrictMath.random String.matches String.replaceAll String.replaceFirst String.split` The function System.arraycopy costs one bytecode for each element copied. All other functions have a fixed bytecode cost. These costs are listed in the[ MethodCosts.txt file](https://github.com/battlecode/battlecode24/blob/master/engine/src/main/battlecode/instrumenter/bytecode/resources/MethodCosts.txt). Methods not listed are free. The bytecode costs of battlecode.common functions are also listed in the javadoc. Basic operations like integer comparison and array indexing cost small numbers of bytecodes each. Bytecodes relating to the creation of arrays (specifically NEWARRAY, ANEWARRAY, and MULTIANEWARRAY; see[ here](https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings) for reference) have an effective cost greater than a single bytecode. This is because these instructions, although they are represented as a single bytecode, can be vastly more expensive than other instructions in terms of computational cost. To remedy this, these instructions have a bytecode cost equal to the total length of the instantiated array. Note that this should have minimal impact on the typical team, and is only intended to prevent teams from repeatedly instantiating excessively large arrays. # **Appendix: Lingering questions and clarifications** If something is unclear, direct your questions to our Discord where other people may have the same question. We'll update this spec as the competition progresses. # **Appendix: Changelog** - Version 3.0.5 (February 1, 2024) - Engine improvements - Add HS & newbie maps - Client improvements - Add HS & newbie maps - Version 3.0.4 (January 30, 2024) - Engine improvements - Replay filename now gets truncated if it is too long - Version 3.0.3 (January 29, 2024) - Engine improvements - Add qualifier maps - Client improvements - Add qualifier maps - Double elim visualizer improvements - Version 3.0.2 (January 28, 2024) - Client improvements - Tournament mode improvements - Version 3.0.1 (January 26, 2024) - Bug fixes - Fix issue with capturing upgrade movement cooldown - Version 3.0.0 (January 24, 2024) - Balance changes - Explosive trap cost 250 -> 200 - Stun trap stun cooldown 50 -> 40 - Kill crumb reward 50 -> 30 - Capturing upgrade flag return delay 8 -> 21 (for a total of 25 rounds) - Attack upgrade attack increase 75 -> 60 - Client improvements - Added sprint 2 maps - Global upgrades now display in chronological order - Console performance improved (esp with lots of printed exceptions) - Tournament mode improvements - Version 2.0.3 (January 22, 2024) - Client improvements - Added HungerGames sprint 1 map - Version 2.0.2 (January 20, 2024) - Engine fixes - Corrected issue where stun trap was using old cooldown (40) - Version 2.0.1 (January 17, 2024) - Engine fixes - getSpawnZoneTeam() will still return int for backwards compatability - getSpawnZoneTeamObject() will return a Team object - 'ACTION' global upgrade retained for backwards compatability, will function as 'ATTACK' - Fixed null pointer exception with senseLegalStartingFlagPlacement - Version 2.0.0 (January 17, 2024) - Balance changes - Decreased attack level XP requirements - Increased heal level XP requirements - Increased attack skill effects (greater cooldown reduction, greater damage bonus) - Increased jailed penalties for healing, decreased for attacking and building - Units can no longer heal themselves - Filling crumb cost 20 -> 30, cooldown 10 -> 30, removed movement cooldown penalty - Explosive trap nerf - Radius when triggered by walking on trap $\sqrt{13}$ -> $\sqrt{4}$ - Radius when triggered by building $\sqrt{9}$ -> $\sqrt{2}$ - Damage when triggered by building, digging, or filling 500 -> 200 (fixed bug causing damage to always be 750) - Stun trap and water trap trigger radius 1 -> $\sqrt{2}$ - Stun trap stun rounds 40 -> 50 - Flag broadcast radius $\sqrt{10}$ -> $\sqrt{100}$ - Global upgrades can now be acquired every 600 rounds instead of 750 - Changed action global upgrade to attack upgrade - Capturing upgrade now also decreases movement cooldown while carrying a flag to +12 - Robots can now sense the global upgrades owned by either team using getGlobalUpgrades() - Engine improvements - The senseLegalStartingFlagPlacement method no longer checks if the location is adjacent to the robot - Added getAttackDamage() and getHealAmount() methods - getSpawnZoneTeam() now returns a Team object - Version 1.2.5 (January 16, 2024) - Engine improvements - Added sprint 1 maps - Client improvements - Added sprint 1 maps - Tournament mode enhancements - Fix occasional whitescreening issue - Add config to enable map validation - Version 1.2.4 (January 15, 2024) - Client improvements - Distinguish between match winner (medal icon) and overall game winner (crown icon) - Display flagID in robot and map tooltips - Fix errors when a player resigns - Improvements to tournament mode - Version 1.2.3 (January 14, 2024) - Engine fixes - senseLegalFlagPlacement now only considers dropped flags as intended - Fixed RobotInfo incorrect hasFlag value - Javadoc / spec fixes - Clarified sensePassability javadoc, fixed javadoc typos - Fixed incorrect flag broadcast radius in spec - Clarified senseLegalFlagPlacement behavior - Client improvements - Fixed desync visual issue when streaming live replays - Draggable tooltip can now be moved outside of the map area - Spawn zone map guarantee check now considers walls and more than two map segments - Improve scaffold locator to prevent empty map and player lists - Changed upload replay hotkey from 'Shift' to 'Ctrl/Cmd + O' - Map tooltip now updates immediately when editing in the map editor - Version 1.2.2 (January 12, 2024) - Spec fixes - Minor typo fixes - Engine fixes / improvements - Added more isSpawned assertions - Client improvements - Fixed dams crashing the map editor - Runner console quality-of-life additions - Added version # to sidebar - Added update rechecking while client is open - Version 1.2.1 (January 11, 2024) - Hotfix relating to game tab scrolling in the client - Version 1.2.0 (January 11, 2024) - Spec fixes - Clarified definition of enemy territory - Clarified trap triggering behavior - Fixed incorrect respawn delay value - Engine fixes / improvements - Added flag IDs to FlagInfo - Added dams to MapInfo - Added team territory to MapInfo - Fixed enemy tetrritory detection issue for crumb rewards - Fixed javadoc typos - Fixed negative XP issue - Balance changes - Base healing cooldown increased from 20 to 30 (to match spec) - Dropping the flag now incurs a +10 movement cooldown - Client improvements - Added config for live match streaming (default false) - Improve live match streaming performance & reliability - Added cooldowns & team color to robot tooltip - Fixed robot incorrect location when moving and being jailed on the same turn - Fixed inconsistent map info tooltips - Better error handling when pressing 'Run Game' - Hovering a tile will now display map info (no longer click) - Fix startup crash on MacOS - Fixed parts of the client getting highlighted that shouldn't - Fixed some issues with scrubbing in the control bar - Version 1.1.0 (January 9, 2024) - Spec fixes - Clarified general robot behavior in intro of Units section - Clarified spawning mechanics - Fixed typos - Balance changes - Killing a robot while in enemy territory now results in a reward of **50** crumbs - Filling no longer yields building XP (but still receives benefits from building level) - Jailed rounds increased from **10** to **25** - Increased healing specialization XP requirements (see table) - Engine fixes - Picking up an enemy flag in a friendly spawn zone now results in capture - Robots can no longer dig on friendly traps - Client improvements - Games executed in the runner now display live as the game is being played - Multiple indicator dots & lines per robot can be visualized - Attempted fix for client config being reset between games - Added new spawn zone map guarantee checks in the map editor - Fixed some issues with the default scaffold locator - Fixed overscrolling and overflow styling issues ## Notes [^1]: These units are in terms of actual cells (not squared units as in previous years of Battlecode).