kreversigame.h 5.66 KB
Newer Older
1 2 3 4
#ifndef KREVERSI_GAME_H
#define KREVERSI_GAME_H

#include <QObject>
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
5
#include <QStack>
6

Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
7 8 9
#include "commondefs.h"

class KReversiBoard;
10
class Engine;
11 12 13 14 15 16

/**
 *  KReversiGame incapsulates all of the game logic.
 *  It creates KReversiBoard and manages a chips on it.
 *  Whenever the board state changes it emits corresponding signals.
 *  The idea is also to abstract from any graphic representation of the game process
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 *  KReversiGame is supposed to be driven by someone from outside.
 *  I.e. it receives commands and emits events when it's internal state changes
 *  due to this commands dispatching.
 *  The main commands are:
 *  makePlayerMove() and makeComputerMove()
 *  Also, after each turn is made a user of this class should check
 *  that isGameOver() returns false,
 *  and that next player can move 
 *  (by calling isAnyPlayerMovePossible() || isAnyComputerMovePossible()).
 *  If, for example isAnyPlayerMovePossible() returns false, than player needs to skip and 
 *  makeComputerMove() should be called.
 *
 *  See KReversiScene for example of working with KReversiGame
31 32 33
 */
class KReversiGame : public QObject
{
34
    Q_OBJECT
35
public:
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
36
    KReversiGame();
37
    ~KReversiGame();
38 39 40 41 42 43 44 45 46 47 48 49 50 51
    /**
     *  This will make the player move at row, col.
     *  If that is possible of course
     *  If demoMode is true, the computer will decide on what move to take.
     *  row and col values do not matter in that case.
     */
    void makePlayerMove(int row, int col, bool demoMode);
    /**
     *  This function will make computer decide where he 
     *  wants to put his chip... and he'll put it there!
     */
    void makeComputerMove();
    /**
     *  Undoes all the computer moves and one player move
52
     *  @return number of undone moves
53
     */
54
    int undo();
55
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
56 57 58
     *  Sets the strength of game engine (1 to 7)
     */
    void setEngineStrength(uint strength);
59 60 61 62
    /**
     *  Sets the computer skill level. From 1 to 7
     */
    void setComputerSkill(int skill);
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    /**
     *  @return strength of the game engine
     */
    uint strength() const;
    /**
     *  @return whether the game is already over
     */
    bool isGameOver() const;
    /**
     *  @return whether any player move is at all possible
     */
    bool isAnyPlayerMovePossible() const;
    /**
     *  @return whether any computer move is at all possible
     */
    bool isAnyComputerMovePossible() const;
    /**
     *  @return a color of the current player
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
82
    ChipColor currentPlayer() const { return m_curPlayer; }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
83
    
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
84 85 86
    // NOTE: this is just a wrapper around KReversiBoard::playerScore
    // Maybe consider merging KReversiBoard into this class?
    // same applies to chipColorAt
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
87 88 89
    /**
     *  @return score (number of chips) of the player
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
90 91 92
    int playerScore( ChipColor player ) const;
    // NOTE: this is just a wrapper around KReversiBoard::playerScore
    ChipColor chipColorAt( int row, int col ) const;
93 94 95 96
    /**
     *  @return if undo is possible
     */
    bool canUndo() const { return !m_undoStack.isEmpty(); }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
97 98 99 100
    /**
     *  Returns a hint to current player
     */
    KReversiMove getHint() const;
101 102 103 104
    /**
     *  @return last move made
     */
    KReversiMove getLastMove() const;
105 106 107
    /**
     *  Returns true, if it's computer's turn now
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
108 109 110 111 112 113
    bool isComputersTurn() const { return m_curPlayer == m_computerColor; }
    /**
     *  @return a list of chips which were changed during last move.
     *  First of them will be the move itself, and the rest - chips which
     *  were turned by that move
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
114
    MoveList changedChips() const { return m_changedChips; }
115 116 117 118
    /**
     *  @return a list of possible moves for current player
     */
    MoveList possibleMoves() const;
119 120
signals:
    void boardChanged();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
121
    void moveFinished();
122
private:
123
    enum Direction { Up, Down, Right, Left, UpLeft, UpRight, DownLeft, DownRight };
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    /**
     * This function will tell you if the move is possible.
     * That's why it was given such a name ;)
     */
    bool isMovePossible( const KReversiMove& move ) const; 
    /**
     *  Searches for "chunk" in direction dir for move.
     *  As my English-skills are somewhat limited, let me introduce 
     *  new terminology ;).
     *  I'll define a "chunk" of chips for color "C" as follows:
     *  (let "O" be the color of the opponent for "C")
     *  CO[O]C <-- this is a chunk
     *  where [O] is one or more opponent's pieces
     */
    bool hasChunk( Direction dir, const KReversiMove& move) const;
139 140 141 142 143
    /**
     *  Performs move, i.e. marks all the chips that player wins with
     *  this move with current player color
     */
    void makeMove( const KReversiMove& move );
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
144 145 146
    /**
     *  Board itself
     */
147
    KReversiBoard *m_board;
148 149 150 151 152
    /**
     *  Color of the current player
     */
    ChipColor m_curPlayer;
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
153 154 155 156
     *  The color of the human played chips
     */
    ChipColor m_playerColor;
    /**
157 158 159
     *  The color of the computer played chips
     */
    ChipColor m_computerColor;
160 161 162 163
    /**
     *  Our AI
     */
    Engine *m_engine;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
164 165 166 167 168 169 170 171 172 173
     // Well I'm not brief at all :). That's because I think that my
     // English is not well shaped sometimes, so I try to describe things
     // so that me and others can understand. Even simple things.
     // Espesially when I think that my description sucks :)
    /**
     *  This list holds chips that were changed/added during last move
     *  First of them will be the chip added to the board by the player
     *  during last move. The rest of them - chips that were turned by that
     *  move.
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
174
    MoveList m_changedChips;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
175
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
176
     *  This is an undo stack.
177 178
     *  It contains a lists of chips changed with each turn.
     *  @see m_changedChips
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
179
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
180
    QStack<MoveList> m_undoStack;
181 182
};
#endif