kreversigame.h 5.49 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 52 53
    /**
     *  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
     */
    void undo();
54
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
     *  Sets the strength of game engine (1 to 7)
     */
    void setEngineStrength(uint strength);
    /**
     *  @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
77
    ChipColor currentPlayer() const { return m_curPlayer; }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
78
    
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
79 80 81
    // 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
82 83 84
    /**
     *  @return score (number of chips) of the player
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
85 86 87
    int playerScore( ChipColor player ) const;
    // NOTE: this is just a wrapper around KReversiBoard::playerScore
    ChipColor chipColorAt( int row, int col ) const;
88 89 90 91
    /**
     *  @return if undo is possible
     */
    bool canUndo() const { return !m_undoStack.isEmpty(); }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
92 93 94 95
    /**
     *  Returns a hint to current player
     */
    KReversiMove getHint() const;
96 97 98 99
    /**
     *  @return last move made
     */
    KReversiMove getLastMove() const;
100 101 102
    /**
     *  Returns true, if it's computer's turn now
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
103 104 105 106 107 108
    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
109
    MoveList changedChips() const { return m_changedChips; }
110 111
signals:
    void boardChanged();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
112
    void moveFinished();
113
private:
114
    enum Direction { Up, Down, Right, Left, UpLeft, UpRight, DownLeft, DownRight };
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    /**
     * 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;
130 131 132 133 134
    /**
     *  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
135 136 137
    /**
     *  Board itself
     */
138
    KReversiBoard *m_board;
139 140 141 142 143
    /**
     *  Color of the current player
     */
    ChipColor m_curPlayer;
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
144 145 146 147
     *  The color of the human played chips
     */
    ChipColor m_playerColor;
    /**
148 149 150
     *  The color of the computer played chips
     */
    ChipColor m_computerColor;
151 152 153 154
    /**
     *  Our AI
     */
    Engine *m_engine;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
155 156 157 158 159 160 161 162 163 164
     // 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
165
    MoveList m_changedChips;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
166
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
167 168 169 170
     *  This is an undo stack.
     *  Note that on each undo action a <b>pair</b> of move lists
     *  will be popped from top. I.e. player turn and computer turn will
     *  be undone in one go.
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
171
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
172
    QStack<MoveList> m_undoStack;
173 174
};
#endif