Writing Your Own AI for Lux Delux
Program your own Lux AIs using Java and the SDK. The SDK is public classes (the Lux API) as well as the source code of all of the AIs that come with Lux. Download the Lux SDK. This document will help you along the path.
You need the Java Developer Tools installed. See the installing JDK page if you need details for your platform.
Getting Lux To Load Your Agent
Lux loads compiled agents from the Agents directory inside the Lux SupportFolder. You must restart Lux if you update your class file, as Lux reads the agents the first time it is used, and after that they stay resident.
Debug Messaging and How to tell what's happening
System.out.println() will appear on standard out (plus the Console.app on Mac OS X). Lux also writes these messages to the LogFile. You might want to add some methods to your 'bot that dumps the strings to a purpose built file.
Setup your IDE to use a real debugger to set breakpoints or step through your agent. See the real debugging page for details on different IDEs.
The Phases of the Game
- Starting Out
- Smart Agent Base
- Initial Country Choosing
- How to decide which
- Initial Deployment
- How to decide where
- Cards Phase
- Attack Phase
- Fortify Phase
The Lux SDK source code examples provide some solutions to the phases. Their behavior uses a 'expert system' approach coded by Dustin. There is much room for improvement in this. The code is commented and meant to be subclassed.
Or you can start fresh using any technique you know.
Writing your Agent
You start coding your own AI by creating a simple text file named after your bot. In my case, I've named my agent Ravitar, so my text file is simply Ravitar.java . This document assumes you have enough experience in Java, or enough native intelligence, or both, to figure out how to get a leg up on this part of the creation of your Agent.
In other words, pick a house 'bot from the examples directory, copy the file to YourBotName.java, and file off the serial numbers.
Make sure you pick one that extends SmartAgentBase if this is your first bot. as you get more experienced, you'll probably start coding Agents from a blank sheet of paper.
The setPrefs function is part of the LuxAgent interface, meaning you need to write it yourself. This function is simple but essential: you are passed a copy of the game's Board object, which you should save so you can use it later. You also need to save your ID number, so you know what countries are yours and which ones are the enemy's.
Initial Country Choosing
If you are playing with the initial country selection dropdown set to 'Selected', then your agent is responsible for deciding which country to pick. If the game is set to 'Random', however, this entire problem goes away.
When Selected is the rule, the engine will repeatedly call your agent's int pickCountry() method. The return value of this method is of type int, and not Country (just to confuse you). Decide which Country you want (see below), get its country code by calling its .getCode() method, and then return that from the method:
public int pickCountry()
Country c = null;
// pick a country
will work so long as c isn't null when you return. If it is, then your agent is set aside, and dumbbot is used instead.
How to pick a country:
You'll need to determine your own way to decide which country is the choicest among the unchosen ones on the board. Generally, you'll want to pick a country in the continent that has the fewest amount of countries, and the fewest borders (think Australia). The Lux Agent SDK supplies several helper routines for this purpose:
BoardHelper.getContinentSize(int cont, Country countries)
BoardHelper.getContinentBorders(int cont, Country countries)
and, if your agent extends SmartAgentBase, then you also have
Ravitar uses a complicated formula to determine which is her goal continent in the early part of the game, and so long as there is an open country in there, or on its boarder, she will go into that continent. Don't ask to see the formula, because in its current incarnation, it is, frankly, crap.
This is the second half of the Random/Random question, and it depends on the 'Initial Armies' dropdown list selection. If this is set to 'placed' on the host computer, then your agent will be handed armies several times to place. In the normal risk board, your agent will have its placeInitialArmies() method called four times, with armies set to 4, 4, 4, and 1.
void placeInitialArmies(int armies) // called by the engine
// decide where to place
Deciding where to place the armies is simply a question of deciding which continent you think you can take, and still have enough strength left over to defend the borders against the barbarian (read: human) hordes.
This will be a question of how many armies you have in the continent (or nearby), and how many non-friendly armies are in the continent, and how many countries are in the continent, and how many border countries there are, and, and, and.
Once you've decided, place your armies using the board's .placeArmies (int number, int ccode ) method until you have used up the armies you've been handed. placeArmies(...) can be called n times, such that 1 <= n <= armiesremaining, depending on your needs. You could place singleton armies across n countries, or n armies on a singleton country, or some on one and some on another. It is entirely up to your code.
See the Deployment phase for further ideas.
Mostly, the cards phase is simply return, because the logic that implements the engine will force you to cash a set (ie, it will cash a set for you) if you return from the cardsPhase() call with five or more cards in your hand. When starting out, this is the easiest way to handle it. Ravitar decides if she wants to cash a set early (less than five cards) depending if she is sniping another player or trying to take a continent. Otherwise, she simply holds them until forced to cash.
To help you decide, there are methods in SmartAgentBase that do this for you:
void placeArmiesToTakeCont( int number, int ccode )
void placeArmiesOnClusterBorder( int number, int ccode )
Alternately, you can use whatever method you want. Shaft, for example, finds a single country, memorizes it, and simply dumps its deployment onto that country every turn. This is a surprisingly easy way to win against people who haven't played before. Communist drops each army onto whichever country it owns that is the weakest.
The game calls your bot's attackPhase() function next. In this function you can call board.attack() to try to take over whatever countries you want. Here is where you can take continents, kill off players, and all that fun stuff. You'll probably want to write functions that take care of each kind of action. Again, BoardHelper has lots of functions that will help you make decisions about what to do. Some of the most helpful BoardHelper functions are pathfinding functions like
These can help you plan your attacks.
At the end of your bot's turn, the game calls the fortifyPhase() function. Here you call board.fortifyArmies() to move your armies around. One thing you'll want to do is move idle armies up to the front lines. To find the route to fortify an army along toward the border, you can use