Ivan Geffner Salvador Roura
In this game, 4 players have control over an army of warriors and cars on a 60 × 60 board with 8 cities. The goal of the game is to “conquer” as many cities as possible.
Teams are identified with numbers from 0 to 3. Initially, every team owns 2 of the cities. Every round, the number of cities of each team is added to the corresponding score. The winner of the game is the player with the highest score after the last round.
At the beginning of the game, each team has 23 units: 20 warriors and 3 cars. The warriors start inside the cities of their teams, with at least one warrior in each city. The cars start at the edges of the board, each on a road.
The board has six kinds of cells: Desert, City, Road, Water, (fuel) Station, and Wall. Warriors can move on desert, cities and roads. Cars can only move on desert and roads. No cell can have more than one unit on it. Water cells recharge adjacent warriors with water, stations recharge adjacent cars with fuel, and walls are just impassable obstacles with no other purpose.
The game lasts 500 rounds, numbered from 0 to 499. The units of player x are only allowed to move at the rounds that are congruent to x modulo 4. For instance, player 1 can only move at rounds 1, 5, 9, etc. There is one exception: cars that have fuel and are located on a road can move regardless of the round number. Additionally, every unit can move at most once per round.
At the end of each round, and for every city, if one team has strictly more warriors inside that city than any other team, then that team conquers the city (unless the city was already owned by that team, when ownership does not change). A city is a (horizontally and vertically) connected component of cells of type City.
Units can try to move to any adjancent cell, either horizontally, vertically, or diagonally, as long as the kind of the adjacent cell is compatible with the kind of the unit. If the adjacent cell is empty, the unit moves there. Otherwise, some rules apply (see below). Units cannot move outside the board.
Initially, warriors have 40 units of food and also 40 units of water, and cars have 100 units of fuel. Every round when they are allowed to move, warriors lose 1 unit of food and 1 unit of water, and cars lose 1 unit of fuel. A warrior whose food or water level reaches 0 dies, and a randomly choosen rival team gets another warrior. A car with no fuel does not “die”, but becomes slow not only on desert but also on roads. Units can never have more food, water or fuel than its initial amount.
Any warrior on a City cell recharges its food level to 40, irrespective of the team that owns the city. Any warrior adjacent to a Water cell recharges its water level to 40. Any car adjacent to a Station cell recharges its fuel level to 100. Warriors will have to cross at least one road to reach water from a city (or back). Fuel stations will always be located on some crossroad.
A warrior can try to move to a cell where there is another warrior or a car. Similarly, a car can try to move to a cell where there is a warrior or another car. We first explain the rules that apply in the usual case when the two involved teams are different.
A car that moves to a cell with a warrior runs over it and kills (captures) it. Every moment, any dead unit dissapears from the board, and a fresh unit will appear at the next round, as explained below.
If a car moves to a cell with another car, both cars explote and dissapear, and two new cars are given to the other two teams.
A warrior that moves to a cell with a car comitts suicide, and a new warrior is given to the rival team.
Warriors can attack any adjacent warrior by an order to move to the rival’s position. In general (when the atackee has at least 6 units of both of them), the attacked warrior will lose 6 units of food and 6 units of water. Moreover, if any of those levels reaches 0, the attackee will get captured by the rival team. Furthermore, half of the food and water stolen (usually 3 units of each) will be recharged to the attacker, never exceeding the limit of 40.
There is one exception to this rule: if two warriors are inside a city and one of them attacks the other, then the thunderdome rule is used: “Two Men Enter, One Man Leaves”. After a bloody fight, one of the warriors dies, whereas the winner’s health remains unchanged.
The survivor of a thunderdome fight is decided by the board at random, with probabilities proportional to the water levels of the contestants. For instance, if one has 30 units of water and the other one 20 units, then the former will survive with probability 3/5, while the latter will survive with probability 2/5.
Note that units are allowed to attack units of the same team. As a general rule, this will probably be a bad idea, although in some cases it might be useful to sacrifice an own unit in order to save another one.
When the attacker and the atackee belong to the same team, the rules are adapted as follows. If a warrior gets killed, the new warrior will be given to another team. If a car collides with another car, the two new cars will be given to two other different teams. All those new teams will be chosen uniformly at random.
As a result of all the above rules, the total number of warriors and the total number of cars remains constant during the whole game.
Every round, more than one order can be given to the same unit, although only the first such order (if any) will be selected. Any player program that tries to give more than 1000 orders during the same round will be aborted.
The selected movements of every round will be executed using a random order. For instance, if a warrior tries to move to the position of a friend car, and that car tries to move to an empty position, then if the warrior moves first it will commit suicide, and afterwards the car will move. Otherwise, if the car moves first, both units will move and survive. As another example, if two enemy cars try to run over a warrior of another team, which does not move, the team of the first car to move will capture the warrior, and afterwards both cars will collide and explote.
After all the selected movements of a round are played, the units captured by each team are reborn. Whenever possible, cars will be placed on roads at the edges of the board, and warriors on desert cells also at the edges, always at a reasonable distance of other units. In the rare cases when this cannot be accomplished, cars will be placed on roads not at the edges, and warriors on desert cells not at the edges, also at a reasonable distance of other units. In even more exceptional situations, cars will be placed on any legal cell, and warriors also on any legal cell, but never inside a city.
If you need (pseudo) random numbers, you must use two methods provided by the game: random(l, u), which returns a random integer in [l..u], and (less frequently) random_permutation(n), which returns a vector<int> with a random permutation of [0..n-1].
Note that the valid directions are Bottom, BR, Right, RT, Top, TL, Left, LB and None, corresponding to integers from 0 to 8. This circular definition can be used to simplify the implementation of your player. See the Demo player for some examples.
A game is defined by a board and the following set of parameters:
The first thing you should do is downloading the source code. It includes a C++ program that runs the games and an HTML viewer to watch them in a reasonable animated format. Also, a “Null” player and a “Demo” player are provided to make it easier to start coding your own player.
Here, we will explain how to run the game under Linux, but it should work under Windows, Mac, FreeBSD, OpenSolaris, …You only need a recent g++ version, make installed in your system, plus a modern browser like Firefox or Chrome.
to build the game and all the players. Note that Makefile identifies as a player any file matching AI*.cc.
./Game Demo Demo Demo Demo -s 30 -i default.cnf -o default.res
This starts a match, with random seed 30, of four instances of the player Demo, in the board defined in default.cnf. The output of this match is redirected to default.res.
to see the list of parameters that you can use. Particularly useful is
to show all the recognized player names.
If needed, remember that you can run
to delete the executable and object files and start over the build.
To create a new player with, say, name Rockatansky, copy AINull.cc (an empty player that is provided as a template) to a new file AIRockatansky.cc. Then, edit the new file and change the
The name that you choose for your player must be unique, non-offensive and at most 12 characters long. This name will be shown in the website and during the matches.
Afterwards, you can start implementing the virtual method play(), inherited from the base class Player. This method, which will be called every round, must decide the orders to give to your units.
You can define auxiliary type definitions, variables and methods inside your player class, but the entry point of your code will always be the play() method.
From your player class you can also call functions to access the state of the game. Those functions are made available to your code using inheritance, but do not tell your Software Engineering teachers because they might not like it. The documentation about the available functions can be found in an additional file.
Note that you must not edit the factory() method of your player class, nor the last line that adds your player to the list of available players.
To test your strategy against the “Dummy”, we provide AIDummy.o object files for this player. This way you still will not have the source code of our “Dummy”, but you will be able to add it as a player and compete against it locally.
To add the “Dummy” player to the list of registered players, you will have to edit the Makefile file and set the variable DUMMY_OBJ to the appropriate value. Remember that object files contain binary instructions targeting a specific machine, so we cannot provide a single, generic file. If you miss an object file for your architecture, contact us and we will try to supply it.
You can also ask your friends for the object files of their players and add them to the Makefile by setting the variable EXTRA_OBJ.
When you think that your player is strong enough to enter the competition, you can submit it to the Jutge. Since it will run in a secure environment to prevent cheating, some restrictions apply to your code: