1/*******************************************************************
2 *
3 * Copyright 2006 Dmitry Suzdalev <dimsuz@gmail.com>
4 * Copyright 2013 Denis Kuplaykov <dener.kup@gmail.com>
5 *
6 * This file is part of the KDE project "KReversi"
7 *
8 * KReversi is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * KReversi is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with KReversi; see the file COPYING. If not, write to
20 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 ********************************************************************/
24#ifndef KREVERSI_GAME_H
25#define KREVERSI_GAME_H
26
27#include <QObject>
28#include <QStack>
29#include <QTimer>
30
31#include <Engine.h>
32class Engine;
33#include <commondefs.h>
34#include <kreversiplayer.h>
35class KReversiPlayer;
36
37/**
38 * KReversiGame incapsulates all of the game logic.
39 * Whenever the board state changes it emits corresponding signals.
40 * The idea is also to abstract from any graphic representation of the game
41 * process
42 *
43 * KReversiGame receives signals from KReversiPlayer classes.
44 * I.e. it receives commands and emits events when it's internal state changes
45 * due to this commands dispatching.
46 *
47 * See KReversiView, KReversiPlayer, KReversiHumanPlayer
48 * and KReversiComputerPlayer for example of working with KReversiGame
49 *
50 * @see KReversiView, KReversiPlayer, KReversiHumanPlayer
51 */
52class KReversiGame : public QObject
53{
54 Q_OBJECT
55public:
56 /**
57 * Constructs game with two specified players.
58 */
59 KReversiGame(KReversiPlayer *blackPlayer, KReversiPlayer *whitePlayer);
60 ~KReversiGame();
61 /**
62 * @return if undo is possible
63 */
64 bool canUndo() const;
65 /**
66 * Undoes all the opponent of current player moves and one his move
67 * (so after calling this function it will be still current player turn)
68 * @return number of undone moves
69 */
70 int undo();
71 /**
72 * @return score (number of chips) of the @p player
73 */
74 int playerScore(ChipColor player) const;
75 /**
76 * @return color of the chip at position @p pos
77 */
78 ChipColor chipColorAt(KReversiPos pos) const;
79 /**
80 * @return a hint to current player
81 */
82 KReversiMove getHint() const;
83 /**
84 * @return last move made
85 */
86 KReversiMove getLastMove() const;
87 /**
88 * @return a list of chips which were changed during last move.
89 * First of them will be the move itself, and the rest - chips which
90 * were turned by that move
91 */
92 MoveList changedChips() const {
93 return m_changedChips;
94 }
95 /**
96 * @return a list of possible moves for current player
97 */
98 MoveList possibleMoves() const;
99 /**
100 * @return whether the game is already over
101 */
102 bool isGameOver() const;
103 /**
104 * @return whether any player move is at all possible
105 */
106 bool isAnyPlayerMovePossible(ChipColor player) const;
107 /**
108 * @return a color of the current player
109 */
110 ChipColor currentPlayer() const {
111 return m_curPlayer;
112 }
113 /**
114 * Sets animation times from players to @p delay milliseconds
115 */
116 void setDelay(int delay);
117 /**
118 * Get wait time for given cell before animating. Used for sequental turning of chips
119 */
120 int getPreAnimationDelay(KReversiPos pos) const;
121 /**
122 * @return History of moves as MoveList
123 */
124 MoveList getHistory() const;
125
126 /**
127 * @return Is hint allowed for current player
128 */
129 bool isHintAllowed() const;
130private slots:
131 /**
132 * Starts next player's turn.
133 */
134 void startNextTurn();
135 /**
136 * Slot used to handle moves from black player
137 * @param move Move of black player
138 */
139 void blackPlayerMove(KReversiMove move);
140 /**
141 * Slot used to handle moves from white player
142 * @param move Move of white player
143 */
144 void whitePlayerMove(KReversiMove move);
145 /**
146 * Slot to handle end of animations with m_delayTimer
147 */
148 void onDelayTimer();
149 /**
150 * Slot to handle ready-status of black player
151 */
152 void blackReady();
153 /**
154 * Slot to handle ready-status of white player
155 */
156 void whiteReady();
157
158signals:
159 void gameOver();
160 void boardChanged();
161 void moveFinished();
162 void whitePlayerCantMove();
163 void blackPlayerCantMove();
164 void whitePlayerTurn();
165 void blackPlayerTurn();
166private:
167 // predefined direction arrays for easy implementation
168 static const int DIRECTIONS_COUNT = 8;
169 static const int DX[];
170 static const int DY[];
171 /**
172 * Used to make player think about his move again after unpossible move
173 */
174 void kickCurrentPlayer();
175 /**
176 * This will make the player @p move
177 * If that is possible, of course
178 */
179 void makeMove(const KReversiMove &move);
180 /**
181 * This function will tell you if the move is possible.
182 */
183 bool isMovePossible(const KReversiMove &move) const;
184 /**
185 * Searches for "chunk" in direction @p dirNum for @p move.
186 * As my English-skills are somewhat limited, let me introduce
187 * new terminology ;).
188 * I'll define a "chunk" of chips for color "C" as follows:
189 * (let "O" be the color of the opponent for color "C")
190 * CO[O]C <-- this is a chunk
191 * where [O] is one or more opponent's pieces
192 */
193 bool hasChunk(int dirNum, const KReversiMove &move) const;
194 /**
195 * Performs @p move, i.e. marks all the chips that player wins with
196 * this move with current player color
197 */
198 void turnChips(const KReversiMove &move);
199 /**
200 * Sets the type of chip according to @p move
201 */
202 void setChipColor(const KReversiMove &move);
203 /**
204 * Delay time
205 */
206 int m_delay;
207 /**
208 * Status flags used to know when both players are ready
209 */
210 bool m_isReady[2];
211 /**
212 * Last player who has made a move. Cannot be NoColor after the first move
213 */
214 ChipColor m_lastPlayer;
215 /**
216 * The board itself
217 */
218 ChipColor m_cells[8][8];
219 /**
220 * Score of each player
221 */
222 int m_score[2];
223 /**
224 * AI to give hints
225 */
226 Engine *m_engine;
227 /**
228 * Color of the current player.
229 * @c NoColor if it is interchange for animations
230 */
231 ChipColor m_curPlayer;
232 /**
233 * This list holds chips that were changed/added during last move
234 * First of them will be the chip added to the board by the player
235 * during last move. The rest of them - chips that were turned by that
236 * move.
237 */
238 MoveList m_changedChips;
239 /**
240 * This is an undo stack.
241 * It contains a lists of chips changed with each turn.
242 * @see m_changedChips
243 */
244 QStack<MoveList> m_undoStack;
245 /**
246 * Used to handle end of player's animations or other stuff
247 */
248 QTimer m_delayTimer;
249
250 /**
251 * Actual players, who play the game
252 */
253 KReversiPlayer *m_player[2];
254};
255#endif
256