File indexing completed on 2024-11-24 03:43:16

0001 /*******************************************************************
0002  *
0003  * Copyright 2007  Aron Boström <c02ab@efd.lth.se>
0004  *
0005  * Bovo is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation; either version 2, or (at your option)
0008  * any later version.
0009  *
0010  * Bovo is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with Bovo; see the file COPYING.  If not, write to
0017  * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  *
0020  ********************************************************************/
0021 
0022 /**
0023  * @file file declaring the class AiBoard, which in fact is the AI
0024  */
0025 
0026 #ifndef BOVO_AIBOARD_H
0027 #define BOVO_AIBOARD_H
0028 
0029 #include <KGameDifficulty>
0030 
0031 #include "common.h"
0032 
0033 using namespace bovo;
0034 
0035 /** namespace for game engine */
0036 namespace bovo
0037 {
0038 class Coord;
0039 class Dimension;
0040 class Move;
0041 } /* namespace bovo */
0042 
0043 /** namespace for AI stuff */
0044 namespace ai
0045 {
0046 
0047 class AiSquare;
0048 
0049 /**
0050  * An AI player
0051  *
0052  * This class might be somewhat missnamed. It doesn't just keep track of a
0053  * playing board on the behalf og the AI. It is the entire AI implementation.
0054  * it implements two algorithms to calculate best moves and it selects which
0055  * move to play. It also can tell if a move is a winning move, but it doesn't
0056  * track a history yet (but maybe it should?).
0057  *
0058  * It uses the standard stuff in common.h way to little.
0059  *
0060  * It is supposed to be slaughtered and split up in two, easing the
0061  * implementation of AdaptingAi (the great feature to come! =P )
0062  *
0063  * Perhaps we want to use Qt4 rather than STL in most of these cases. When we
0064  * implement AdaptingAi we have to depend on Qt4 and/or ThreadWeaver anyways.
0065  *
0066  * @code
0067  * Dimension dimension(width, height);
0068  * AiBoard ai(dimension, Easy);
0069  * Coord move = getMoveFromPlayerEitherByNetworkOrGui();
0070  * Coord aiMove = ai.move(move);
0071  * doSomethingWithAiMoveLikeDisplayingItInTheGui(aiMove);
0072  * @endcode
0073  */
0074 class AiBoard
0075 {
0076 public:
0077     /**
0078      * @brief Constructs an AiBoard with width, height and Skill
0079      * @description Constructs a Board object with a specified width, height and
0080      * skill
0081      * @param width the width
0082      * @param height the height
0083      * @param skill the skill (difficulty level) the AI player will be playing with
0084      */
0085     AiBoard(const usi width, const usi height, KGameDifficultyLevel::StandardLevel skill = KGameDifficultyLevel::Medium, Player player = O);
0086 
0087     /**
0088      * @brief Constructs an AiBoard with width, height and Skill
0089      * @description Constructs a Board object with a specified width and height
0090      * specified by a Dimension and a skill
0091      * @param width the width
0092      * @param height the height
0093      * @param skill the skill (difficulty level) the AI player will be playing with
0094      */
0095     explicit AiBoard(const Dimension &dimension, KGameDifficultyLevel::StandardLevel skill = KGameDifficultyLevel::Medium, Player player = O);
0096 
0097     /**
0098      * @brief destructs this AiBoard
0099      * @description destructs this AiBoard object
0100      */
0101     ~AiBoard();
0102 
0103     /**
0104      * @brief is a Coord empty or set?
0105      * @description tells whether a given Coord is marked as empty or
0106      * marked by a player
0107      * @throw outOfBounds when coord is not on playing board
0108      * @param coord Coord to check
0109      * @return @c true if coord is empty, @c false otherwise
0110      */
0111     bool empty(const Coord &) const;
0112 
0113     /**
0114      * @brief is a Coord empty or set?
0115      * @description tells whether a given Coord is marked as empty or
0116      * marked by a player
0117      * @throw outOfBounds when coord is not on playing board
0118      * @param x X-part of coordinate to check
0119      * @param y X-part of coordinate to check
0120      * @return @c true if coord is empty, @c false otherwise
0121      */
0122     bool empty(const usi x, const usi y) const;
0123 
0124     /**
0125      * @brief height of AiBoard
0126      * @description tells the number of rows in the playing board
0127      * @return the number of rows
0128      */
0129     usi height() const;
0130 
0131     /**
0132      * @brief get move from AI
0133      * @description get the move the AI wants to play
0134      * @return the move the AI wants to play
0135      */
0136     Coord move();
0137 
0138     /**
0139      * @brief get move from AI
0140      * @description Feed the latest move from the player to the AI and get a
0141      * list of suggested AI moves in return. This should be a QList\<Coord>.
0142      * @param coord the move the player played his latest turn
0143      * @return the moves the AI suggest to play
0144      * @todo Implement!
0145      */
0146     Coord *moves();
0147 
0148     /**
0149      * @brief the player occupying a Coord
0150      * @description tells which players occupies a certain square in the board
0151      * @param coord the square to check
0152      * @return @c X if player 1, @c O if player 2, @c No if empty
0153      * @throw outOfBounds if coord isn't on the playing board
0154      */
0155     Player player(const Coord &) const;
0156 
0157     /**
0158      * @brief the player occupying a Coord
0159      * @description tells which players occupies a certain square in the board
0160      * @param x the X-part of the Coord to check
0161      * @param y the Y-part of the Coord to check
0162      * @return @c X if player 1, @c O if player 2, @c No if empty
0163      * @throw outOfBounds if coord isn't on the playing board
0164      */
0165     Player player(const usi x, const usi y) const;
0166 
0167     /**
0168      * @brief set the player of a Coord
0169      * @description sets which players should occupy a certain square in the
0170      * playing board. Returns whether the game ends with this move (i.e. it
0171      * was the winning move).
0172      * @param move the Move to place
0173      * @return @c true if this move resulted in a Game Over,
0174      * @c false otherwise
0175      * @throw busy if coord was already occupied
0176      * @throw gameOver if game was already over
0177      * @throw notValidPlayer if player wasn't X or O
0178      */
0179     bool setPlayer(const Move &move);
0180 
0181     /**
0182      * @brief change Skill
0183      * @description changes the Skill (difficulty level) of the AI player
0184      */
0185     void setSkill(KGameDifficultyLevel::StandardLevel skill);
0186 
0187     /**
0188      * @brief width of Board
0189      * @description tells the number of columns in the playing board
0190      * @return the number of columns
0191      */
0192     usi width() const;
0193 
0194 private:
0195     /* Playing board property. */
0196     AiSquare **m_board;
0197 
0198     /* hasn't game really started? */
0199     bool m_cleanBoard;
0200 
0201     /* Dimension property of playing board. */
0202     Dimension *m_dimension;
0203 
0204     /* is Game Over? property */
0205     bool m_gameover;
0206 
0207     /* AI player property */
0208     Player m_player;
0209 
0210     /* AI Level property. */
0211     KGameDifficultyLevel::StandardLevel m_skill;
0212 
0213     /* Return the best-fitting coordinate according to the specs.
0214      * Use this when all the board has been given points. */
0215     Coord evaluate() const;
0216 
0217     /* returns, adds och sets points on a given square. */
0218     uli points(const Coord &) const;
0219     void addPoints(const Coord &, const uli points);
0220     void setPoints(const Coord &, const uli points);
0221 
0222     /* initialize this class */
0223     void setup();
0224 
0225     /* Do the real calculation of points for a given square.
0226      * Player is the AI player you're optimizing. */
0227     uli value(const Coord &, const usi player) const;
0228 
0229     /* value2 performs a second evaluation in order to make out the tiny
0230      * differences that haven't been spotted yet.
0231      * Only run this when needed. */
0232     uli value2(const Coord &) const;
0233 
0234     /* is this move (coord) a winning move? */
0235     bool win(const Coord &) const;
0236 
0237     /* Marks all neighbour (5 squares in each
0238      * direction) as in need of a recalculation
0239      * of its points. */
0240     void zero(const Coord &);
0241 };
0242 
0243 } /* namespace ai */
0244 
0245 #endif // BOVO_AIBOARD_H