kreversigame.h 5.27 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 38
    ~KReversiGame();
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
     *  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 the board so the callers can examine its current state
60 61
     */
    const KReversiBoard& board() const;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
62 63 64
    /**
     *  @return a color of the current player
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
65
    ChipColor currentPlayer() const { return m_curPlayer; }
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
66
    
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
67 68 69
    // 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
70 71 72
    /**
     *  @return score (number of chips) of the player
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
73 74 75
    int playerScore( ChipColor player ) const;
    // NOTE: this is just a wrapper around KReversiBoard::playerScore
    ChipColor chipColorAt( int row, int col ) const;
76
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
77
     *  This will make the player move at row, col.
78 79 80 81 82 83 84 85
     *  If that is possible of course
     */
    void makePlayerMove(int row, int col);
    /**
     *  This function will make computer decide where he 
     *  wants to put his chip... and he'll put it there!
     */
    void makeComputerMove();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
86 87 88 89
    /**
     *  Undoes the last player-computer move pair
     */
    void undo();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
90 91 92 93
    /**
     *  Returns a hint to current player
     */
    KReversiMove getHint() const;
94 95 96
    /**
     *  Returns true, if it's computer's turn now
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
97 98 99 100 101 102
    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
103
    MoveList changedChips() const { return m_changedChips; }
104 105
signals:
    void boardChanged();
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
106
    void moveFinished();
107
private:
108
    enum Direction { Up, Down, Right, Left, UpLeft, UpRight, DownLeft, DownRight };
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    /**
     * 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;
124 125 126 127 128
    /**
     *  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
129 130 131
    /**
     *  Board itself
     */
132
    KReversiBoard *m_board;
133 134 135 136 137
    /**
     *  Color of the current player
     */
    ChipColor m_curPlayer;
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
138 139 140 141
     *  The color of the human played chips
     */
    ChipColor m_playerColor;
    /**
142 143 144
     *  The color of the computer played chips
     */
    ChipColor m_computerColor;
145 146 147 148
    /**
     *  Our AI
     */
    Engine *m_engine;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
149 150 151 152 153 154 155 156 157 158
     // 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
159
    MoveList m_changedChips;
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
160
    /**
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
161 162 163 164
     *  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
165
     */
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
166
    QStack<MoveList> m_undoStack;
167 168
};
#endif