--- /dev/null
+/*
+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 <KLocale>
+
+#include "GameController.h"
+
+#include <QTimer>
+#include <QStringList>
+#include <QList>
+
+// #include <kdebug.h>
+
+#include "Board.h"
+#include "Score.h"
+#include "Kalah.h"
+#include "MoveGenerator.h"
+
+
+GameController::GameController(GameInfo* gameInfo){
+ m_gameInfo = gameInfo;
+ m_humanScore = new Score();
+ m_computerScore = new Score();
+ initializeGameController();
+
+ connect(this,SIGNAL(signalSowMaker(int)),this,SLOT(sowMaker(int)));
+ connect(this,SIGNAL(signalAfterSow(int)),this,SLOT(afterSow(int)));
+ connect(this,SIGNAL(signalComputerMove()),this,SLOT(makeComputerMove()));
+
+}
+
+void GameController::initializeGameController(){
+
+ m_gameDifficulty = GameController::EASY;
+ m_moveGenerator = new MoveGenerator(m_gameDifficulty,m_gameInfo,this);
+ m_humanTurn = true;
+ m_cupIndexClicked = -1;
+ m_humanSide = GameController::LOWER;
+ m_humanKalah = Kalah::Right;
+ m_gamePaused = false;
+ m_gameOver = false;
+ m_physicalMoveAllowed = false;
+ m_captureInfo = m_gameInfo->captureInfo();
+
+ //If game is clockwise change human kalah
+ if(m_humanSide == GameController::LOWER && m_gameInfo->rotationType() == GameInfo::CLOCKWISE){
+ m_humanKalah = Kalah::Left;
+ }
+
+ m_humanScore->reset();
+ m_computerScore->reset();
+
+ emit signalMessage("");
+ emit signalShowTurn(m_humanTurn);
+ emit signalShowScore(m_humanScore->score(),true);
+ emit signalShowScore(m_computerScore->score(),false);
+
+ initializeBoard();
+ setHumanSideCups();
+
+}
+
+void GameController::initializeBoard(){
+
+ while(m_physicalBoard.count()){
+ m_physicalBoard.pop_back();
+ m_logicalBoard.pop_back();
+ }
+
+ //stoneInfo in cups (0 to 2*m_gameInfo->numCupsPerRow()-1)
+ for(int i = 0 ; i< 2*m_gameInfo->numCupsPerRow();i++){
+ m_physicalBoard.append(m_gameInfo->initialStonesPerCup());
+ m_logicalBoard.append(m_gameInfo->initialStonesPerCup());
+ }
+
+ //stoneInfo in kalah's
+ for(int i = 0 ; i < 2 ; i++){
+ m_physicalBoard.append(0);
+ m_logicalBoard.append(0);
+ }
+
+}
+
+void GameController::setHumanSideCups(){
+
+ while(m_humanSideCups.count())
+ m_humanSideCups.pop_back();
+
+ for(int i = 0 ; i < m_gameInfo->numCupsPerRow();i++)
+ m_humanSideCups.append(i);
+ if(m_humanSide == GameController::LOWER)
+ for(int i = 0 ; i < m_gameInfo->numCupsPerRow();i++){
+ m_humanSideCups[i] = 2*m_gameInfo->numCupsPerRow() - 1 - m_humanSideCups[i];
+
+ }
+
+}
+
+//It is called from the GraphcisScene to start the game
+void GameController::setBoardItem(Board *board){
+ m_board = board;
+
+ //If computer starts we will delay it by 1.5 seconds
+ if(!m_humanTurn){
+ emit signalShowTurn(false);
+ QTimer::singleShot(1500, this, SLOT(makeComputerMove()));
+ }
+
+}
+
+//-------------Is this valid cup(cupIndex) belongs to human ----------------
+bool GameController::isHumanCup(int cupIndex){
+
+ if(cupIndex >= m_gameInfo->numCupsPerRow())
+ return true;
+ return false;
+}
+
+//----------------Is the kalah(kalahIndex) belongs to human---------------------
+bool GameController::isHumanKalah(int kalahIndex){
+ kalahIndex -= 2*m_gameInfo->numCupsPerRow();
+
+ if(kalahIndex == m_humanKalah){
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------Human Move-----------------------------------
+void GameController::makeHumanMove(int index){
+
+ if(isGameOver(m_physicalBoard) || !m_humanTurn) return;
+
+ m_physicalMoveAllowed = true;
+ // kDebug() << "Human Moving .................";
+ if(m_gameInfo->lapStyle() == GameInfo::MULTIPLE)
+ m_multipleLapDelay = false;
+ m_rotationInfo = m_gameInfo->rotationInfo(index);
+ sowMaker(index);
+
+}
+
+//----------------------------------Computer Move----------------------------
+void GameController::makeComputerMove(){
+
+ if(isGameOver(m_physicalBoard) || m_humanTurn) return;
+
+ // kDebug() << "Computer Moving ................";
+
+ m_physicalMoveAllowed = false;
+ int index = m_moveGenerator->bestMove(m_physicalBoard,false);
+ m_physicalMoveAllowed = true;
+ m_rotationInfo = m_gameInfo->rotationInfo(index);
+
+ if(index != -1){
+ // kDebug() << "Index: " << index << " Stones: " << m_physicalBoard[index];
+ sowMaker(index);
+ }
+
+ else
+ computerHasNoMove();
+}
+
+//slot sowMaker
+void GameController::sowMaker(int index){
+
+ if(isGameOver(m_physicalBoard)) return;
+ m_physicalMoveAllowed = true;
+
+ m_index = index;
+ //For human Turn, we want to response quick, unless it falls between multiple lap
+ if(m_humanTurn){
+ if(m_gameInfo->lapStyle() == GameInfo::MULTIPLE && m_multipleLapDelay)
+ QTimer::singleShot(1500,this,SLOT(sowController()));
+ else sowController();
+ }
+
+ else QTimer::singleShot(1500,this,SLOT(sowController()));
+}
+
+
+void GameController::sowController(){
+
+ if(m_gameOver) return;
+
+ int index = m_index;
+ index = singleSow(index);
+
+ if(m_gameInfo->lapStyle() == GameInfo::MULTIPLE && !isEndOfLap(index,m_physicalBoard)){
+ if(m_humanTurn) m_multipleLapDelay = true;
+ emit signalSowMaker(index);
+ }
+ else{
+ emit signalAfterSow(index);
+ }
+
+}
+
+//slot After Sow
+void GameController::afterSow(int index){
+
+ if(isGameOver(m_physicalBoard)) return;
+ if(m_gameInfo->isBonusTurn()){
+
+ if(index >= 2*m_gameInfo->numCupsPerRow()){ //is a kalah
+ // kDebug() << "A Bonus Turn:";
+ if(m_humanTurn && isHumanKalah(index)){
+ emit signalMessage( tr("You got a bonus turn") );
+ if(isHumanSideEmpty(m_physicalBoard)) humanHasNoMove();
+ return;
+
+ }
+ else if(!m_humanTurn && !isHumanKalah(index)){
+ emit signalMessage( tr("Computer got a bonus turn") );
+ if(isComputerSideEmpty(m_physicalBoard)) computerHasNoMove();
+ emit signalComputerMove();
+ return;
+ }
+
+ }
+ }
+
+
+ if(isGameOver(m_physicalBoard)) return;
+ handleCrossCapture(index,m_physicalBoard);
+ emit signalMessage("");
+
+ if(isGameOver(m_physicalBoard)) return;
+ int multiplier = handleCountNSeriesCapture(index,m_physicalBoard);
+
+ if(isGameOver(m_physicalBoard)) return;
+ changeTurn();
+
+ if(!m_humanTurn && !m_gameOver){
+ // kDebug() << "Next turn computer";
+ if(isComputerSideEmpty(m_physicalBoard)) computerHasNoMove();
+ else{
+ if(multiplier > 0)
+ QTimer::singleShot( multiplier * 1500, this, SLOT(makeComputerMove() ) );
+ else
+ QTimer::singleShot(1500, this, SLOT(makeComputerMove()));
+ }
+ }
+ else{
+ // kDebug() << "Next turn Human";
+ if(isHumanSideEmpty(m_physicalBoard) ) humanHasNoMove();
+ }
+
+}
+
+void GameController::changeTurn(){
+
+ m_humanTurn == true ? m_humanTurn = false : m_humanTurn = true;
+ emit signalShowTurn(m_humanTurn);
+}
+
+//---------------------------- is End Of Lap -----------------------------------
+bool GameController::isEndOfLap(int index,QList<int>& board){
+
+ //if last stone ends on a cup with desired no of stone
+ if(index < 2*m_gameInfo->numCupsPerRow() && board[index] == m_gameInfo->stonesToEndLap()){
+ return true;
+ }
+ //if last stone on a kalah
+ if(index >= 2*m_gameInfo->numCupsPerRow()){
+ return true;
+ }
+
+ return false;
+}
+
+//Will be true when each cup is empty
+bool GameController::isGameOver(QList<int>& board){
+
+ if(m_gameOver) return true;
+
+ for(int i = 0 ; i < 2*m_gameInfo->numCupsPerRow() ; i++)
+ if( board[i] > m_gameInfo->leftToCup() )
+ return false;
+ if(m_physicalMoveAllowed) emit signalGameOver();
+ m_gameOver = true;
+ return m_gameOver;
+}
+
+//--------------------------------single Lap sowing -------------------------------------
+int GameController::singleSow(int cupIndex){
+ //we first find out from which side the sowing started - easy, who is moving
+ Side side = m_humanSide;
+ if(!m_humanTurn) side = (Side)(1 - m_humanSide);
+
+ // if(m_physicalMoveAllowed) kDebug() << "We are here to sow";
+
+ QList<int> board;
+ if(m_physicalMoveAllowed) board = physicalBoard();
+ else board = logicalBoard();
+
+ //0-CLOCKWISE,1-ANTI_CLOCKWISE
+ int rotation = m_gameInfo->rotationInfo(cupIndex);
+ int i , kalahNo = Kalah::Left;
+ bool putKalahNow = false;
+ int returnValue = cupIndex;
+
+ //Initial Check where to put in the first stone
+ if( rotation == GameInfo::ANTICLOCKWISE){
+
+ i = cupIndex - 1;
+ if(cupIndex >= m_gameInfo->numCupsPerRow()){
+ kalahNo = Kalah::Right;
+ }
+
+ if( m_gameInfo->stonesToKalah() &&
+ ( (cupIndex == m_gameInfo->numCupsPerRow() && side == GameController::LOWER)
+ || ( cupIndex == 0 && side == GameController::UPPER ) ) )
+ putKalahNow = true;
+ }
+ //clockwise
+ else{
+ i = cupIndex + 1;
+ if(cupIndex < m_gameInfo->numCupsPerRow())
+ kalahNo = Kalah::Right;
+
+ if( m_gameInfo->stonesToKalah() &&
+ ( (cupIndex == (2 * m_gameInfo->numCupsPerRow()-1) && side == GameController::LOWER)
+ || ( cupIndex == (m_gameInfo->numCupsPerRow()-1) && side == GameController::UPPER) ) )
+ putKalahNow = true;
+ }
+
+
+ //Continuous check and update
+ int loop = board[cupIndex]- m_gameInfo->leftToCup();
+
+ for(int j = 0 ; j < loop ; j++){
+
+ if( rotation == GameInfo::CLOCKWISE)
+ i %= 2 * m_gameInfo->numCupsPerRow();
+ else
+ if( i < 0) i = 2 * m_gameInfo->numCupsPerRow() - 1;
+
+ //If it is need to be put in cup
+ if( !putKalahNow ){
+ board[i]++;
+
+ if(m_physicalMoveAllowed){
+ m_board->updateChildren(cupIndex,i,true);
+// // kDebug() << "Putting to cup: " << i;
+ }
+ returnValue = i;
+
+ //check whether the next stone will put in kalah or not
+ if( rotation == GameInfo::ANTICLOCKWISE){
+ if( m_gameInfo->stonesToKalah() &&
+ ( ( i == m_gameInfo->numCupsPerRow() && side == GameController::LOWER )
+ ||( i == 0 && side == GameController::UPPER ) ) )
+ putKalahNow = true;
+ i--;
+ }
+ else{
+ if( m_gameInfo->stonesToKalah() &&
+ ( (i == (2 * m_gameInfo->numCupsPerRow()-1) && side == GameController::LOWER)
+ || ( i == (m_gameInfo->numCupsPerRow()-1) && side == GameController::UPPER) ) )
+ putKalahNow = true;
+ i++;
+ }
+
+ }
+ //going to put it in kalah
+ else{
+
+ if(kalahNo == Kalah::Right){
+
+ if(m_physicalMoveAllowed){
+// kDebug() << "Putting to Right Kalah";
+ m_board->updateChildren(cupIndex,Kalah::Right,false);
+ }
+ returnValue = 2*m_gameInfo->numCupsPerRow() + Kalah::Right;
+ board[returnValue]++;
+ }
+
+ else{
+ if(m_physicalMoveAllowed){
+// kDebug() << "Putting to left kalah";
+ m_board->updateChildren(cupIndex,Kalah::Left,false);
+ }
+
+ returnValue = 2*m_gameInfo->numCupsPerRow() + Kalah::Left;
+ board[returnValue]++;
+ }
+
+ if(m_physicalMoveAllowed){
+ if(m_humanTurn && kalahNo == m_humanKalah)
+ changeScore(1,true);
+ else changeScore(1,false);
+ }
+
+ putKalahNow = false;
+ }
+
+ board[cupIndex]--;
+ }
+
+ if(m_physicalMoveAllowed) setPhysicalBoard(board);
+ else setLogicalBoard(board);
+
+ return returnValue;
+}
+
+
+void GameController::slotGameDifficulty(Difficulty difficulty){
+// kDebug() << "GameDifficulty is: " << difficulty;
+ m_gameDifficulty = difficulty;
+ m_moveGenerator->changeDifficulty(m_gameDifficulty);
+}
+
+
+//******************************** slots ******************************************
+void GameController::slotMouseClicked(int index){
+
+ if(m_gameOver)
+ return;
+
+ if(m_humanTurn){
+ m_cupIndexClicked = index;
+
+ if(isHumanSideEmpty(m_physicalBoard)){
+ emit signalMessage( tr("Sorry, you have no move") );
+ humanHasNoMove();
+ }
+ else if(m_cupIndexClicked < 0){
+ emit signalMessage( tr("Click on a Cup") );
+ }
+
+ else if(!isHumanCup(index))
+ emit signalMessage( tr("Click on a cup in the lower row") );
+
+ else if(m_physicalBoard[index] <= m_gameInfo->leftToCup())
+ emit signalMessage( tr("Sorry, not enough stones to move") );
+
+ else{
+ makeHumanMove(m_cupIndexClicked);
+ }
+ }
+
+}
+
+void GameController::slotGameOverForNewGame(int identity){
+ m_gameOver = true;
+ emit signalMessage( tr("Loading game...") );
+
+ QTimer* timer = new QTimer(this);
+ signalMapper = new QSignalMapper(this);
+ connect(timer,SIGNAL(timeout()),signalMapper,SLOT(map()));
+ signalMapper->setMapping(timer,identity);
+ connect(signalMapper,SIGNAL(mapped(int)),this,SIGNAL(timeout(int)));
+
+ connect(this,SIGNAL(timeout(int)),this,SLOT(newGameEmitter(int)));
+ timer->setSingleShot(true);
+ timer->start(1500);
+}
+
+void GameController::newGameEmitter(int identity){
+ emit signalNewGame(identity);
+}
+
+void GameController::slotGameOverForRestartGame(){
+ m_gameOver = true;
+// kDebug() << "GameOver is true";
+ emit signalMessage( tr("Loading game...") );
+ QTimer::singleShot(2000,this,SLOT(restartGameEmitter()));
+}
+
+void GameController::restartGameEmitter(){
+ emit signalRestartGame();
+}
+
+//******************************** slots *****************************
+
+bool GameController::isHumanSideEmpty(QList<int>& board){
+
+ for(int i = 0 ; i < m_gameInfo->numCupsPerRow() ; i++)
+ if(board[m_humanSideCups[i]] > m_gameInfo->leftToCup())
+ return false;
+ return true;
+}
+
+bool GameController::isComputerSideEmpty(QList<int>& board){
+
+ int maxIndex = 2*m_gameInfo->numCupsPerRow() - 1;
+
+ for(int i = 0 ; i < m_gameInfo->numCupsPerRow() ; i++)
+ if(board[maxIndex - m_humanSideCups[i]] > m_gameInfo->leftToCup())
+ return false;
+ return true;
+}
+
+//---------------------------------- capture handling-------------------------------------
+
+void GameController::handleCrossCapture(int index,QList<int>& board){
+
+ if(m_physicalMoveAllowed){ //kDebug() << "handle Cross capture -------";
+ if(isGameOver(m_physicalBoard)) return;
+ }
+ if(index >= 2*m_gameInfo->numCupsPerRow())
+ return;
+
+ //if CrossCapture allowed then 0th bit should be 1
+ int capture = m_gameInfo->captureType();
+ if(m_physicalMoveAllowed) // kDebug() << "Capture Info: " << capture;
+ if(!(capture & 1)){
+ if(m_physicalMoveAllowed) //kDebug() << "We will return";
+ return;
+ }
+
+ int opponentCupIndex;
+ int kalahIndex = -1;
+ //If it is a cup
+ if(index < 2*m_gameInfo->numCupsPerRow()){
+
+ opponentCupIndex = 2*m_gameInfo->numCupsPerRow() - 1 - index;
+ //if opponet cup is empty
+ if(board[opponentCupIndex] == 0)
+ return;
+ if(board[index] != 1) //we are now taking that only 1 stone
+ return;
+
+ if(isHumanCup(index) && m_humanTurn)
+ kalahIndex = m_humanKalah;
+ else if(!m_humanTurn && !isHumanCup(index))
+ kalahIndex = 1 - m_humanKalah;
+
+ //Now do the capture;
+ if(kalahIndex != -1){
+ QString strIndex = QString("%1,%2").arg(index).arg(kalahIndex);
+
+ //Animation part
+ if(m_physicalMoveAllowed){
+ QTimer* timer = new QTimer(this);
+ signalMapper = new QSignalMapper(this);
+
+ connect(timer,SIGNAL(timeout()),signalMapper,SLOT(map()));
+ signalMapper->setMapping(timer,strIndex);
+ connect(signalMapper,SIGNAL(mapped(const QString&)),this,SIGNAL(timeout(const QString&)));
+
+ connect(this,SIGNAL(timeout(const QString&)),this,SLOT(crossCapture(const QString&)));
+ timer->setSingleShot(true);
+ timer->start(1500);
+ }
+ else crossCapture(strIndex);
+ }
+ }
+
+}
+
+//Cross Capture is done here
+void GameController::crossCapture(const QString& indexString){
+
+ if(isGameOver(m_physicalBoard)) return;
+
+ int capture = m_gameInfo->captureType();
+ if(! (capture & 1) ) return;
+
+ int loop,i;
+ QList<int> board;
+ QStringList list;
+ int index,kalahIndex,opponentCupIndex;
+
+ list = indexString.split(',');
+ index = list[0].toInt();
+ kalahIndex = list[1].toInt();
+ opponentCupIndex = 2*m_gameInfo->numCupsPerRow() - 1 - index;
+
+ if(m_physicalMoveAllowed) board = physicalBoard();
+ else board = logicalBoard();
+
+ loop = board[index];
+ for(i = 0 ; i < loop ; ++i){
+ //we want to remove from index and put to kalah(human)
+ if(m_physicalMoveAllowed) m_board->updateChildren(index,kalahIndex,false);
+ board[index]--;
+ board[kalahIndex + 2*m_gameInfo->numCupsPerRow()]++;
+
+ if(m_physicalMoveAllowed){
+ if(kalahIndex == m_humanKalah)
+ changeScore(1,true);
+ else changeScore(1,false);
+ }
+ }
+
+ loop = board[opponentCupIndex];
+ for(i = 0 ; i < loop ; ++i){
+ //we want to remove from index and put to kalah(human)
+ if(m_physicalMoveAllowed) m_board->updateChildren(opponentCupIndex,kalahIndex,false);
+ board[opponentCupIndex]--;
+ board[kalahIndex + 2*m_gameInfo->numCupsPerRow()]++;
+
+ if(m_physicalMoveAllowed){
+ if(kalahIndex == m_humanKalah)
+ changeScore(1,true);
+ else changeScore(1,false);
+ }
+
+ }
+
+ if(m_physicalMoveAllowed) setPhysicalBoard(board);
+ else setLogicalBoard(board);
+
+}
+
+int GameController::handleCountNSeriesCapture(int index,QList<int>& board){
+ if(m_physicalMoveAllowed){
+ // kDebug() << "count and series capture--------";
+ if(isGameOver(m_physicalBoard)) return 0;
+ }
+ //Do the capture
+ int capture = m_gameInfo->captureType(),i = 0,kalahIndex;
+ int countCaptureIndex = -1,seriesCaptureIndex = -1;
+ bool captureAllowed;
+ int timerCount;
+
+ if(capture & 1) i++; //cross capture is at capture_info[0]
+ if(capture & 2) countCaptureIndex = i++;
+ if(capture & 4) seriesCaptureIndex = i++;
+
+ //If no count capture, then no series capture also
+ if(countCaptureIndex == -1){
+ return 0;
+ }
+ else{
+ //At this point we know count captue is allowed in this game
+ captureAllowed = false;
+
+ //we will check whether capture is allowed in this position. For example, game supports
+ //capture at the opponent, but current last stone is on own cup, so no capture
+ if( ( !( (m_humanTurn == false && isHumanCup(index) == false) || (m_humanTurn && isHumanCup(index) ) )
+ && ( m_captureInfo[countCaptureIndex].first == GameInfo::OPPONENT ||
+ m_captureInfo[countCaptureIndex].first == GameInfo::BOTH ) )
+ ||
+ ( ( ( m_humanTurn && isHumanCup(index) ) || (!m_humanTurn && !isHumanCup(index) ) )
+ && (m_captureInfo[countCaptureIndex].first == GameInfo::OWN ||
+ m_captureInfo[countCaptureIndex].first == GameInfo::BOTH ) ) )
+ {
+ captureAllowed = true;
+ timerCount = 0;
+ }
+
+ while(captureAllowed){
+
+ //if capture allowed and stone Number matched at the cup, then we will capture
+ if(stoneNumberMatched(index,countCaptureIndex,board)){
+ timerCount++;
+
+// if(m_physicalMoveAllowed) kDebug() << "count capture allowed";
+ if(m_humanTurn) kalahIndex = m_humanKalah;
+ else kalahIndex = 1 - m_humanKalah;
+
+ QString strIndex = QString("%1,%2").arg(index).arg(kalahIndex);
+
+ //Animation part
+ if(m_physicalMoveAllowed){
+// kDebug() << "str: " << strIndex;
+
+ QTimer* timer = new QTimer(this);
+ signalMapper = new QSignalMapper(this);
+
+ connect(timer,SIGNAL(timeout()),signalMapper,SLOT(map()));
+ signalMapper->setMapping(timer,strIndex);
+ connect(signalMapper,SIGNAL(mapped(const QString&)),this,SIGNAL(timeout(const QString&)));
+
+ connect(this,SIGNAL(timeout(const QString&)),this,SLOT(countCapture(const QString&)));
+ timer->setSingleShot(true);
+ timer->start(timerCount * 1500);
+ }
+ else countCapture(strIndex);
+
+ }
+ else break;
+
+ //Get Index of the next cup
+ if(seriesCaptureIndex != -1){
+ index = nextIndex(index,seriesCaptureIndex);
+// if(m_physicalMoveAllowed) kDebug() << "Next Cup Index: " << index;
+ }
+ else break;
+
+ //if at my own side but capture is only allowed at the opponent
+ if( ( ( ( m_humanTurn && isHumanCup(index)) || (!m_humanTurn && !isHumanCup(index) ) )
+ && m_captureInfo[countCaptureIndex].first == GameInfo::OPPONENT )
+ ||
+ //Or at my opponent side, but capture is allowed only at my own side
+ ( ( ( m_humanTurn && !isHumanCup(index) ) || ( !m_humanTurn && isHumanCup(index) ) )
+ && m_captureInfo[countCaptureIndex].first == GameInfo::OWN ) )
+ captureAllowed = false;
+ }
+
+ }
+ return timerCount;
+
+}
+
+//do the capture
+void GameController::countCapture(const QString& indexString){
+
+ if(isGameOver(m_physicalBoard)) return;
+
+ QList<int> board;
+ QStringList list;
+ int index,kalahIndex;
+
+ list = indexString.split(',');
+ index = list[0].toInt();
+ kalahIndex = list[1].toInt();
+
+ if(m_physicalMoveAllowed) board = physicalBoard();
+ else board = logicalBoard();
+
+ if(m_physicalMoveAllowed) m_board->updateChildren(index,kalahIndex,board[index]);
+ board[kalahIndex + 2*m_gameInfo->numCupsPerRow()] += board[index];
+
+ if(m_physicalMoveAllowed){
+ if(m_humanTurn) changeScore(board[index],true);
+ else changeScore(board[index],false);
+ }
+
+ board[index] = 0;
+
+ if(m_physicalMoveAllowed) setPhysicalBoard(board);
+ else setLogicalBoard(board);
+
+}
+
+bool GameController::stoneNumberMatched(int index,int countCaptureIndex,QList<int>& board){
+ //numbered
+ if( m_captureInfo[countCaptureIndex].second[0] == GameInfo::NUMBER){
+ //Check whether the cup has necessary stone to capture
+ for(int i = 1; i<m_captureInfo[countCaptureIndex].second.count();i++){
+ if(m_captureInfo[countCaptureIndex].second[i] == board[index]){
+// if(m_physicalMoveAllowed) kDebug() << "Index: " << index << " Stone:" << board[index];
+ return true;
+ }
+ }
+// if(m_physicalMoveAllowed) kDebug() << "Returning false";
+ return false;
+ }
+ //pattern
+ else{
+// if(m_physicalMoveAllowed) kDebug() << "I am in pattern";
+ //Even Pattern
+ if(m_captureInfo[countCaptureIndex].second[1] == GameInfo::EVEN){
+ if( board[index] % 2 == 0 && board[index] != 0){
+// if(m_physicalMoveAllowed) kDebug() << "Index: " << index << " Stone:" << board[index];
+ return true;
+ }
+ }
+ //Odd Pattern
+ else{
+ if(board[index] % 2)
+ return true;
+ }
+
+ return false;
+ }
+}
+
+
+int GameController::nextIndex(int index,int seriesCaptureIndex){
+ //We have to go back
+
+ if(m_captureInfo[seriesCaptureIndex].second[0] == GameInfo::FOLLOWING){
+
+ if(m_rotationInfo == GameInfo::CLOCKWISE){
+ if(index == 0){
+ index = 2 * m_gameInfo->numCupsPerRow() - 1;
+ return index;
+ }
+
+ else{
+ index = index-1;
+ return index;
+ }
+ }
+ else{
+ index = (index+1) % ( 2 * m_gameInfo->numCupsPerRow() );
+ return index;
+ }
+ }
+ //we will go forward
+ else{
+
+ if(m_rotationInfo == GameInfo::CLOCKWISE){
+ index = (index + 1) % ( 2 * m_gameInfo->numCupsPerRow() );
+ return index;
+ }
+
+ else{
+ if(index == 0){
+ index = 2 * m_gameInfo->numCupsPerRow() - 1;
+ return index;
+ }
+ else{
+ index = index - 1;
+ return index;
+ }
+ }
+ }
+}
+
+//-------------------------------------capture handling ends---------------------------
+
+void GameController::changeScore(int amount,bool human){
+ if(human){
+ m_humanScore->changeScore(amount);
+ emit signalShowScore(m_humanScore->score(),true);
+ }
+ else{
+ m_computerScore->changeScore(amount);
+ emit signalShowScore(m_computerScore->score(),false);
+ }
+}
+
+//Human Has no move, now what
+void GameController::humanHasNoMove(){
+
+ if(m_gameOver) return;
+ int check = m_gameInfo->specialFlag();
+ if(m_physicalMoveAllowed) emit signalMessage( tr("No Move human") );
+
+ if( check & 2){//turn passing
+ if(m_physicalMoveAllowed) changeTurn();
+ else m_humanTurn = !m_humanTurn;
+
+ if(m_physicalMoveAllowed) makeComputerMove();
+ }
+ else{
+ if(m_physicalMoveAllowed) finalCapture(m_physicalBoard);
+ else finalCapture(m_logicalBoard);
+ }
+}
+
+//computer has no move, now what
+void GameController::computerHasNoMove(){
+ // Special Flag - 0(empty Opponent),1(turn Passing),2(Compulsory Moves)
+ if(m_gameOver) return;
+ int check = m_gameInfo->specialFlag();
+ if(m_physicalMoveAllowed) emit signalMessage( tr("No Move Computer") );
+
+ if( check & 2){//turn passing
+ if(m_physicalMoveAllowed) changeTurn();
+ else m_humanTurn = !m_humanTurn;
+ }
+ else{
+ if(m_physicalMoveAllowed) finalCapture(m_physicalBoard);
+ else finalCapture(m_logicalBoard);
+ }
+}
+
+//when one has no move, this is called on condition
+void GameController::finalCapture(QList<int>& board){
+
+ int loop;
+
+ //capture from human side to humanKalah
+ for( int i = 0 ; i < m_humanSideCups.count() ; i++){
+ int index = m_humanSideCups[i];
+
+ //Going to Human Kalah
+ if(board[index]){
+ loop = board[index];
+ for(int i = 0 ; i < loop ; i++){
+ if(m_physicalMoveAllowed) m_board->updateChildren(index,m_humanKalah,false);
+ board[index]--;
+ board[m_humanKalah + 2*m_gameInfo->numCupsPerRow()]++;
+ if(m_physicalMoveAllowed) changeScore(1,true);
+ }
+ }
+ //Going to Computer kalah
+ if(board[2*m_gameInfo->numCupsPerRow() - 1 - index]){
+ loop = board[2*m_gameInfo->numCupsPerRow() - 1 - index];
+ for(int i = 0 ; i < loop ; i++){
+ if(m_physicalMoveAllowed) m_board->updateChildren(2*m_gameInfo->numCupsPerRow() - 1 - index,1-m_humanKalah,false);
+ board[2*m_gameInfo->numCupsPerRow() - 1 - index]--;
+ board[1-m_humanKalah + 2*m_gameInfo->numCupsPerRow()]++;
+ if(m_physicalMoveAllowed) changeScore(1,false);
+ }
+ }
+
+ }
+
+ if(m_physicalMoveAllowed){
+ m_gameOver = true;
+ emit signalGameOver();
+ }
+}
+
+//----------------------------------------------------------------------------------------
+
+
+QPair< bool,QList<int> > GameController::logicalMoveController(QList<int>board,int index,bool turn){
+
+ bool tempTurn = m_humanTurn; //storing turn of physical board
+ m_physicalMoveAllowed = false; //setting physical move as invalid
+
+ bool humanTurn = !turn; //next turn should be other(if not bonus move)
+ m_humanTurn = turn; //current board status, turn of parent node
+ setLogicalBoard(board);
+
+ //sowing
+ index = singleSow(index);
+
+ if(m_gameInfo->lapStyle() == GameInfo::MULTIPLE){
+ while(!isEndOfLap(index,m_logicalBoard)){
+ index = singleSow(index);
+ }
+ }
+
+
+ //If bonus turn do not change turn
+ if(m_gameInfo->isBonusTurn()){
+
+ if(index >= 2*m_gameInfo->numCupsPerRow()){ //is a kalah
+ //kDebug() << "A Bonus Turn:";
+ if(m_humanTurn && isHumanKalah(index)){
+ humanTurn = true;
+ }
+ else if(!m_humanTurn && !isHumanKalah(index)){
+ humanTurn = false;
+ }
+
+ }
+ }
+
+ handleCrossCapture(index,m_logicalBoard);
+ handleCountNSeriesCapture(index,m_logicalBoard);
+
+ if(isHumanSideEmpty(m_logicalBoard))
+ humanHasNoMove();
+ else if(isComputerSideEmpty(m_logicalBoard))
+ computerHasNoMove();
+
+ m_humanTurn = tempTurn; //restoring m_humanTurn
+ m_physicalMoveAllowed = true;
+ return qMakePair(humanTurn,m_logicalBoard);
+
+}
+
+void GameController::setPhysicalBoard(QList<int> board){
+ for(int i = 0 ; i < m_physicalBoard.count() ; i++)
+ m_physicalBoard[i] = board[i];
+}
+
+
+void GameController::setLogicalBoard(QList<int> board){
+ for(int i = 0 ; i < m_logicalBoard.count() ; i++)
+ m_logicalBoard[i] = board[i];
+}
+
+QList<int> GameController::logicalBoard(){ return m_logicalBoard;}
+QList<int> GameController::physicalBoard(){return m_physicalBoard;}
+
+//----------------------------------------------------------------------------------------
+#include "moc_GameController.cpp"