2 Mancala - A Historical Board Game
3 Copyright (C) 2009-2010 A.H.M.Mahfuzur Rahman 65mahfuz90@gmail.com
4 Copyright (c) 2010 Reto Zingg g.d0b3rm4n@gmail.com
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of
9 the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "MoveGenerator.h"
23 // #include <kdebug.h>
26 #include "GameController.h"
29 MoveGenerator::MoveGenerator(int gameDifficulty,GameInfo *gameInfo,GameController *gameController){
31 m_gameDifficulty = gameDifficulty;
32 m_gameInfo = gameInfo;
33 m_gameController = gameController;
36 //we need to use m_depthList[m_gameDifficulty];
43 int MoveGenerator::bestMove(QList<int> currentState,bool humanTurn){
45 // As we are calculating move only for computer player, humanTurn is currently
47 int cupIndex = -1,utility; //The valid move we want to return
50 //rootNode is a maximizer
51 Node* rootNode = new Node(m_gameInfo);
52 copyBoard(rootNode,currentState);
53 rootNode->setTurn(false);
54 showBoardState(rootNode);
55 QList<Node*> m_possibleMoves;
58 simulateMoves(rootNode,m_possibleMoves);
59 //kDebug() << "Move simulation ended";
61 while(allEvaluations.count())
62 allEvaluations.pop_back();
63 while(allCupIndexes.count())
64 allCupIndexes.pop_back();
67 while(m_possibleMoves.count()){
69 node = m_possibleMoves.front();
71 //we have a bonus turn, so we maximize again
72 if(rootNode->turn() == node->turn()){
73 // kDebug() << "Calling maxValue";
74 allCupIndexes.append(node->move());
75 utility = maxValue(node,-1000,1000);
76 allEvaluations.append(utility);
79 cupIndex = node->move();
82 //we are making turn, so it is a minimizer
84 // kDebug() << "Calling minValue";
85 allCupIndexes.append(node->move());
86 utility = minValue(node,-1000,1000);
87 allEvaluations.append(utility);
90 cupIndex = node->move();
94 m_possibleMoves.pop_front();
97 //kDebug() << "Evaluations: " << allEvaluations;
98 // kDebug() << "Index: " << cupIndex << " value " << value ;
102 int MoveGenerator::maxValue(Node *parentNode,int alpha,int beta){
104 if(isGameOver( parentNode->getBoard() ) || parentNode->depth() == m_depthList[m_gameDifficulty])
105 return parentNode->evaluationFunction(m_gameController);
107 int value = -1000,utility;
108 //kDebug() << alpha << beta << parentNode->turn();
110 QList<Node*> m_possibleMoves;
112 simulateMoves(parentNode,m_possibleMoves);
114 while(m_possibleMoves.count()){
116 node = m_possibleMoves.front();
117 // kDebug() << "cost: " << node->evaluationFunction(m_gameController);
119 //we have a bonus turn, so we maximize again
120 if(parentNode->turn() == node->turn()){
121 // kDebug() << "Calling maxValue";
122 allCupIndexes.append(node->move());
123 utility = maxValue(node,alpha,beta);
124 allEvaluations.append(utility);
129 //we are making turn, so it is a minimizer
131 // kDebug() << "Calling minValue";
132 allCupIndexes.append(node->move());
133 utility = minValue(node,alpha,beta);
134 allEvaluations.append(utility);
146 m_possibleMoves.pop_front();
152 int MoveGenerator::minValue(Node *parentNode,int alpha,int beta){
154 if(isGameOver(parentNode->getBoard()) || parentNode->depth() == m_depthList[m_gameDifficulty])
155 return parentNode->evaluationFunction(m_gameController);
157 int value = 1000,utility;
158 //kDebug() << alpha << beta << parentNode->turn();
160 QList<Node*> m_possibleMoves;
162 simulateMoves(parentNode,m_possibleMoves);
165 while(m_possibleMoves.count()){
167 node = m_possibleMoves.front();
168 // kDebug() << "cost: " << node->evaluationFunction(m_gameController);
170 //we have a bonus turn, so we minimize again
171 if(parentNode->turn() == node->turn()){
172 // kDebug() << "Calling minValue";
173 allCupIndexes.append(node->move());
174 utility = minValue(node,alpha,beta);
175 allEvaluations.append(utility);
180 //we are making turn, so it is a maximizer
182 // kDebug() << "Calling maxValue";
183 utility = maxValue(node,alpha,beta);
184 allCupIndexes.append(node->move());
185 allEvaluations.append(utility);
197 m_possibleMoves.pop_front();
204 void MoveGenerator::simulateMoves(Node* currentNode,QList<Node*> &nodes){
208 QList<int> parentBoard = currentNode->getBoard();
209 // QPair<bool,QList<int> > infoNode;
212 if(currentNode->turn() == false){
214 for(int i = 0 ; i < m_gameInfo->numCupsPerRow() ; i++){
215 //If there is enough stone to sow
216 if( parentBoard[i] > m_gameInfo->leftToCup()){
219 Node* tempNode = new Node(m_gameInfo);
220 QPair<bool,QList<int> > infoNode;
222 infoNode = m_gameController->logicalMoveController(parentBoard,i,currentNode->turn());
224 //setting node information
225 copyBoard(tempNode,infoNode.second);
226 tempNode->setTurn(infoNode.first);
227 tempNode->setDepth( currentNode->depth() + 1 );
228 tempNode->setMove(i);
230 //kDebug() << "Node Info:";
231 //kDebug() << tempNode->getBoard();
232 //kDebug() << "Turn: " << tempNode->turn() << " Move: " << tempNode->move();
234 nodes.append(tempNode);
243 for(int i = m_gameInfo->numCupsPerRow() ; i < 2*m_gameInfo->numCupsPerRow() ; i++){
244 //If there is enough stone to sow
245 if( parentBoard[i] > m_gameInfo->leftToCup()){
248 Node* tempNode = new Node(m_gameInfo);
249 QPair<bool,QList<int> > infoNode;
251 infoNode = m_gameController->logicalMoveController(parentBoard,i,currentNode->turn());
253 //setting node information
254 copyBoard(tempNode,infoNode.second);
255 tempNode->setTurn(infoNode.first);
256 tempNode->setDepth( currentNode->depth() + 1 );
257 tempNode->setMove(i);
259 //kDebug() << "Node Info:";
260 //kDebug() << tempNode->getBoard();
261 //kDebug() << "Turn: " << tempNode->turn() << " Move: " << tempNode->move();
263 nodes.append(tempNode);
269 //if(count1 > 0) kDebug() << "Count1: " << count1;
270 //if(count2 > 0) kDebug() << "Count2: " << count2;
273 bool MoveGenerator::isGameOver(QList<int> board){
275 for(int i = 0 ; i < 2*m_gameInfo->numCupsPerRow() ; i++)
276 if( board[i] > m_gameInfo->leftToCup() )
278 //kDebug() << "Game Is Over ...";
282 void MoveGenerator::copyBoard(Node* to,Node* from){
283 QList<int> fromBoard,toBoard;
284 fromBoard = from->getBoard();
286 for(int i = 0 ; i < 2 * m_gameInfo->numCupsPerRow() + 2 ; i++ )
287 toBoard.append(fromBoard[i]);
288 to->setBoard(toBoard);
291 void MoveGenerator::copyBoard(Node* to,QList<int>board){
292 QList<int> tempBoard;
293 for(int i = 0 ; i < 2 * m_gameInfo->numCupsPerRow() + 2 ; i++ ){
294 //kDebug() << "Index: " << i << " content: " << board[i];
295 tempBoard.append(board[i]);
297 to->setBoard(tempBoard);
300 void MoveGenerator::showBoardState(Node *node){
301 QList<int> board = node->getBoard();
302 // kDebug() << board;
305 //--------------------------------- Node Functions Below ------------------------------
307 Node::Node(GameInfo* info){
314 for(int i = 0 ; i < 2 * m_gameInfo->numCupsPerRow() + 2 ; i++)
315 m_boardState.append(0);
318 int Node::evaluationFunction(GameController* controller){
321 // kDebug() << "In kalah of Computer: "
322 // << m_boardState[1-controller->humanKalahIndex() + 2 * m_gameInfo->numCupsPerRow()]
323 // << "depth: "<< m_depth;
324 cost = m_boardState[1-controller->humanKalahIndex() + 2 * m_gameInfo->numCupsPerRow()]
325 - m_boardState[controller->humanKalahIndex() + 2 * m_gameInfo->numCupsPerRow()];
327 //kDebug() << "returning: " << cost;
331 void Node::setBoard(QList<int> board){
333 for(int i = 0 ; i < 2 * m_gameInfo->numCupsPerRow() + 2 ; i++)
334 m_boardState[i] = board[i];