For documentation on the API, see this document. To get started developing a bot, see our Github. For Advanced specs documentation that goes over the actual engine code implementation, see this document.
We are always looking for feedback and bug reports, if you find any issues with the code, specifications etc. please ping us on Discord or post a GitHub Issue
As the sun set on the world an array of lights dotted the once dark horizon. With the help of a brigade of toads, Lux had made it past the terrors in the night to see the dawn of a new age. Seeking new challenges, plans were made to send a forward force with one mission: terraform Mars!
In the Lux AI Challenge Season 2, two competing teams control a team of Factory and Robots that collect resources and plant lichen, with the main objective to own as much lichen as possible at the end of the turn-based game. Both teams have complete information about the entire game state and will need to make use of that information to optimize resource collection, compete for scarce resources against the opponent, and grow lichen to score points.
Each competitor must program their own agent in their language of choice. In the NeurIPS edition, each turn, each agent gets 9 seconds to submit their actions, excess time is not saved across turns. In each game, each player is given a pool of 60 seconds that is tapped into each time the agent goes over a turn's 9-second limit. Upon using up all 60 seconds and going over the 9-second limit, the agent freezes and loses automatically.
The rest of the document will go through the key features of this game.
The world of Lux is represented as a 2d grid. Coordinates increase east (right) and south (down). The map is always a square and is 48 tiles long. The (0, 0) coordinate is at the top left. The map has various features including Raw Resources (Ice, Ore), Refined Resources (Water, Metal), Robots (Light, Heavy), Factories, Rubble, and Lichen. Code wise, the coordinate (x, y) in a map feature such as rubble is indexed by board.rubble[x][y]
for ease of use.
Each player will start the game by bidding on factory placement order, then alternating placing several Factories and specifying their starting resources. See the Starting Phase for more details.
The Day/Night cycle consists of a 50 turn cycle, the first 30 turns being day turns, the last 20 being night turns. During the day, solar panels replenish the power of all Robots but during the night robots power is not recharged. Factories generate power each turn regardless with a base amount of 50 power from their nuclear reactor and additional power from connected lichen tiles
There are two kinds of raw resources: Ice and Ore which can be refined by a factory into Water or Metal respectively. These resources are collected by Light or Heavy robots, then dropped off once a robot transfers them to a friendly factory, which then automatically converts them into refined resources at a constant rate. Refined resources are used for growing lichen (scoring points) as well as building more robots. Lastly, factories will process ice and ore integer units at a time without wasting any based on the processing ratio. E.g. if a factory has 8 ore, it will refine 5 ore into 1 metal and leave 3 ore leftover; if a factory has 7 ice, it will refine 4 ice into 1 water and leave 3 ice leftover.
Raw Type | Factory Processing Rate | Refined Type | Processing Ratio |
Ice | 100/turn | Water | 4:1 |
Ore | 50/turn | Metal | 5:1 |
During the first turn of the game, each player is given the map, starting resources (N
factories and N*150
water and metal), and are asked to bid for who goes first/second. Each 1 bid removes 1 water and 1 ore from that player's starting resources. Each player responds in turn 1 with their bid, which can be positive to prefer going first or negative to prefer going second.
Whichever player places the highest absolute bid loses that amount of water and ore from their starting resources and gets to place first (or second if they bid a negative value). If both players tie in bid amount, then the first player / player_0 wins the bid.
During the next 2*N
turns of the game, each player alternates between spawning a factory or doing nothing as the other player spawns a factory with the winner of the bid placing first. Each player may select any location on the map that can fit a 3x3 factory that doesn't overlap any ice/ore resources, and the center is 6 tiles or more away from another existing factory's center. Any factories our starting resources not used are lost.
Strategy Tip: Going first is not always advantageous!
Robots and Factories can perform actions each turn given certain conditions and enough power to do so. In general, all actions are simultaneously applied and are validated against the state of the game at the start of a turn. Each turn players can give an action to each factory and a queue of actions to each robot.
Robots always execute actions from an action queue (limited to 20 items) while factories directly execute actions. Each robot action in the queue has an n
value and a repeat
value. n
represents the number of times the robot will execute a particular action before removing it from the front of the queue. If repeat == 0
, the action is removed from the queue once completed n
times. If repeat > 0
, then we recycle the action to the back of the action queue with n = repeat
now.
An action is considered executed if it's valid against current state, namely there is sufficient power to perform the action. If it's not valid, that turn it will not count towards n
.
Submitting a new action queue for a robot requires the robot to use additional power to replace it's action queue. It costs an additional 1 power for Lights, an additional 10 power for Heavies (two weight classes of robots). The new action queue is then stored and wipes out what was stored previously. If the robot does not have enough power, the action queue is simply not replaced.
repeat = True
allows you to design action queues that repeat infinitely and don't need any updates, saving power. n
allows for generally more complex action sequences to be designed in an action queue which is limited to 20 actions.
The next few sections describe the Robots and Factories in detail.
There are two robot types, Light and Heavy. Every robot has an action queue and will attempt to execute the action at the front of the queue.
Dimension | Light | Heavy | Factory |
Cargo Space | 100 | 1000 | Infinite |
Battery Capacity | 150 | 3000 | Infinite |
Power Charge (during day) | 1 | 10 | 50* all the time |
Light and Heavy Robots share the same set of actions / action space. However, in general, heavy robots generally accomplish 10x more with their actions but their actions will cost more power.
The following table summarizes the configurations.
Action | Light | Heavy |
Move | floor(1 + 0.05 * rubble value of target square) power | floor(20 + 1 * rubble value of target square) power |
Transfer | 0 power | 0 power |
Pickup | 0 power | 0 power |
Dig | 5 power (2 rubble removed, 2 resources gain, 10 lichen value removed) | 60 power (20 rubble removed, 20 resource gain, 100 lichen value removed) |
Self Destruct | 10 power | 100 power |
Recharge X | 0 power | 0 power |
Each square on the map has a rubble value which affects how difficult that square is to move onto. Rubble value is an integer ranging from 0 to 100 inclusive. The exact power required to move into a square with rubble can be found on the table above. Rubble can be removed from a square by a light or heavy robot by executing the dig action while occupying the square.
This environment also has robot collisions. Robots which move onto the same square on the same turn can be destroyed and add rubble to the square according the following rules:
Each light robot destroyed in this way adds 1 rubble. Each heavy robot destroyed in this way adds 10 rubble. (same values as self destructs).
Lastly, any addition of rubble onto a tile with Lichen on it will automatically remove all of the lichen on that tile.
A factory is a building that takes up 3x3 tiles of space. Robots created from the factory will appear at the center of the factory. Allied robots can move onto one of the factory's 9 tiles, but enemies cannot.
Each turn a factory will automatically:
If there is no water left, the nuclear reactor that powers the factory will explode, destroying the factory and leaving behind 50 rubble on each of the 3x3 tiles.
Each factory can perform one of the following actions
ceil(# connected and new lichen tiles / 10)
water. (Note that in starter kits the exact water cost is not provided, only a conservative estimate)The following is the cost to build the two classes of robots. Note that also robots when built will have their battery charged up to the power cost.
Robot Type | Metal Cost | Power Cost |
Light Robot | 10 | 50 |
Heavy Robot | 100 | 500 |
Lichen serves two purposes.
At the start, factories can perform the water action to start or continue lichen growing. Taking this action will seed lichen in all orthogonally adjacent squares to the factory if there is no rubble present (total of 3*4=12). Whenever a tile has a lichen value of 20 or more and is watered, it will spread lichen to new adjacent tiles without rubble, resources, or factories and give them lichen values of 1. The amount of water consumed by the water action grows with the number of tiles with lichen on them connected to the factory according to ceil(# connected and new lichen tiles / 10)
. In each tile a maximum of 100 lichen value can be stored.
All factories have their own special strains of lichen that can’t mix, so lichen tiles cannot spread to tiles adjacent to lichen tiles from other factories. This is for determinism and simplified water costs.
Factories also gain power equal to the number of their own connected lichen tiles each turn. For example, a factory with 12 attached lichen tiles (of any lichen value) gains 62 power each turn as opposed to the default 50.
When rubble is added to a tile, that tile loses all lichen.
Additionally, robots can dig on a tile with lichen and reduce it over time. If all lichen on a tile is removed in this way, rubble is added preventing lichen from regrowing back immediately.
If a number of lichen tiles get disconnected from your factory (due to some rubble being added to a tile or being dug out), they cannot be watered (and thus will lose 1 lichen value) until connected again through lichen tiles. These tiles still count to your score however.
At the end of each turn, all tiles that have not been watered lose 1 lichen.
To help avoid confusion over smaller details of how each turn is resolved, we provide the game resolution order here and how actions are applied.
Actions in the game are first all validated against the current game state to see if they are valid. Then the actions, along with game events, are resolved in the following order and simultaneously within each step
After 1000 turns, the winner is whichever team has the most lichen value on the map. If any team loses all of their factories, they automatically lose and the other team wins. If the lichen value is tied or both teams lose all their factories at the same time, then the game ends in a draw.
Our team at the Lux AI Challenge reserves the right to make any changes on game rules during the course of the competition. We will work to keep our decision-making as transparent as possible and avoid making changes late on in the competition.