remove old files add new sources
[mancala] / src / MoveGenerator.cpp
diff --git a/src/MoveGenerator.cpp b/src/MoveGenerator.cpp
new file mode 100644 (file)
index 0000000..d24641b
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+Mancala - A Historical Board Game
+Copyright (C) 2009-2010 A.H.M.Mahfuzur Rahman 65mahfuz90@gmail.com
+Copyright (c) 2010 Reto Zingg g.d0b3rm4n@gmail.com
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of
+the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "MoveGenerator.h"
+
+// #include <kdebug.h>
+
+#include "GameInfo.h"
+#include "GameController.h"
+
+
+MoveGenerator::MoveGenerator(int gameDifficulty,GameInfo *gameInfo,GameController *gameController){
+
+    m_gameDifficulty = gameDifficulty;
+    m_gameInfo = gameInfo;
+    m_gameController = gameController;
+    m_gameDifficulty = 0;
+
+    //we need to use m_depthList[m_gameDifficulty];
+    m_depthList[0] = 2;
+    m_depthList[1] = 6;
+    m_depthList[2] = 8;
+
+}
+
+int MoveGenerator::bestMove(QList<int> currentState,bool humanTurn){
+
+    // As we are calculating move only for computer player, humanTurn is currently
+    // unused
+    int cupIndex = -1,utility;   //The valid move we want to return
+    int value = -1000;
+
+    //rootNode is a maximizer
+    Node* rootNode = new Node(m_gameInfo);
+    copyBoard(rootNode,currentState);
+    rootNode->setTurn(false);
+    showBoardState(rootNode);
+    QList<Node*> m_possibleMoves;
+    Node* node;
+
+    simulateMoves(rootNode,m_possibleMoves);
+    //kDebug() << "Move simulation ended";
+
+    while(allEvaluations.count())
+        allEvaluations.pop_back();
+    while(allCupIndexes.count())
+        allCupIndexes.pop_back();
+
+
+    while(m_possibleMoves.count()){
+
+        node = m_possibleMoves.front();
+
+        //we have a bonus turn, so we maximize again
+        if(rootNode->turn() == node->turn()){
+//            kDebug() << "Calling maxValue";
+            allCupIndexes.append(node->move());
+            utility = maxValue(node,-1000,1000);
+            allEvaluations.append(utility);
+            if(utility > value){
+                value = utility;
+                cupIndex = node->move();
+            }
+        }
+        //we are making turn, so it is a minimizer
+        else {
+//            kDebug() << "Calling minValue";
+            allCupIndexes.append(node->move());
+            utility = minValue(node,-1000,1000);
+            allEvaluations.append(utility);
+            if(utility > value){
+                value = utility;
+                cupIndex = node->move();
+            }
+        }
+
+        m_possibleMoves.pop_front();
+    }
+
+    //kDebug() << "Evaluations: " << allEvaluations;
+    // kDebug() << "Index: " << cupIndex << " value " << value ;
+    return cupIndex;
+}
+
+int MoveGenerator::maxValue(Node *parentNode,int alpha,int beta){
+
+    if(isGameOver( parentNode->getBoard() ) || parentNode->depth() == m_depthList[m_gameDifficulty])
+        return parentNode->evaluationFunction(m_gameController);
+
+    int value = -1000,utility;
+    //kDebug() << alpha << beta << parentNode->turn();
+
+    QList<Node*> m_possibleMoves;
+    Node* node;
+    simulateMoves(parentNode,m_possibleMoves);
+
+    while(m_possibleMoves.count()){
+
+        node = m_possibleMoves.front();
+//        kDebug() << "cost: " << node->evaluationFunction(m_gameController);
+
+        //we have a bonus turn, so we maximize again
+        if(parentNode->turn() == node->turn()){
+//            kDebug() << "Calling maxValue";
+            allCupIndexes.append(node->move());
+            utility = maxValue(node,alpha,beta);
+            allEvaluations.append(utility);
+            if(utility > value){
+                value = utility;
+            }
+        }
+        //we are making turn, so it is a minimizer
+        else {
+//            kDebug() << "Calling minValue";
+            allCupIndexes.append(node->move());
+            utility = minValue(node,alpha,beta);
+            allEvaluations.append(utility);
+            if(utility > value){
+                value = utility;
+            }
+        }
+
+        if(value >= beta)
+            return value;
+        if(value > alpha)
+            alpha = value;
+
+
+        m_possibleMoves.pop_front();
+    }
+
+    return value;
+}
+
+int MoveGenerator::minValue(Node *parentNode,int alpha,int beta){
+
+    if(isGameOver(parentNode->getBoard()) || parentNode->depth() == m_depthList[m_gameDifficulty])
+        return parentNode->evaluationFunction(m_gameController);
+
+    int value = 1000,utility;
+    //kDebug() << alpha << beta << parentNode->turn();
+
+    QList<Node*> m_possibleMoves;
+    Node* node;
+    simulateMoves(parentNode,m_possibleMoves);
+
+
+    while(m_possibleMoves.count()){
+
+        node = m_possibleMoves.front();
+//        kDebug() << "cost: " << node->evaluationFunction(m_gameController);
+
+        //we have a bonus turn, so we minimize again
+        if(parentNode->turn() == node->turn()){
+//            kDebug() << "Calling minValue";
+            allCupIndexes.append(node->move());
+            utility = minValue(node,alpha,beta);
+            allEvaluations.append(utility);
+            if(utility < value){
+                value = utility;
+            }
+        }
+        //we are making turn, so it is a maximizer
+        else {
+//            kDebug() << "Calling maxValue";
+            utility = maxValue(node,alpha,beta);
+            allCupIndexes.append(node->move());
+            allEvaluations.append(utility);
+            if(utility < value){
+                value = utility;
+            }
+        }
+
+        if(value < beta)
+            beta = value;
+        if(value <= alpha)
+            return value;
+
+
+        m_possibleMoves.pop_front();
+    }
+
+    return value;
+
+}
+
+void MoveGenerator::simulateMoves(Node* currentNode,QList<Node*> &nodes){
+
+    //    Node* tempNode;
+    int count1,count2;
+    QList<int> parentBoard = currentNode->getBoard();
+    //    QPair<bool,QList<int> > infoNode;
+
+    //Computer turn
+    if(currentNode->turn() == false){
+        count1 = 0;
+        for(int i = 0 ; i < m_gameInfo->numCupsPerRow() ; i++){
+            //If there is enough stone to sow
+            if( parentBoard[i] > m_gameInfo->leftToCup()){
+
+                count1++;
+                Node* tempNode = new Node(m_gameInfo);
+                QPair<bool,QList<int> > infoNode;
+
+                infoNode = m_gameController->logicalMoveController(parentBoard,i,currentNode->turn());
+
+                //setting node information
+                copyBoard(tempNode,infoNode.second);
+                tempNode->setTurn(infoNode.first);
+                tempNode->setDepth( currentNode->depth() + 1 );
+                tempNode->setMove(i);
+
+                //kDebug() << "Node Info:";
+                //kDebug() << tempNode->getBoard();
+                //kDebug() << "Turn: " << tempNode->turn() << " Move: " << tempNode->move();
+
+                nodes.append(tempNode);
+            }
+        }
+
+    }
+
+    //Human Turn
+    else{
+        count2 = 0;
+        for(int i = m_gameInfo->numCupsPerRow() ; i < 2*m_gameInfo->numCupsPerRow() ; i++){
+            //If there is enough stone to sow
+            if( parentBoard[i] > m_gameInfo->leftToCup()){
+
+                count2++;
+                Node* tempNode = new Node(m_gameInfo);
+                QPair<bool,QList<int> > infoNode;
+
+                infoNode = m_gameController->logicalMoveController(parentBoard,i,currentNode->turn());
+
+                //setting node information
+                copyBoard(tempNode,infoNode.second);
+                tempNode->setTurn(infoNode.first);
+                tempNode->setDepth( currentNode->depth() + 1 );
+                tempNode->setMove(i);
+
+                //kDebug() << "Node Info:";
+                //kDebug() << tempNode->getBoard();
+                //kDebug() << "Turn: " << tempNode->turn() << " Move: " << tempNode->move();
+
+                nodes.append(tempNode);
+            }
+        }
+
+    }
+
+    //if(count1 > 0) kDebug() << "Count1: " << count1;
+    //if(count2 > 0) kDebug() << "Count2: " << count2;
+}
+
+bool MoveGenerator::isGameOver(QList<int> board){
+
+    for(int i = 0 ; i < 2*m_gameInfo->numCupsPerRow() ; i++)
+        if( board[i] > m_gameInfo->leftToCup() )
+            return false;
+    //kDebug() << "Game Is Over ...";
+    return true;
+}
+
+void MoveGenerator::copyBoard(Node* to,Node* from){
+    QList<int> fromBoard,toBoard;
+    fromBoard = from->getBoard();
+
+    for(int i = 0 ; i < 2 * m_gameInfo->numCupsPerRow() + 2 ; i++ )
+        toBoard.append(fromBoard[i]);
+    to->setBoard(toBoard);
+}
+
+void MoveGenerator::copyBoard(Node* to,QList<int>board){
+    QList<int> tempBoard;
+    for(int i = 0 ; i < 2 * m_gameInfo->numCupsPerRow() + 2 ; i++ ){
+        //kDebug() << "Index: " << i << " content: " << board[i];
+        tempBoard.append(board[i]);
+    }
+    to->setBoard(tempBoard);
+}
+
+void MoveGenerator::showBoardState(Node *node){
+    QList<int> board = node->getBoard();
+    // kDebug() << board;
+}
+
+//--------------------------------- Node Functions Below ------------------------------
+
+Node::Node(GameInfo* info){
+
+    m_gameInfo = info;
+    m_depth = 0;
+    m_humanTurn = false;
+    m_move = -1;
+
+    for(int i = 0 ; i < 2 * m_gameInfo->numCupsPerRow() + 2 ; i++)
+        m_boardState.append(0);
+}
+
+int Node::evaluationFunction(GameController* controller){
+
+    int cost = 0;
+//    kDebug() << "In kalah of Computer: "
+//    << m_boardState[1-controller->humanKalahIndex() + 2 * m_gameInfo->numCupsPerRow()]
+//    << "depth: "<< m_depth;
+    cost = m_boardState[1-controller->humanKalahIndex() + 2 * m_gameInfo->numCupsPerRow()]
+           - m_boardState[controller->humanKalahIndex() + 2 * m_gameInfo->numCupsPerRow()];
+
+    //kDebug() << "returning: " << cost;
+    return cost;
+}
+
+void Node::setBoard(QList<int> board){
+
+    for(int i = 0 ; i < 2 * m_gameInfo->numCupsPerRow() + 2 ; i++)
+        m_boardState[i] = board[i];
+}