int Game::minMove(int depth, int alpha, int beta) { std::vector<int> allMoves = getAvailableMoves(); int winner = checkWinner(); if ((allMoves.size() <= 0 || winner > 0) || depth <= 0) { return evaluateState(2, winner); } int* bestMove = NULL; int bestScore = INT_MAX; for (std::vector<int>::const_iterator it = allMoves.begin(); it != allMoves.end(); it++) { setCell(*it, 1); int score = maxMove(depth - 1, alpha, beta); undoMove(*it); if (score < bestScore) { bestScore = score; beta = score; } if (beta < alpha) { return bestScore; } } return bestScore; }
int Game::minMax() { std::vector<int> allMoves = getAvailableMoves(); int bestMove = NULL; int bestScore = INT_MIN; for (std::vector<int>::const_iterator it = allMoves.begin(); it != allMoves.end(); it++) { setCell(*it, 1); int val = maxMove(100, INT_MIN + 1, INT_MAX); undoMove(*it); if (val > bestScore) { bestScore = val; bestMove = *it; } } return bestMove; }
TPoint CSearchEngine::alphaBetaTT(TBlock board[], const TPos&_p1, const TPos&_p2, const TPlayer next, vector<TMove> &history, int depth, TPoint alpha, TPoint beta) { #ifdef _DEBUG TBlock backup[BOARD_SIZE]; memcpy(backup, board, BOARD_SIZE*sizeof(TBlock)); vector<TMove> _history(history); #endif // _DEBUG assert((GET_BLOCK(board, _p1)) == BLOCK_PLAYER_1); assert((GET_BLOCK(board, _p2)) == BLOCK_PLAYER_2); assert(next == PLAYER_1 || next == PLAYER_2); static CMyTimer *timer = CMyTimer::getInstance(); static CMyAI* pAI = CMyAI::getInstance(); if (pAI->shouldEndMoveNow()) return TIMEOUT_POINTS; static CTranspositionTable *tt = CTranspositionTable::getInstance(); CGameState state(history); state.depth = depth; CGameState* ttEntry = tt->get(state); if (ttEntry && ttEntry->depth >= depth){ if (ttEntry->lower >= beta) { return ttEntry->lower; } if (ttEntry->upper <= alpha) { return ttEntry->upper; } alpha = max(alpha, ttEntry->lower); beta = min(beta, ttEntry->upper); } bool bOk; TPoint g; TPoint point = CHeuristicBase::evaluateBoardTT(board, _p1, _p2, next, history); if (point != 0) { g = point; } else if (depth == 0) { g = heuristic.rateBoardTT(board, _p1, _p2, next, history); } else { vector<TMove> moves; moves = next == PLAYER_1 ? getAvailableMoves(board, _p1) : getAvailableMoves(board, _p2); CHeuristicBase::sortMoves(moves, board, _p1, _p2, next, history); TPoint ab; if (next == PLAYER_1){ g = -MY_INFINITY; TPoint a = alpha; for (auto m = moves.begin(); m != moves.end(); m++){ bOk = move(board, _p1, *m, false); assert(bOk); history.push_back(*m); g = max(g, ab = alphaBetaTT(board, MOVE(_p1, *m), _p2, PLAYER_2, history, depth - 1, a, beta)); bOk = move(board, MOVE(_p1, *m), getOpositeDirection(*m), true); assert(bOk); history.pop_back(); if (ab == TIMEOUT_POINTS) return TIMEOUT_POINTS; assert(ab >= -MY_INFINITY && ab <= MY_INFINITY); a = max(g, a); } } else { g = MY_INFINITY; TPoint b = beta; for (auto m = moves.begin(); m != moves.end(); m++){ bOk = move(board, _p2, *m, false); assert(bOk); history.push_back(*m); g = min(g, ab = alphaBetaTT(board, _p1, MOVE(_p2, *m), PLAYER_1, history, depth - 1, alpha, b)); bOk = move(board, MOVE(_p2, *m), getOpositeDirection(*m), true); assert(bOk); history.pop_back(); if (ab == TIMEOUT_POINTS) return TIMEOUT_POINTS; assert(ab >= -MY_INFINITY && ab <= MY_INFINITY); b = min(g, b); } } } if (!ttEntry) ttEntry = tt->put(state); if (g <= alpha) ttEntry->upper = g; if (g > alpha && g < beta){ ttEntry->lower = g; ttEntry->upper = g; } if (g >= beta) ttEntry->lower = g; ttEntry->depth = depth; #ifdef _DEBUG assert(memcmp(board, backup, BOARD_SIZE*sizeof(TBlock)) == 0); assert(_history.size() == history.size()); assert(equal(_history.begin(), _history.end(), history.begin())); #endif // _DEBUG return g; }
pair<TMove, TPoint> CSearchEngine::getOptimalMoveByAB(TBlock board[], const TPos&_p1, const TPos&_p2, const TPlayer next, const vector<TMove> &_history, int depth) { #ifdef _DEBUG TBlock backup[BOARD_SIZE]; memcpy(backup, board, BOARD_SIZE*sizeof(TBlock)); #endif // _DEBUG vector<TMove> history(_history); bool bOk; vector<TMove> moves; moves = next == PLAYER_1 ? getAvailableMoves(board, _p1) : getAvailableMoves(board, _p2); if (moves.size() == 0){ return pair<TMove, TPoint>(rand() % 4 + 1, 0); } CHeuristicBase::sortMoves(moves, board, _p1, _p2, next, history); TPoint value; TPoint ab; TPoint a = -MY_INFINITY; TPoint b = MY_INFINITY; TMove bestMove = 0; if (next == PLAYER_1){ value = -MY_INFINITY; for (auto m = moves.begin(); m != moves.end(); m++){ bOk = move(board, _p1, *m, false); assert(bOk); history.push_back(*m); if (USING_MEMORY) ab = alphaBetaTT(board, MOVE(_p1, *m), _p2, PLAYER_2, history, depth - 1, a, b); else ab = alphaBeta(board, MOVE(_p1, *m), _p2, PLAYER_2, history, depth - 1, a, b); if (value < ab){ value = ab; bestMove = *m; } bOk = move(board, MOVE(_p1, *m), getOpositeDirection(*m), true); assert(bOk); history.pop_back(); if (ab == TIMEOUT_POINTS) return pair<TMove, TPoint>(bestMove, TIMEOUT_POINTS); assert(ab >= -MY_INFINITY && ab <= MY_INFINITY); a = max(value, a); if (b <= a) break; } } else { value = MY_INFINITY; for (auto m = moves.begin(); m != moves.end(); m++){ bOk = move(board, _p2, *m, false); assert(bOk); history.push_back(*m); if (USING_MEMORY) ab = alphaBetaTT(board, _p1, MOVE(_p2, *m), PLAYER_1, history, depth - 1, a, b); else ab = alphaBeta(board, _p1, MOVE(_p2, *m), PLAYER_1, history, depth - 1, a, b); if (value > ab){ value = ab; bestMove = *m; } bOk = move(board, MOVE(_p2, *m), getOpositeDirection(*m), true); assert(bOk); history.pop_back(); if (ab == TIMEOUT_POINTS) return pair<TMove, TPoint>(bestMove, TIMEOUT_POINTS); assert(ab >= -MY_INFINITY && ab <= MY_INFINITY); b = min(value, b); if (b <= a) break; } } #ifdef _DEBUG assert(memcmp(board, backup, BOARD_SIZE*sizeof(TBlock)) == 0); #endif // _DEBUG assert(bestMove >= 1 && bestMove <= 4); return pair<TMove, TPoint>(bestMove, value); }
TPoint CSearchEngine::alphaBeta(TBlock board[], const TPos&_p1, const TPos&_p2, const TPlayer next, vector<TMove> &history, int depth, TPoint a, TPoint b) { #ifdef _DEBUG TBlock backup[BOARD_SIZE]; memcpy(backup, board, BOARD_SIZE*sizeof(TBlock)); vector<TMove> _history(history); #endif // _DEBUG assert((GET_BLOCK(board, _p1)) == BLOCK_PLAYER_1); assert((GET_BLOCK(board, _p2)) == BLOCK_PLAYER_2); assert(next == PLAYER_1 || next == PLAYER_2); static CMyAI* pAI = CMyAI::getInstance(); static CMyTimer *timer = CMyTimer::getInstance(); if (pAI->shouldEndMoveNow()) return TIMEOUT_POINTS; bool bOk; TPoint bestValue = -MY_INFINITY; TPoint point = CHeuristicBase::evaluateBoardTT(board, _p1, _p2, next, history); if (point == TIMEOUT_POINTS) return point; if (point != 0) { assert(point > POINTS / 2 || point < -POINTS / 2); return point; } if (depth == 0) { TPoint t = heuristic.rateBoardTT(board, _p1, _p2, next, history); assert(abs(t) <= MY_INFINITY); return t; } vector<TMove> moves; moves = next == PLAYER_1 ? getAvailableMoves(board, _p1) : getAvailableMoves(board, _p2); CHeuristicBase::sortMoves(moves, board, _p1, _p2, next, history); TPoint value; TPoint ab; if (next == PLAYER_1){ value = -MY_INFINITY; for (auto m = moves.begin(); m != moves.end(); m++){ bOk = move(board, _p1, *m, false); assert(bOk); history.push_back(*m); value = max(value, ab = alphaBeta(board, MOVE(_p1, *m), _p2, PLAYER_2, history, depth - 1, a, b)); bOk = move(board, MOVE(_p1, *m), getOpositeDirection(*m), true); assert(bOk); history.pop_back(); if (ab == TIMEOUT_POINTS) return TIMEOUT_POINTS; assert(ab >= -MY_INFINITY && ab <= MY_INFINITY); a = max(value, a); if (b <= a) break; } } else { value = MY_INFINITY; for (auto m = moves.begin(); m != moves.end(); m++){ bOk = move(board, _p2, *m, false); assert(bOk); history.push_back(*m); value = min(value, ab = alphaBeta(board, _p1, MOVE(_p2, *m), PLAYER_1, history, depth - 1, a, b)); bOk = move(board, MOVE(_p2, *m), getOpositeDirection(*m), true); assert(bOk); history.pop_back(); if (ab == TIMEOUT_POINTS) return TIMEOUT_POINTS; assert(ab >= -MY_INFINITY && ab <= MY_INFINITY); b = min(value, b); if (b <= a) break; } } #ifdef _DEBUG assert(memcmp(board, backup, BOARD_SIZE*sizeof(TBlock)) == 0); assert(_history.size() == history.size()); assert(equal(_history.begin(), _history.end(), history.begin())); #endif // _DEBUG assert(value >= -MY_INFINITY && value <= MY_INFINITY); return value; }
void testFindPath(TBlock *board, const TPos&p = 0) { static CMyTimer* timer = CMyTimer::getInstance(); TPos pos = p; int c = 0; int upper = 0, lower = 0, exact = 0, calculatedExact = 0; bool bOk; #ifdef OPENCV imshow("original board", toImage(board)); waitKey(1); #endif // OPENCV upper = CBC::calculateLength(board, pos, true, EXACT_AREA_BELOW_10); assert(upper != TIMEOUT_POINTS); if (upper > 45) return; // { // int t1, t2; // static CBCO o; // CBC::calculateBCs(board, &o, pos); // t1 = CBC::calculateLength(board, pos, false, ESTIMATE_ALL); // t2 = o.findLengthOfLongestPath(ESTIMATE_ALL); // assert(t1 == t2); // // t1 = CBC::calculateLength(board, pos, false, EXAXT_AREA_BELOW_10); // t2 = o.findLengthOfLongestPath(EXAXT_AREA_BELOW_10); // assert(t1 == t2); // // t1 = CBC::calculateLength(board, pos, false, EXAXT_AREA_BELOW_25); // t2 = o.findLengthOfLongestPath(EXAXT_AREA_BELOW_25); // assert(t1 == t2); // // t1 = CBC::calculateLength(board, pos, false, EXACT); // t2 = o.findLengthOfLongestPath(EXACT); // assert(t1 == t2); // // return; // } nTimes++; cout << "Upper Estimated length : " << upper << endl; timer->reset(); calculatedExact = CBC::calculateLength(board, pos, false, EXACT); assert(calculatedExact != TIMEOUT_POINTS); int timeInMs = timer->getTimeInMs(); cout << "Exact Calculated length : " << calculatedExact << " calculated in " << timeInMs << " ms\n"; exact = exploreMapWithoutRecursion(board, BOARD_SIZE, pos); cout << "Exact length : " << exact << endl; lower = CHeuristicBase::getLowerLengthOfTheLongestPath(board, pos); cout << "Lower Estimated length : " << lower << endl; int travelled = 0; while (true){ if (getAvailableMoves(board, pos).size() == 0) break; timer->reset(); TMove i = CHeuristicBase::getFirstMove(board, pos, EXACT, -1); int temp = CBC::calculateLength(board, pos, false, EXACT); assert(temp != TIMEOUT_POINTS); assert(travelled + temp == exact); travelled++; bOk = move(board, pos, i); assert(bOk); pos = MOVE(pos, i); #ifdef OPENCV imshow("game", toImage(board)); waitKey(1); #endif // OPENCV } cout << "Traveled length : " << travelled << endl << endl; if (lower == exact) lowwer_extract++; if (travelled == exact) traveled_exact++; if (upper > exact) upper_extract++; if (calculatedExact != exact || calculatedExact != travelled || upper < exact) system("pause"); }