int Board::getScore(const player p) const { int score = 0; if (boardFull()) return 0; player who = OPEN; score += getPositionalScore(p); if (fourInARow()) score = INT_MAX; return score; }
//Dumb play - a random move int dumbPlay(int pieceType) { int randomColumn; randomColumn = rand()%GRID_N;//0 to GRID_N -1 number //End if board is full if(boardFull()) { if(isParent) { gameOver(EMPTY_SPACE); return -1; } else { return -1; } } while(columnFull(randomColumn)) { //That column is full //Generate another random one //Reseed //srand(time(NULL)); randomColumn = rand()%GRID_N;//0 to GRID_N -1 number } //Got a column that is not full //Place piece there placePiece(randomColumn,pieceType); //Check that we did not just randomly win if(getWinner(pieceType) == pieceType) { if(isParent) { //Call game over function gameOver(pieceType); } else { return randomColumn; } } return randomColumn; }
void MiniMax::minimize(tree& state, int depth, int alpha, int beta) { /* Their turn: * Find the worst (for us, best for opponent) move from here and take its * score for the current state */ scoreState(state); if (isWin(state.score)) { return; } if (boardFull(state)) { state.score = 0; return; } if (depth <= 0) { // Base case. Run the heuristic. return; } // Recursive case. Take the min of the maxes. int v = std::numeric_limits<int>::max(); size_t numChildren = state.children.size(); for (size_t i = 0; i < numChildren; ++i) { try { state.children[i] = makeMove(state, i, false); } catch (const std::runtime_error&) { continue; } state.children[i].move = i; maximize(state.children[i], --depth, alpha, beta); //favor moves in the middle if (i == state.children.size() / 2 && !isWin(state.children[i].score)) { --state.children[i].score; } v = std::min(v, state.children[i].score); if (v <= alpha) { // ***PRUNE*** state.score = v; return; } beta = std::min(beta, v); } // We didn't prune. state.score = v; }
UltimateTicTacToeMontecarloAI::GameState UltimateTicTacToeMontecarloAI::gameState(Board const& board, int player) const { int winner = gridWinner(board.bigGrid); if(winner == player) { return GameState::WIN; } else if(winner == otherPlayer(player)) { return GameState::LOSE; } else if(boardFull(board)) { return GameState::TIE; } else { return GameState::UNRESOLVED; } }
void waitForChildMove(int childIndex) { //Get move from reading int columnRead = readTurn(receiveIDs[childIndex]); //Make this move on parent board //Set the child board as the active board activeBoard = &parentBoardsArray[childIndex]; placePiece(columnRead, CHILD_PIECE); //Check for full and win if(getWinner(CHILD_PIECE) == CHILD_PIECE) { //Child won gameOver(CHILD_PIECE); } else if(boardFull()) { gameOver(EMPTY_SPACE); } }
// Function rotates Board, slides a Board to Left, // creates new Cell and rotates Board back static long boardStep(board_p board, int r) { long score = 0; long progress = 0; long goal = 0; char victory = 0; char full = 0; board_p prev = NULL; int i; ASSERT(NULL != board, "boardStep"); ASSERT(0 <= r, "boardStep"); ASSERT(r <= 3, "boardStep"); score = board->score; progress = board->progress; goal = ((long)1) << board->goal; prev = boardClone(board); for (i = 0; i < r; ++i) boardRotate(board); if (boardSlide(board)) if (boardGenerate(board)) ++board->round; victory = !(progress & goal) && (board->progress & goal); full = boardFull(board); switch (board->state) { case State_Game: if (full && victory) board->state = State_Victory; else if (full) board->state = State_Defeat; else if (victory) board->state = State_Goal; break; case State_Victory: break; case State_Defeat: break; case State_Goal: board->state = State_Free; break; case State_Free: if (boardFull(board)) board->state = State_Victory; break; } if (board->score < 0) board->score = 0; for (i = 4 - r; i > 0; --i) boardRotate(board); if (boardEquals(board, prev)) { // don't autorelease prev beause it's // already autoreleased } else { boardAutorelease(board->prev); board->prev = boardRetain(prev); } return board->score - score; };
/*board is the board right now. lvl is the lvl of the node we are creating, row and col is the position of the most recently added piece. row and col are not relevant when lvl is 0 and are invalid*/ Cathy::Node* Cathy::GameTree::CreateTree(int board[][NUMSQUARES],int lvl){ Node* nn=new Node(); int whowon; int whomoves=(lvl%2)?-player_:player_; MoveList p1; MoveList p2; MoveList flips; int nump1,nump2; int r,c; int newboard[NUMSQUARES][NUMSQUARES]; wchar_t debugStr[255 + 1]; int maxOrMin = lvl%2; // 0 is max, 1 is min if(!canMove(board, p1, p2) || boardFull(board)){ //game over, neither player can move getScores(board,nump1,nump2); if(nump1==nump2) whowon=0; else if(nump1>nump2) whowon=1; else whowon=-1; //Base case 1: someone has won the game, game is over score is 100 if(whowon) { nn->score_=whowon * player_* MAXSCORE; //if player_ is 1 and they won the whowon would be +ve so //we have score being +1, otherwise if player_ is -1 and //player 2 won, then whowon would be -1 so score will still //be +1. } } else if(lvl==height_-1){ //tree has reached its max height nn->score_=Eval(board,player_, p1, p2); //always evaluate for player at root! } else{ if(whomoves==1){ if(p1.numMoves()==0){ nn->noMove_=CreateTree(board,lvl+1); } else{ for(int i=0,prev_r=0,prev_c=0;i<p1.numMoves();i++){ p1.getRowCol(i,r,c); flips.clear(); addPiece(board,r,c,1,flips); if( i == 0 ){ // if it is the first node, then create it nn->child_[r][c] = CreateTree(board,lvl+1); prev_r = r, prev_c = c; } else{ if(maxOrMin == 0){ //otherwise, check before create, depending on lvl if(nn->child_[prev_r][prev_c]->score_ < Eval(board,player_,p1,p2) ){ nn->child_[prev_r][prev_c] = NULL; //delete nn->child_[prev_r][prev_c]; nn->child_[r][c] = CreateTree(board,lvl+1); prev_r = r, prev_c = c; } } else if(maxOrMin ==1){ if(nn->child_[prev_r][prev_c]->score_ > Eval(board,player_,p1,p2) ){ nn->child_[prev_r][prev_c] = NULL; //delete nn->child_[prev_r][prev_c]; nn->child_[r][c] = CreateTree(board,lvl+1); prev_r = r, prev_c = c; } } } /*undo the changes before testing the next move*/ board[r][c]=0; for(int j=0;j<flips.numMoves();j++){ flips.getRowCol(j,r,c); board[r][c]=-1; } } } } else{ if(p2.numMoves()==0){ nn->noMove_=CreateTree(board,lvl+1); } else{ for(int i=0,prev_r=0,prev_c=0;i<p2.numMoves();i++){ p2.getRowCol(i,r,c); flips.clear(); addPiece(board,r,c,-1,flips); if( i == 0 ){ // if it is the first node, the create it nn->child_[r][c] = CreateTree(board,lvl+1); prev_r = r, prev_c = c; } else{ if(maxOrMin == 0){ //otherwise, check before create, depending on lvl if(nn->child_[prev_r][prev_c]->score_ < Eval(board,player_,p1,p2) ){ nn->child_[prev_r][prev_c] = NULL; //delete nn->child_[prev_r][prev_c]; nn->child_[r][c] = CreateTree(board,lvl+1); prev_r = r, prev_c = c; } } else if(maxOrMin ==1){ if(nn->child_[prev_r][prev_c]->score_ > Eval(board,player_,p1,p2) ){ nn->child_[prev_r][prev_c] = NULL; //delete nn->child_[prev_r][prev_c]; nn->child_[r][c] = CreateTree(board,lvl+1); prev_r = r, prev_c = c; } } } /*undo the move before testing the next move*/ board[r][c]=0; for(int j=0;j<flips.numMoves();j++){ flips.getRowCol(j,r,c); board[r][c]=1; } } } } bool setgood=false; //StringCbPrintfW(debugStr,255,L"Create Tree is called %d \n", lvl%2); //OutputDebugStringW(debugStr); //NOTE: If you implement alpha beta pruning, you will have to track max/min in the //tree creation loop. if(lvl%2){ if(nn->noMove_){ nn->score_=nn->noMove_->score_; } else{ for(int i=0;i<NUMSQUARES;i++){ for(int j=0;j<NUMSQUARES;j++){ if(nn->child_[i][j]){ if(!setgood || nn->child_[i][j]->score_ < nn->score_){ nn->score_=nn->child_[i][j]->score_; setgood=true; } } }//for }//for } } else{ if(nn->noMove_){ nn->score_=nn->noMove_->score_; } else{ for(int i=0;i<NUMSQUARES;i++){ for(int j=0;j<NUMSQUARES;j++){ if(nn->child_[i][j]){ if(!setgood || nn->child_[i][j]->score_ > nn->score_){ nn->score_=nn->child_[i][j]->score_; setgood=true; if(lvl==0){ bestrow_=i; bestcol_=j; } } } }//for }//for } } } //end of tree creation loop return nn; }
bool Board::boardSolved() { if (!boardFull()) { return false; } bool kFound = false; // testing for all nine digits in each row for (int k = 1; k < 10; k++) { for (int i = 0; i < BOARD_SIZE; i++) { kFound = false; for (int j = 0; j < BOARD_SIZE; j++) { if (boardArray[i][j] == k) { kFound = true; } } if (!kFound) { return false; } } } // testing for all nine digits in each column for (int k = 1; k < 10; k++) { for (int j = 0; j < BOARD_SIZE; j++) { kFound = false; for (int i = 0; i < BOARD_SIZE; i++) { if (boardArray[i][j] == k) { kFound = true; } } if (!kFound) { return false; } } } // testing for all nine digits in each cell int i; int j; for (int k = 1; k < 10; k++) { // cell one kFound = false; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } // cell two kFound = false; for (i = 0; i < 3; i++) { for (j = 3; j < 6; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } // cell three kFound = false; for (i = 0; i < 3; i++) { for (j = 6; j < 9; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } // cell four kFound = false; for (i = 3; i < 6; i++) { for (j = 0; j < 3; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } // cell five kFound = false; for (i = 3; i < 6; i++) { for (j = 3; j < 6; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } // cell six kFound = false; for (i = 3; i < 6; i++) { for (j = 6; j < 9; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } // cell seven kFound = false; for (i = 6; i < 9; i++) { for (j = 0; j < 3; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } // cell eight kFound = false; for (i = 6; i < 9; i++) { for (j = 3; j < 6; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } // cell nine kFound = false; for (i = 6; i < 9; i++) { for (j = 6; j < 9; j++) { if (boardArray[i][j] == k) { kFound = true; } } } if (!kFound) { return false; } } return true; }