int AIInterface::Search(Duel* pos, int depth, int player) { //Duel* lastpos if (depth == 0) { return Evaluate(pos, player); } int value = 0; vector<Message> moves = getValidMoves(pos); for (int i = 0; i < min(10, int(moves.size())); i++) { //Duel* d = new Duel(*pos); Duel* d = new Duel; ActiveDuel = d; d->isSimulation = true; d->RandomGen.SetRandomSeed(pos->RandomGen.GetRandomSeed()); d->setDecks(pos->decknames[0], pos->decknames[1]); d->startDuel(); d->dispatchAllMessages(); cout << "AI: move size: " << pos->MoveHistory.size() << endl; for (vector<Message>::iterator i = pos->MoveHistory.begin(); i != pos->MoveHistory.end(); i++) { //cout << "AI sim move: " << (*i).getType() << endl; d->handleInterfaceInput(*i); d->dispatchAllMessages(); } if (d->hands[0].cards.size() != pos->hands[0].cards.size()) { cout << "AI: ERROR check not valid NON-ROOT " << d->hands[0].cards.size() << " " << pos->hands[0].cards.size() << endl; cout << d->MoveHistory.size() << " " << pos->MoveHistory.size() << endl; } for (int i = 0; i < depth; i++) { vector<Message> m = getValidMoves(d); if (m.size() == 0) { cout << "AI: out of moves" << endl; break; } Message mov = m.at(rand() % m.size()); d->handleInterfaceInput(mov); d->dispatchAllMessages(); cout << "AI: move made: " << mov.getType() << endl; } value += Evaluate(d, player); if (d!=NULL) delete d; } return value; }
int AIInterface::AlphaBeta(Duel* pos, int depth, int player) { if (depth == 0) { int r = Evaluate(pos, pos->turn); //cout << "eval : " << r << endl; return r; } //cout << "depth : " << depth << endl; vector<Message> m = getValidMoves(duel); int max = -10000; bool autotap = duel->castingcard == -1 ? false : true; int pmana = duel->manazones[duel->turn].getUntappedMana(); int puntap = duel->isThereUntappedManaOfCiv(duel->turn, CIV_FIRE); for (vector<Message>::iterator i = m.begin(); i != m.end(); i++) { duel->handleInterfaceInput(*i); duel->dispatchAllMessages(); int x = -AlphaBeta(duel, depth-1, duel->turn); duel->undoLastMove(); vector<Message> m2 = getValidMoves(duel); if (m2.size() != m.size()) { cout << "AI: ERROR: moves size mismatch, move: " << (*i).getType() << endl; for (int k = 0; k < m.size(); k++) { cout << m.at(k).getType() << endl; } for (int k = 0; k < m2.size(); k++) { cout << m2.at(k).getType() << endl; } cout << "mana: " << duel->manazones[duel->turn].getUntappedMana() << " " << pmana << " untap: " << duel->isThereUntappedManaOfCiv(duel->turn, CIV_FIRE) << " " << puntap << endl; cout << " "; } //cout << "AI: value " << x << " for move: " << (*i).getType() << endl; /*if (duel->hands[0].cards.size() != duel->hands[0].cards.size()) { cout << "AI: undo failed " << i->getType() << duel->hands[0].cards.size() << " " << duel->hands[0].cards.size() << endl; }*/ if (x > max) { max = x; } if (autotap) //auto-tap break; } return max; }
string AIEngine::randMove() { srand(time(NULL)); vector< pair<int,int> > validPieces = getValidPieces(); // Randomly choose one of available pieces pair<int,int> piece = validPieces[rand() % validPieces.size()]; vector< pair<int,int> > validMoves = getValidMoves(piece); // Randomly choose one of available moves pair<int,int> move = validMoves[rand() % validMoves.size()]; // Update the board int sX = get<0>(piece), sY = get<1>(piece); board->setIndex(sX, sY, '\0'); int dX = get<0>(move), dY = get<1>(move); if(pieceType == 'X') board->setIndex(dX, dY, 'X'); if(pieceType == 'O') board->setIndex(dY, dY, 'O'); // Convert move choice to string return writeMove(sX, sY, dX, dY); }
Message AIInterface::makeMove() { vector<Message> m = getValidMoves(duel); if (m.size() == 0) { return Message("AI: NO VALID MOVES ERROR"); } if (m.size() == 1) //only 1 valid move { cout << "AI: only 1 legal move" << endl; return m.at(0); } if (duel->castingcard != -1) //auto-tap { return m.at(0); } int max = -10000; Message maxmove("AI: DEFAULT MOVE ERROR"); duel->isSimulation = 1; for (vector<Message>::iterator i = m.begin(); i != m.end(); i++) { duel->handleInterfaceInput(*i); duel->dispatchAllMessages(); int x = -AlphaBeta(duel, 4, duel->turn); duel->undoLastMove(); vector<Message> m2 = getValidMoves(duel); if (m2.size() != m.size()) { cout << "AI: ERROR: moves size mismatch" << endl; } cout << "AI: value " << x << " for move: " << (*i).getType() << endl; /*if (duel->hands[0].cards.size() != duel->hands[0].cards.size()) { cout << "AI: undo failed " << i->getType() << duel->hands[0].cards.size() << " " << duel->hands[0].cards.size() << endl; }*/ if (x > max) { maxmove = *i; max = x; } } cout << "AI: maxmove value: " << max << endl; duel->isSimulation = 0; return maxmove; }
MOVELIST* getValidMoves(STRING board, int index, int* count) { MOVELIST* validMoves; while((board[index] != BLANKCHAR) && (index < boardsize)) { index++; } if(index==boardsize) { validMoves = NULL; } else { *count = *count + 1; validMoves = CreateMovelistNode(index, getValidMoves(board, index+1, count)); } return validMoves; }
MOVELIST *GenerateMoves (POSITION position) { MOVELIST* validMoves; char* board; int blankcount = 0; board = (char*)SafeMalloc((possize)*sizeof(char)); generic_hash_unhash(position, board); validMoves = getValidMoves(board, 0, &blankcount); if(swapmode != SWAP_NONE && generic_hash_turn(position) != FIRSTPLAYER && blankcount == boardsize-swapturn) validMoves = CreateMovelistNode(SWAPMOVE, validMoves); SafeFree(board); return validMoves; }
void getCanonicalValidMoves(PointColor c, std::vector<Move>& out) { getValidMoves(c, out); }
Board AIEngine::alphaBeta(Board board, char curpawn, int stopper, bool once, pair<int, int> node, int a, int b) //1 = max, 0 = min { int alpha = a; int beta = b; char pawn = curpawn; Board current = board; /*CHECKS FOR VICTORY OR DEFEAT*/ if (stopper <= 0) return board; if (board.checkVictory() == 1 && pawn != curpawn) { board.score -= 1000; return board; } if (board.checkVictory() == 1 && pawn == curpawn) { board.score += 1000; return board; } if (board.checkVictory() == 2 && pawn != curpawn) { board.score -= 1000; return board; } if (board.checkVictory() == 2 && pawn == curpawn) { board.score += 1000; return board; } /*GET THE NEXT PAWN*/ char nextPawn; if (curpawn == 'X') nextPawn = 'O'; else nextPawn = 'X'; /*FIND AVAILABLE PAWNS (NODES) TO MOVE FOR THE CURRENT PAWN TYPE ONLY DONE ONCE*/ if (once) { board.score = 0; int bestScore = INT_MIN; Board best; char savePawn = pawn; pawn = curpawn; vector<pair<int, int>> peices; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (isValidPiece(i, j)) { peices.push_back(pair<int, int>(i, j)); } } } pawn = savePawn; for (int i = 0; i < peices.size(); i++) { node = peices[i]; Board temp = bestMove(board, curpawn, stopper, false, node); if (temp.score > bestScore) { best = temp; bestScore = best.score; } } return best; } /*Check on the possible moves for the one node pawn, and evaluate them DONE IF THE FUNCTION WAS CALLED RECURSIVELY*/ if (!once) { current = board; char savePawn = pawn; pawn = curpawn; vector<pair<int, int>> validMoves = getValidMoves(node); pawn = savePawn; /*ERROR CHECKING*/ /*cout << "Stopper: " << stopper << endl; cout << "Node: " << get<0>(node) << get<1>(node) << endl; cout << "Valid moves: "; for (int i = 0; i < validMoves.size(); i++) { cout << get<0>(validMoves[i]) << get<1>(validMoves[i]) << " "; } cout << endl;*/ /*END OF ERROR CHECKING*/ Board best; Board temp = board; Board temp2; int baseline; if (curpawn == pieceType) { baseline = INT_MIN; } else { baseline = INT_MAX; } int v; for (int i = 0; i < validMoves.size(); i++) { temp = board; /*SCORING THE MOVE*/ if (curpawn == pieceType) { if (temp.getIndex(get<0>(validMoves[i]), get<1>(validMoves[i])) == nextPawn) { temp.score += 5; } else { temp.score += 1; } } else { if (temp.getIndex(get<0>(validMoves[i]), get<1>(validMoves[i])) == pieceType) { temp.score -= 4; } else { temp.score += 0; } } temp.setIndex(get<0>(node), get<1>(node), '\0'); temp.setIndex(get<0>(validMoves[i]), get<1>(validMoves[i]), curpawn); //IF AI WINS if (get<0>(validMoves[i]) == 7 && curpawn == pawn) { temp.score = INT_MAX; return temp; } if (curpawn == pieceType) { /*Maximize*/ temp2 = alphaBeta(temp, nextPawn, stopper - 1, false, validMoves[i], alpha, beta); /* if (temp2.score > baseline) { baseline = temp2.score; best = temp; best.score = baseline; }*/ if (temp2.score > baseline) v = temp2.score; else v = baseline; if (alpha < v) alpha = alpha; else alpha = v; if (beta <= alpha) return temp; } else { /*Minimize*/ pawn = nextPawn; vector<pair<int, int>> peices; for (int j = 0; j < 8; j++) { for (int k = 0; k < 8; k++) { if (isValidPiece(j, k)) { peices.push_back(pair<int, int>(j, k)); } } } pawn = savePawn; for (int j = 0; j < peices.size(); j++) { temp2 = alphaBeta(temp, nextPawn, stopper - 1, false, peices[j], alpha, beta); /*if (temp2.score < baseline) { baseline = temp2.score; best = temp; best.score = baseline; }*/ if (temp2.score < baseline) v = temp2.score; else v = baseline; if (beta > v) beta = beta; else beta = v; if (beta <= alpha) return temp; } } } return best; } }