#ifndef CLASSICABALONEAI_H
#define CLASSICABALONEAI_H
/**
* This abstract class defines the interface to the artificial
* intelligence. The AI works on a hex grid, which is addressed
* using x/y coordinates. However, to transform a rectangular grid
* into a hex grid, every second column is shifted half a cell down
* against it's neighbouring columns. The following figure shows how
* addessing the hex grid works (each cell contains it's coordinates):
\verbatim
+---+ +---+ +---+
/ \ / \ / \
+ 0,0 +---+ 2,0 +---+ 4,0 +
\ / \ / \ /
+---+ 1,0 +---+ 3,0 +---+
/ \ / \ / \
+ 0,1 +---+ 2,1 +---+ 4,1 +
\ / \ / \ /
+---+ 1,1 +---+ 3,1 +---+
/ \ / \ / \
+ 0,2 +---+ 2,2 +---+ 4,2 +
\ / \ / \ /
+---+ 1,2 +---+ 3,2 +---+
/ \ / \ / \
+ 0,3 +---+ 2,3 +---+ 4,3 +
\ / \ / \ /
+---+ 1,3 +---+ 3,3 +---+
/ \ / \ / \
+ +---+ +---+ +
\endverbatim
* Note: The figure assumes that, for a two player game, players start
* on the left and the right side of the board.
*
* This grid is called the operation area. The operation area has a
* certain extent, which is specified upon construction of the AI object.
* In this area, the Abalone board is defined. Each cell can be part
* of the board or void. Accessible cells mark the Abalone board, void cells
* the surrounding area. Usually, the Abalone board is a hexagon, with five
* cells per edge, however, the class should be able to operate with any board
* shape (advanced Abalone rules for instance allow to 'break' the board, that
* is, to break an accessible cell, making it a void cell).
* All cells surrounding the Abalone board are marked as void. Therefore, the
* operation area will look something like this (void
* cells are marked with 'x' - only the upper right corner of the board is
* shown here):
\verbatim
+---+ +---+ +---+
/xxxxx\ /xxxxx\ /xxxxx\
+xxxxxxx+---+xxxxxxx+---+xxxxxxx+..
\xxxxx/xxxxx\xxxxx/xxxxx\xxxxx/xx
+---+xxxxxxx+---+xxxxxxx+---+xx
/xxxxx\xxxxx/xxxxx\xxxxx/xxxxx\xx
+xxxxxxx+---+xxxxxxx+---+xxxxxxx+..
\xxxxx/xxxxx\xxxxx/xxxxx\xxxxx/
+---+xxxxxxx+---+xxxxxxx+---+
/xxxxx\xxxxx/xxxxx\xxxxx/ \
+xxxxxxx+---+xxxxxxx+---+ 4,2 +..
\xxxxx/xxxxx\xxxxx/ \ /
+---+xxxxxxx+---+ 3,2 +---+
/xxxxx\xxxxx/ \ / \
+xxxxxxx+---+ 2,3 +---+ 4,3 +..
\xxxxx/ \ / \ /
+---+ 1,3 +---+ 3,3 +---+
/xxxxx\ / \ / \
+xxxxxxx+---+ 2,4 +---+ 4,4 +..
\xxxxx/ \ / \ /
+---+ 1,4 +---+ 3,4 +---+
/xxxxx\ / \ / \
+xxxxxxx+---+ 2,5 +---+ 4,5 +..
\xxxxx/ \ / \ /
+---+ 1,5 +---+ 3,5 +---+
/xxxxx\ / \ / \
+xxxxxxx+---+ +---+ +..
: : : : : :
\endverbatim
*
* A class implementing ClassicAbaloneAI must implement the following behaviour:
* When the instance is constructed, the operation area's extent is defined.
* Initially the operation area consists of only void cells. After construction,
* the board is created using the setCellAccessible() method. The
* the number of players will be set using setNumPlayers(); the AI's player ID
* will be assigned to it by setPlayerID(). The pieces will be placed on the
* board using the setPiece() method to create the initial game state.
*
* After all the initialization is done, the game begins. A game is for a
* ClassicAbaloneAI a sequence of alternating movePerformed() and calculateMove()
* calls, where in the former the AI is informed of other player's moves, where
* in the latter the AI calculates it's own moves. Data is exchanged using the
* Move struct. movePerformed may be called more than once during a round, depending
* on the number of players.
*
* The AI does not need to determin whether the game has been won or lost yet,
* or not, this is done by the surrounding environment which is observing the
* game.
*
* The reset() method resets the AI to it's initial state after construction
* (the operation area will be cleared - that means no pieces are on the area, and
* every cell is a void cell).
* A playerID is an integer number that defines a player participating in an
* Abalone game uniquely. All player numbers in a game are assigned consecutively,
* therefore, in a three player Abalone game, the ID's 0, 1, and 2 exist. In a two
* player game, only the IDs 0 and 1 will be used. To allow multiple AIs to play
* together within one game, each AI gets it's own player ID.
* @see ClassicAbaloneAI::Move
* @author Uwe Pachler, 2001
*/
class ClassicAbaloneAI
{
private:
int playerID;
int numPlayers;
public:
/**
* This class defines a single Abalone move. For each move, there exits
* central ball from with the move starts.
* For each move in Abalone, there exists the an originating piece.
* An ordinary (non-escape) move can be represented as an arrow, like this:
\verbatim
: : : : : :
+---+ +---+ +---+
/ \ / \ / \
..+ 3,3 +---+ 5,3 +---+ 7,3 +..
\ / \ / \ /
+---+ 4,3 +---+ 6,3 +---+
/ \ / \ / \
..+ 3,4 +---+ 5,4 +---+ 7,4 +..
\ / ooo \ / \ /
+---+ oo+oo +---+ 6,4 +---+
/ \ o|o / \ / \
..+ 3,5 +-|-+ 5,5 +---+ 7,5 +..
\ / o|o \ / \ /
+---+ oo+oo +---+ 6,5 +---+
/ \ o|o / \ / \
..+ 3,6 +-|-+ 5,6 +---+ 7,6 +..
\ / | \ / \ /
+---+ V +---+ 6,6 +---+
/ \ / \ / \
..+ +---+ +---+ +..
: : : : : :
\endverbatim
* In this case the two pieces on 4,4 and 4,5 are moved one cell down.
* The piece on 4,4 is called the originating piece, since it marks the
* origin of the move. The direction of the move is DOWN, and the number
* of pieces involved is two.
* If the two pieces moved up one cell, the originating piece would be
* on cell 4,5, and the direction would be (you guessed it!) UP, like this:
\verbatim
: : : : : :
+---+ +---+ +---+
/ \ / \ / \
..+ 3,3 +---+ 5,3 +---+ 7,3 +..
\ / \ / \ /
+---+ A +---+ 6,3 +---+
/ \ | / \ / \
..+ 3,4 +-|-+ 5,4 +---+ 7,4 +..
\ / o|o \ / \ /
+---+ oo+oo +---+ 6,4 +---+
/ \ o|o / \ / \
..+ 3,5 +-|-+ 5,5 +---+ 7,5 +..
\ / o|o \ / \ /
+---+ oo+oo +---+ 6,5 +---+
/ \ ooo / \ / \
..+ 3,6 +---+ 5,6 +---+ 7,6 +..
\ / \ / \ /
+---+ 4,6 +---+ 6,6 +---+
/ \ / \ / \
..+ +---+ +---+ +..
: : : : : :
\endverbatim
* However, all this only describes ordinary moves. In the case of
* escape moves, It gets a bit more complicated. In the moves before,
* we assumed that the train of pieces moved within a move extends
* along the movement direction. We only had to specify the origin,
* direction, direction and number of pieces involved to define a
* move.
* Since in escape moves, one can move a train sideways, the direction
* along which the train itself extends must also be specified. Consider
* this move:
\verbatim
: : : : : :
+---+ +---+ +---+
/ \ / \ / \
..+ 3,3 +---+ 5,3 +---+ 7,3 +..
\ / \ / \ /
+---+ 4,3 +---+ A +---+
/ \ / \ | / \
..+ 3,4 +---+ A +-|-+ 7,4 +..
\ / \ | / o|o \ /
+---+ A +-|-+ oo+oo +---+
/ \ | / o|o \ ooo / \
..+ 3,5 +-|-+ oo+oo +---+ 7,5 +..
\ / o|o \ ooo / \ /
+---+ oo+oo +---+ 6,5 +---+
/ \ ooo / \ / \
..+ 3,6 +---+ 5,6 +---+ 7,6 +..
\ / \ / \ /
+---+ 4,6 +---+ 6,6 +---+
/ \ / \ / \
..+ +---+ +---+ +..
: : : : : :
\endverbatim
* In this escape move, the move direction is UP. The origin piece is
* at 4,5, and the number of pieces is 3. The direction of the train
* itself is UP_RIGHT, since it extends from the origin piece at 4,5 to
* the upper right.
* There is another (equivalent) representation of this move, with
* the origin piece at 6,4 and a train direction of DOWN_LEFT. The
* number of pieces and the move direction remain the same (3 and
* UP).
* For normal moves, the train direction is the same as the move
* direction.
*/
struct Move
{
/**
* This type defines the six directions possible in Abalone's hex
* grid. The member names speak for themselves.
\verbatim
UP
LEFT_UP \ | /RIGHT_UP
\ | /
-+-
/ | \
LEFT_DOWN / | \RIGHT_DOWN
DOWN
\endverbatim
*/
enum Direction
{
/**
* upwards
*/
UP,
/**
* downwards
*/
DOWN,
/**
* towards the upper left
*/
LEFT_UP,
/**
* towards the lower left
*/
LEFT_DOWN,
/**
* towards the upper right
*/
RIGHT_UP,
/**
* towards the lower right
*/
RIGHT_DOWN
};
/**
* The direction where the train is moved.
*/
Direction moveDirection;
/**
* The direction along which the train of pieces extends.
*/
Direction trainDirection;
/**
* The origin piece's x coordinate
*/
int originX;
/**
* The origin piece's y coordinate
*/
int originY;
/**
* The number of pieces involved in this move.
*/
int numBalls;
};
protected:
/**
* Initializes a new ClassicAbaloneAI instance.
*/
ClassicAbaloneAI();
/**
* @returns the actual number of players in the game.
*/
inline int getNumPlayers()
{ return numPlayers; }
public:
/**
* Destroys the ClassicAbaloneAI instance
*/
virtual ~ClassicAbaloneAI();
/**
* sets the player's ID number (typically ranging from 0 to 2 for
* classic abalone, however, don't rely on this upper limit for
* player IDs.
* @param playerID the player ID number that is assigned to
* this instance.
*/
inline void setPlayerID(int playerID)
{ this->playerID = playerID; }
/**
* @returns the playerID assigned to this ClassicAbaloneAI
*/
inline const int getPlayerID() const
{ return playerID; }
/**
* Sets the actual number of players in the game. playerID's will
* range from 0 to getNumPlayers()-1, consecutively.
*
* @param numPlayers
*/
inline void setNumPlayers(int numPlayers)
{ this->numPlayers = numPlayers; }
/**
* This method makes a cell accessible.
* @param x the cell's x coordinate
* @param y the cell's y coordinate
* @param accessible if true, the cell is set to be accessible
* (or part of the board), if false the cell is set to be void
*/
virtual void setCellAcessible(int x, int y, bool accessible) = 0;
/**
* This method is used to initilize the board. It sets a new piece onto
* a specific cell. The cell itself must be accessible, otherwise
* results will be undefined.
*/
virtual void setPiece(int playerID, int x, int y) = 0;
/**
* Informs the AI about a certain player's move. This methd is clalled
* once for every other player participating in the game.
* @param playerID The ID number of the player
* @param move The move that was performed by the player
*/
virtual void movePerformed(int playerID, const Move& move) = 0;
/**
* This method is the core of the AI. It calculates the AI's next game
* move and returns it.
* @see ClassicAbaloneAI::Move
*/
virtual const Move calculateNextMove() = 0;
/**
* Resets the operation area. The area contains no pieces, and
* every cell is a void cell.
*/
virtual void reset() = 0;
};
#endif /* CLASSICABALONEAI_H */