#include "Game.h" vector Game::getLegalMoves(char player, Board b) { DEBUG(">>>> vector getLegalMoves(char player, Board b)\n"); Board temp = b; int numMoves = temp.possibleMoves.size(); vector legalMoves; legalMoves.clear(); for(int i = 0; i < numMoves; i++){ temp.possibleMoves[i].setPlayer(player); if(temp.IsLegal(temp.possibleMoves[i])){ DEBUG("Possible move by player %c\n", player); legalMoves.push_back(temp.possibleMoves[i]); } } return legalMoves; } Move Game::Random(char player, Board b) { DEBUG("Random function entrance with player = %c\n", player); vector legalMoves = getLegalMoves(player, b); int numMoves = legalMoves.size(); int randomChoice = 0; if (numMoves > 1) randomChoice = (rand()%(numMoves - 1)); return legalMoves[randomChoice]; } Move Game::MiniMax(char player, Board b, int depth, char heuristic) { DEBUG("MiniMax function entrance with player = %c\n", player); vector valueOneMoves; vector valueZeroMoves; vector valueNegOneMoves; valueOneMoves.clear(); valueZeroMoves.clear(); valueNegOneMoves.clear(); int index = 0; vector legalMoves = getLegalMoves(player, b); int numMoves = legalMoves.size(); Move result; int score, maxscore = -9999; DEBUG("Possible moves scores\n"); for(int i = 0; i < numMoves; i++){ score = minimaxHelper(player, b, legalMoves[i], true, depth-1, heuristic); legalMoves[i].setScore(score); if(score == 1) valueOneMoves.push_back(legalMoves[i]); else if(score == 0) valueZeroMoves.push_back(legalMoves[i]); else if(score == -1) valueNegOneMoves.push_back(legalMoves[i]); if(score > maxscore){ maxscore = score; result = legalMoves[i]; } legalMoves[i].Print(); } if(valueOneMoves.size() == 1){ OUTPUT("Choosing only 1-move\n"); return valueOneMoves[0]; }else if(valueOneMoves.size() > 1){ index = (rand()%(valueOneMoves.size()-1)); OUTPUT("Choosing %dth of %d 1-moves\n", index, valueOneMoves.size()); return valueOneMoves[index]; }else if(valueZeroMoves.size() == 1){ OUTPUT("Choosing only 0-move\n"); return valueZeroMoves[0]; }else if (valueZeroMoves.size() > 1){ index = (rand()%(valueZeroMoves.size()-1)); OUTPUT("Choosing %dth of %d 0-moves\n", index, valueZeroMoves.size()); return valueZeroMoves[index]; }else{ index = (rand()%(valueNegOneMoves.size()-1)); OUTPUT("Choosing %dth of %d -1-moves\n", index, valueNegOneMoves.size()); return valueNegOneMoves[index]; } DEBUG("Will use score = %d\n", maxscore); return result; } int Game::minimaxHelper(char player, Board b, Move mv, bool max, int depth, char heuristic) { int moveScore; char other = 'A'; if(player == 'A') other = 'B'; DEBUG(">>> Move minimaxhelper(char player=%c, Board b, Move mv, bool max=%i )\n", player, max); Board b_temp = newBoardWithMove(b,mv); if (heuristic == OPTIMISTIC) { moveScore = optimisticBoardScore(b_temp, player); } else if (heuristic == PESSIMISTIC) { moveScore = pessimisticBoardScore(b_temp, player); } else if (heuristic == UNCERTAIN) { moveScore = uncertainBoardScore(b_temp, player); } else { CRASH("Unrecognized heuristic"); } if(depth == 0) { return moveScore; } if(b_temp.IsWin(winningRunLength, player))//if win { return 1; } if(b_temp.IsWin(winningRunLength, other))//if opponent wins { return -1; } if(b_temp.fullBoard()){//if there are no more moves return moveScore; } //recursive part vector possible = getLegalMoves(other, b_temp); int psize = possible.size(); int value; int bestvalue = 0;//possibly keep at zero for (int i= 0; i < psize; i ++){ value = minimaxHelper(player, b_temp, possible[i], !max, depth-1, heuristic); if(!max){ value = value * -1; if(bestvalue < value) bestvalue = value; } if(bestvalue > value) bestvalue = value; } return bestvalue; } Board Game::newBoardWithMove(Board oldB, Move m) { DEBUG("\n"); Board b = oldB; b.MakeMove(m); return b; } int Game::optimisticBoardScore(Board& b, char p) { if(b.IsWin(winningRunLength, p)){ return 1; } if(b.IsDraw()){ return 0; } char other = 'A'; if(p == 'A') other = 'B'; if(b.IsWin(winningRunLength, other)){ return -1; } // incomplete board return 1; } int Game::pessimisticBoardScore(Board& b, char p) { if(b.IsWin(winningRunLength, p)){ return 1; } if(b.IsDraw()){ return 0; } char other = 'A'; if(p == 'A') other = 'B'; if(b.IsWin(winningRunLength, other)){ return -1; } // incomplete board return -1; } int Game::uncertainBoardScore(Board& b, char p) { if(b.IsWin(winningRunLength, p)){ return 1; } if(b.IsDraw()){ return 0; } char other = 'A'; if(p == 'A') other = 'B'; if(b.IsWin(winningRunLength, other)){ return -1; } // incomplete board return 0; } Move Game::playToLoss(char player, Board b, int depth) { DEBUG("playToLoss function entrance with player = %c\n", player); vector valueOneMoves; vector valueZeroMoves; vector valueNegOneMoves; valueOneMoves.clear(); valueZeroMoves.clear(); valueNegOneMoves.clear(); vector legalMoves = getLegalMoves(player, b); int numMoves = legalMoves.size(); int index = 0; Move result; int score, maxscore = -9999; DEBUG("Possible moves scores\n"); for(int i = 0; i < numMoves; i++){ score = minimaxHelper(player, b,legalMoves[i], true, depth-1, UNCERTAIN); legalMoves[i].setScore(score); if(score == -1) valueOneMoves.push_back(legalMoves[i]); else if(score == 0) valueZeroMoves.push_back(legalMoves[i]); else if(score == 1) valueNegOneMoves.push_back(legalMoves[i]); if(score > maxscore){ maxscore = score; result = legalMoves[i]; } } if(valueOneMoves.size() == 1){ return valueOneMoves[0]; }else if(valueOneMoves.size() > 1){ index = (rand()%(valueOneMoves.size()-1)); return valueOneMoves[index]; }else if(valueZeroMoves.size() == 1){ return valueZeroMoves[0]; }else if (valueZeroMoves.size() > 1){ index = (rand()%(valueZeroMoves.size()-1)); return valueZeroMoves[index]; }else{ index = (rand()%(valueNegOneMoves.size()-1)); return valueNegOneMoves[index]; } DEBUG("Will use score = %d\n", maxscore); return result; }