#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 */