The Freecraft AI interface is designed to allow an external controller to understand the state and send actions to the Freecraft game. It does not export a full view of the state, since much of this information is either irrelevant or implied. It also does not describe any features of the map.
It builds off the Freecraft game, and therefore requires a working version of Freecraft 1.18. We have provided both the source code and a patched executable for convenience. The binary was compiled in Linux using the SDL (see preparing to install Freecraft for details), and has only been tested under RedHat. The interface uses sockets for communication, so the controller does not need to be on the same computer as the game.
There are likely to be numerous bugs in the interface, due to its size and the limited testing it has been subjected to. If you would like to be notified when the interface is updated, please join the freecraft-interface mailing list @ Contact.
If you are using Linux, you may be able to use the precompiled binary version we have provided. Recall that you do not need to run Freecraft on the same computer as your controller. If you plan to use the binary, follow step (a), then go to the download page and get the binary version of Freecraft and the patch.
a. Preparing to install Freecraft
Several files are necessary to install Freecraft. The "Software Requirements" section of the official Freecraft instructions has the following list of libraries: SDL, libpng, zlib, libogg/libvorbis (recommended), libbzip2 (optional), libFLAC (optional), libmad (optional), zziplib (optional). The instructions page has links for all but the SDL, which is available here.
b. Installing Freecraft
If you are using Linux, you may be able to use the binary on the download page. If the binary does not work, you'll have to download the Freecraft 1.18 source code and compile according to steps 1&2 of the instructions. NOTE: I have had issues compiling with version 2.96 of gcc. Try using gcc 2.95 or a 3.x version. If you have trouble, make sure you have installed all the required libraries, and have done the necessary setup steps.
c. Installing the interface
If you are using Linux, you should be able to use the patch on the download page. Otherwise, you'll have to download the FAI interface code, unzip the files into the Freecraft /src directory, and recompile.
d. Configuring the interface
By default, Freecraft uses port 5557 for computer player 1, and 5558 for computer player 2. These can be changed in the fmdp_vars.ini file in the base Freecraft directory. In addition, there a number of game settings, such as video contrast, fog-of-war, and visual orders that you may wish to modify in the freecraft.ccl file. See Customizing Freecraft for details.
3. Overview of the interface
To use the interface, you'll need to understand how the state and actions are represented, and how to receive and send them. This section covers the former. The state and actions are specified as a collection of classes and objects, and represented as a set of strings. Each string is one class, with the first character (byte) telling the class; for example, peasants you control are the 'P' class and peasants the enemy controls are the 'p' class. Following the class character is a set of numbers, with 0 to 6 numbers per object. As an example, the state may have a string such as "P 5 5 20 17 63 0 5 6 20 17 63 0". In this case, P represents the peasant class, the first 6 numbers explain the state of peasant 0, and the second 6 numbers explain the state of peasant 1. In the receiver code, we use a set of enumeration to try and make the numbers less cryptic.
When the interface is initialized, the client must "request" the number of objects of each class that it should respond to. For example, if the client requests 4 peasants, 4 enemies, and 2 "PeasantTask" actions, then the state will report information for at most 4 peasants and at most 4 enemies. Further, the client will only be able to second actions for the first 2 peasants--the other two will be inactive. Note that this DOES NOT change the map that is loaded in Freecraft. It only changes the features of the state that are reported and the actions that can be called.
For details on how the state and actions are communicated, see the Protocol. If possible, use the receiver code, as it takes care of most of the details of the communication.
a. The state
A class can be a unit type (peasant, footman), structure type (keep, barracks), or global (gold, wood). Each class is identified by a letter; upper case for the class of units that you control, lower case for the class of units the enemy controls. Each class has a fixed number of state variables, as defined below. There is a soft cap on the number of objects that can be part of a class, based on the limits of the socket message length (set to 2048 by default)--this should allow roughly 150 units of any type, which is sufficient.
Units have 6 state variables: x and y position, health, current task, target type, and target number
Structures have 4 state variables: x and y position, health, and current task
Globals have 1 state variable: value.
Classes in the interface
UNITS - Peasant ('P'), Footman ('F'), Archer ('A'), Ballista ('L')
STRUCTURES - Keep ('K') (equal to Freecraft's town hall, keep, or castle), Barracks ('B'), Mill ('M'), Blacksmith ('S'), Farm ('R'), GuardTower ('T')
GLOBALS - Gold ('G'), Wood ('W'), FoodStuff ('O') (equal to the amount of food the player can produce minus the amount of food used by the player's units)
OTHER - Enemy ('E')
Each Unit and Structure Type ('X') also has an eType ('x') variant. This refers to an object of the specified type that is an enemy. For example, eFootman ('f') is the class of peasants that you can attack.
The Enemy class is a special "catch all" class that can be used to get state information about unknown enemy types or extra enemy units beyond those requested. It can be either a unit or a structure, but only has 4 state variables: x, y, health, and task.
The State Variables: x and y positions and health are all integers. The unit's target (either to attack or repair) is indicated with the two target state variables. Target type is an ASCII character (a single byte) that maps to a state class. Target number is an integer that maps to a state object of the appropriate class. Finally, the current task is an integer referring to the 'UnitAction' enumeration from the Freecraft and interface code. The most common tasks are the following:
UnitActionNone=0, /// No valid action
UnitActionStill=1, /// unit stand still, does nothing
UnitActionMove=4, /// unit moves to position/unit
UnitActionAttack=5, /// unit attacks position/unit
UnitActionAttackGround=6, /// unit attacks ground
UnitActionDie=7, /// unit dies/is dead
UnitActionSpellCast=8, /// unit casts spell
UnitActionTrain=9, /// structure is training a new unit
UnitActionUpgradeTo=10, /// structure is upgrading itself (for town halls, keeps, and castles)
UnitActionResearch=11, /// building is researching spell (for blacksmiths)
UnitActionBuilded=12, /// building is under construction by some peasant
UnitActionBuild=16, /// unit builds building
UnitActionRepair=17, /// unit repairing
UnitActionHarvest=18, /// unit harvest lumber
UnitActionMineGold=19, /// unit mines gold
UnitActionReturnGoods=24, /// unit returning any resource
b. The actions
Actions are slightly more complicated. Each action object has 4 parameters (P0 to P3), set by the client. These should be 0s by default--an all 0 action does nothing. Each class uses the 4 parameters differently. In addition, the _order_ of the objects may be relevant. For example, if there are 3 peasants (0, 1, and 2), then PeasantTask action object 1 will refer to Peasant 1. We know describe each action and its parameters in detail.
PeasantTask ('0') - This class sends orders to Peasant objects. PeasantTask i corresponds to Peasant i. P0 specifies the action type as follows:
WORK_STOP (0) tells the unit to stop iff P1=aTRUE (1).
WORK_MOVE (1) tells the peasant to move to position (x,y), where x=P1 and y=P2.
WORK_GETGOLD (2) and..
WORK_GETWOOD (3) tell the peasant to attempt to get gold or wood (fails if the unit is building or repairing).
WORK_BUILD (4) tells the unit to attempt to build the structure of class P1, object P2.
WORK_REPAIR (5) tells the unit to attempt to repair the structure of class P1, object P2.
FootmanTask ('1'), ArcherTask ('2'), BallistaTask ('3') - These classes send orders to various units that can attack. XTask i corresponds to X i. P0 specifies the action type as follows:
STOP (0) tells the unit to stop iff P1=aTRUE (1).
MOVE (1) tells the unit to move to position (x,y), where x=P1 and y=P2.
ENEMY (2) tells the unit to attack the unit of the Enemy class, object P1 (this is short hand for P0=UNIT).
GROUND (3) tells the unit to move to position (x,y), attacking any enemy it finds along the way, where x=P1 and y=P2.
UNIT (4) tells the unit to attack the unit of class P1, object P2.
CLOSEST (5) tells the unit to attack the nearest opposing unit iff P1=aTRUE (1).
TrainUnit ('b') - This is the most complex action. First, the order detirmines the order in which the builds are attempted. For example, if you have 600 gold, and want to build both a footman and a peasant, whichever build request is first will be attempted first (though it may fail for other reasons). Second, P0 must either be BORN_BYUNIT ('?') or specify the type of structure that will be ordered to build. If P0 is BORN_BYUNIT, then the interface will find a structure for you. Otherwise, the interface will use the structure you specify.
BORN_BYUNIT: attempt to build unit of type P1, object P2, iff P3=aTRUE. If the object specified is already alive, does nothing.
Otherwise: tell structure of type P0, object P1 to build unit of type P2, object P3. If the object specified is already alive or the structure is dead or busy, does nothing. If P3 is the constant ANY_UNIT (-1), then the structure will simply build a unit of the correct type which will be assigned to any object once the unit is alive.
4. Using the receiver code
The receiver code attempts to simplify some of the complexities of using the interface. It is written in C, and represents the state and actions as a large data structure. Look at the null, defender, or attacker code on the download page to get a basic idea of how the communication structure works.
a. Basic communication
The basic data structure is FreecraftData. Do not create FreecraftData using malloc; instead, call InitFreecraftData(servername, port, kill_mode, numUnitsArray, numActionsArray) to create the FreecraftData pointer. "servername" is the host computer that is running Freecraft ("localhost" for the local machine). "port" is the port number (should be a high, arbitrary number, such as 5501). "kill_mode" determines how many units are left alive from the initial map. If set to 0, the game will kill no units; 1, the game kills excess player units; 2, the game kills excess player units and structures; 3, the game kills all excess units except the unit on the 1,1 board position (used to keep the game running after a victory).
The numUnitsArray should be an array of NUM_UNITS (256) integers. If numUnitsArray = x, then the interface will initialize x objects of class i. Likewise, if numActionsArray[j] = y, then the interface will initialize y action objects of class j. In general, the number of "XType" actions will be equal to the number of objects of class X. The TrainUnit action class will often have a different number, depending on the number of simultaneous build actions allowed.
The client should then loop, calling GetState then SendActions, either until it is done or until GetState returns 1 (indicating that Freecraft is done). After calling GetState, the client can read any of the data in the state, then should modify the actions array as desired, finally calling SendState to send the actions. Finally, when the client is done with the FreecraftData pointer, it should call FreeFreecraftData (rather than free).
b. Reading the state
Suppose we call FreecraftData data = InitFreecraftData(...). We can then read the state from the 2D array data->state. The first index specifies the class, and the second specifies the object. So data->state['p'] refers to the 4th enemy-controlled peasant. The X and Y members of a state refer to the objects's position, Task refers to a particular task as described above in the overview. Val either refers to a unit's health or to a global's value. TargetType and TargetNum only apply to units, and define the unit it is currently targeting.
c. Sending the actions
The client controls the data->actions array. As with the state, the first index specifies the action class, and the second specifies the object. So data->state['2'] refers to the ArcherTask of the 3rd archer. Each element of the array is an opts array of 4 values. Setting data->state['2'].opts = MOVE will tell the 3rd archer to move to the location specified by the next 2 parameters. See the actions section for details on what each of the options mean for different classes.
The interface uses a very straight-forward protocol. There are a series of messages to initialize the game, telling the interface how to modify the map and how many objects of each class to respond to. The bulk of the communication occurs next, sending the state class by class, then receiving each action class in turn, repeating.
Full details will be posted soon.
6. Demonstration Scenarios
There are 5 scenarios in 9 maps (available here): strategic, tactical, defensive, offensive, and war. See the README included in the download for details on the maps.
To use a map, start Freecraft. Select "Single Player Game". Choose, "Select Scenario" and choose the appropriate map. NOTE: for any computer vs. computer scenario, you MUST change the Game Type from "Use map settings" to "Free for all". Choose "Start Game". After Freecraft loads, the console will say "Waiting for client to connect". At this point, the controller for computer player 1, then computer player 2, should be started.
The game now begins, recieving actions as above (unless, of course, it crashed). To stop the game, close the Freecraft window.
There are also 3 default players available, one for each of the strategic, defensive, and offensive scenarios, available here. The defensive and offensive players can be pitted against each other. The first parameter of each is the port. For the strategic player, the second and third parameters are the maximum number of peasants and footmen respectively.
7. Customizing Freecraft
First, many aspects of Freecraft can be changed without touching the code. In data/ccl there are various LISP-like files with parameters. freecraft.ccl is the most important: you can download our default .ccl and compare them. The most relevant parameters are those for visualization (show-x) and build and resource collection speeds (set-speed). Another useful ccl file is dalliance/units.ccl: this allows you to change the attack power, defense, range, and maximum health of any unit.
If you wish to explore the code, be aware than version 1.18 may not be the latest version of Freecraft. The interface may work with more recent versions, but there is no way to guarantee this.