int AlphaBeta (const uint64_t P, const uint64_t O, uint64_t& NodeCounter, int alpha, int beta) { const uint64_t empties = Empties(P, O); if (empties == 4) return AlphaBeta_4(P, O, NodeCounter, alpha, beta); uint64_t flipped; uint64_t BitBoardPossible = PossibleMoves(P, O); unsigned long Move; int score = -64; NodeCounter++; if (!BitBoardPossible){ if (HasMoves(O, P)) return -AlphaBeta(O, P, NodeCounter, -beta, -alpha); else //Game is over return BIND(EvalGameOver(P, empties), alpha, beta); } while (BitBoardPossible) { Move = BitScanLSB(BitBoardPossible); RemoveLSB(BitBoardPossible); flipped = flip(P, O, Move); score = -AlphaBeta(O ^ flipped, P ^ (1ULL << Move) ^ flipped, NodeCounter, -beta, -alpha); if (score >= beta) return beta; if (score > alpha) alpha = score; } return alpha; }
void MakeMove(void) { int X,Y, bestX, bestY, d, nosol; if (timelimit1 == 0){ if (debug) fprintf(stderr, "alphabeta depthlimit = %d\n", depthlimit); (void) AlphaBeta(gamestate, depthlimit, -10000000, 10000000, me, &X, &Y); if (debug) fprintf(stderr, "returned X = %d Y = %d\n", X, Y); } else { currenttime = clock(); //get current time deadline = currenttime + timelimit1 * (CLOCKS_PER_SEC / 1000); //calculate by when we need to make a move d = 1; if (debug) fprintf(stderr, "timelimit1 = %d currenttime = %lu deadline = %lu\n", timelimit1, currenttime, deadline); nosol = TRUE; while (currenttime < deadline){ d = d + 1; if (debug) fprintf(stderr, "interation depth = %d\n", d); (void) AlphaBeta(gamestate, d, -10000000, 10000000, me, &bestX, &bestY); if (currenttime < deadline) { //storing the best possible move in the time given X = bestX; Y = bestY; nosol = FALSE; if (debug) fprintf(stderr, "saving move (%d , %d)\n", X, Y); } } if (nosol) error("timelimit too small to find a move\n"); if (debug) fprintf(stderr, "end of iteration at currentime = %lu\n", currenttime); } if (X>=0) { Update(gamestate, me, X, Y); printf("%d %d\n", X, Y); fflush(stdout); } else { printf("pass\n"); fflush(stdout); } if (debug) printboard(gamestate, me, ++turn, X, Y); }
void ComputerThink(void) { short best; nodecount = 0; best = AlphaBeta(-INFINITY, INFINITY, MAX_PLY); //printf("%ld\n",nodecount); }
/* Search game tree by alpha-beta algorith */ short AlphaBeta(short alpha, short beta, short depth) { short i, value, best; if (!depth) return Eval(); Gen(); best = -INFINITY; for (i=gen_begin[ply]; i<gen_end[ply] && best<beta; i++) { if (best > alpha) alpha = best; if (MakeMove(gen_dat[i].m)) value = 1000-ply; else value = -AlphaBeta(-beta, -alpha, depth-1); UnMakeMove(); if (value > best) { best = value; if (!ply) newmove = gen_dat[i].m; } } return best; }
int AlphaBeta(board state, int depth, int alpha, int beta, int player, int * bestX, int * bestY) //AlphaBeta { int X,Y, numacts, i, value; int Xacts[64], Yacts[64]; //maximum of 64 (actually 60) possible moves board child; if (timelimit1){ currenttime = clock(); if (deadline < currenttime) return 0; } if (CutoffTest(state, depth)) return Evaluate(state); numacts = Actions(state, player, Xacts, Yacts); if (player == 1){//the MAX player (us) for (i=0; i<numacts; i++) { Result(state, child, player, Xacts[i], Yacts[i]); value = AlphaBeta(child, depth-1, alpha, beta, -player, &X, &Y); if (timelimit1 && deadline < currenttime) return 0; //checking if we've reached the timelimit if applicable if (value > alpha) { alpha = value; *bestX = Xacts[i]; *bestY = Yacts[i]; } if (beta <= alpha)//beta cut-off break; } return alpha; } else { for (i=0; i<numacts; i++) { Result(state, child, player, Xacts[i], Yacts[i]); value = AlphaBeta(child, depth-1, alpha, beta, -player, &X, &Y); if (timelimit1 && deadline < currenttime) return 0; //checking if we've reached the time limit if applicable if (value < beta) { beta = value; *bestX = Xacts[i]; *bestY = Yacts[i]; } if (beta <= alpha)//alpha cutoff break; } return beta; } }
int CAlphabeta_HHEngine::AlphaBeta(int nDepth, int alpha,int beta) { int score; int Count,i; BYTE type; i=IsGameOver(CurPosition, nDepth); if(i!=0) return i; if(nDepth<=0)//叶子节点取估值 return m_pEval->Eveluate(CurPosition,(m_nMaxDepth-nDepth)%2,m_nUserChessColor); Count=m_pMG->CreatePossibleMove(CurPosition,nDepth,(m_nMaxDepth-nDepth)%2,m_nUserChessColor); if(nDepth==m_nMaxDepth) { //在根节点设定进度条 m_pThinkProgress->SetRange(0,Count); m_pThinkProgress->SetStep(1); } //取所有走法的历史得分 for(i=0;i<Count;i++) m_pMG->m_MoveList[nDepth][i].Score=GetHistoryScore(&m_pMG->m_MoveList[nDepth][i]); MergeSort(m_pMG->m_MoveList[nDepth],Count,0);//对Count种走法按历史得分大小排序 int bestmove=-1;//记录最佳走法的变量 for(i=0;i<Count;i++) { if(nDepth==m_nMaxDepth) m_pThinkProgress->StepIt();//走进度条 type=MakeMove(&m_pMG->m_MoveList[nDepth][i]); score=-AlphaBeta(nDepth-1,-beta,-alpha); UnMakeMove(&m_pMG->m_MoveList[nDepth][i],type); if(score>alpha) { alpha=score; if(nDepth==m_nMaxDepth) m_cmBestMove=m_pMG->m_MoveList[nDepth][i]; bestmove=i; } if(alpha>=beta) { bestmove=i; break; } } if(bestmove!=-1) EnterHistoryScore(&m_pMG->m_MoveList[nDepth][bestmove],nDepth);//将最佳走法汇入历史记录表 return alpha; }
void CChineseChessView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: ÔÚ´ËÌí¼ÓÏûÏ¢´¦Àí³ÌÐò´úÂëºÍ/»òµ÷ÓÃĬÈÏÖµ if (isMouseDown){ isMouseDown=false; CRect rect; GetClientRect(&rect); CPoint logpoint=PhysicalToLogicPoint(point); if (logpoint.x>=0){ //human move Gen(); newmove.from = LogicPointToNum(selectedPoint); newmove.dest = LogicPointToNum(logpoint); for (int i=gen_begin[ply]; i<gen_end[ply]; i++){ if (gen_dat[i].m.from==newmove.from && gen_dat[i].m.dest==newmove.dest){ if(UpdateNewMove()){ UpdateDisplay(rect); int ret; ret=MessageBox("you are really a lucky dog,dare to try again?","Game Over",MB_YESNO); if (ret==IDYES){ NewGame(true); return; }else{ exit(0); } } side = xside; xside = 1-xside; //computer move short best; best = AlphaBeta(-INFINITY, INFINITY, MAX_PLY); if(UpdateNewMove()){ UpdateDisplay(rect); int ret; ret=MessageBox("afraid?dare to try again?","Game Over",MB_YESNO); if (ret==IDYES){ NewGame(true); return; }else{ exit(0); } } side = xside; xside = 1-xside; break; } } } UpdateDisplay(rect); } CView::OnLButtonUp(nFlags, point); }
/* @brief 对当前棋局,计算team在board上放置棋子的最好位置。 @param board 棋局 @param team 要放子的一方 @param depth 搜索最大深度 @return team的最佳放子位置 */ GBIntPoint getAIPos(int **board, PieceTeam team, int depth) { InDepth = depth; AITeam = team; AlphaBeta(board, depth, -INFINIT, INFINIT, team); delete2DIntArray(board); printf("AI piece: %d, %d", BestPiece.r, BestPiece.c); return BestPiece; }
void CAlphabeta_HHEngine::SearchAGoodMove(BYTE position[10][9]) { memcpy(CurPosition, position, 90); m_nMaxDepth = m_nSearchDepth; ResetHistoryTable();//初始化历史记录表 AlphaBeta(m_nMaxDepth, -20000, 20000); m_umUndoMove.cmChessMove = m_cmBestMove; m_umUndoMove.nChessID = MakeMove(&m_cmBestMove); memcpy(position, CurPosition, 90); }
GameMove* AlphaBetaParallel::getNextMove(const GameBoard* board, uint32_t max_depth) { float score; GameMove* move; AlphaBeta(board, 0, max_depth, -1 * std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), score, move); fprintf(stderr, "Turn: %s\n", board->getTurn()==WHITE? "WHITE" : "BLACK"); move->printMove(); fprintf(stderr, "Score: %f\n", score); return move; }
void CAlphaBeta_TTEngine::SearchAGoodMove(BYTE position[][9]) { memcpy(CurPosition,position,90); CalculateInitHashKey(CurPosition);//计算初始棋盘的哈希值 m_nMaxDepth=m_nSearchDepth; AlphaBeta(m_nMaxDepth,-20000,20000); m_umUndoMove.cmChessMove=m_cmBestMove; m_umUndoMove.nChessID=MakeMove(&m_cmBestMove); memcpy(position,CurPosition,90); }
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; }
void G_H::execute(void) { Vm = input(0) - 0.01275; //membrane voltage corrected for junction potential; alpha_1 = AlphaBeta(-2.89e-3, -0.445, 24.02, Vm); beta_1 = AlphaBeta(2.71e-2, -1.024, -17.4, Vm); alpha_2 = AlphaBeta(-3.18e-3, -0.695, 26.72, Vm); beta_2 = AlphaBeta(2.16e-2, -1.065, -14.25, Vm); tau_h_fast = 1.0 / (alpha_1 + beta_1); tau_h_slow = 1.0 / (alpha_2 + beta_2); h_fast_inf = alpha_1 / (alpha_1 + beta_1); h_slow_inf = alpha_2 / (alpha_2 + beta_2); h_fast = h_fast_inf + (h_fast - h_fast_inf) * exp(-DeltaTSec / tau_h_fast); h_slow = h_slow_inf + (h_slow - h_slow_inf) * exp(-DeltaTSec / tau_h_slow); Im = -Gh_max * (0.65 * h_fast + 0.35 * h_slow) * (Vm - Vh_rev); Ih = Im; output(0) = Ih; }
//目前没有用到type,只能用来找黑子 void AlphaBetaEngine::SearchAGoodMove(BYTE position [ ] [ GRID_NUM ],int /*type*/, int & x,int & y) { #ifdef _DEBUG_NUM branchNum = cutoffNum = 0; #endif memcpy(CurPosition, position, GRID_COUNT); AlphaBeta(m_nSearchDepth, -20000, 20000); #ifdef _DEBUG_NUM printf("branchNum %d cutoffNum %d\n", branchNum, cutoffNum); #endif x = m_cmBestMove.StonePos.x; y = m_cmBestMove.StonePos.y; }
// performs an alpha beta search with iterative deepening and returns the best move found int IterSearch(board_t *brd, searchinfo_t *sinfo, int post) { int bestScore = -INFINITE; int bestMove = NO_MOVE; int moveNum = 0; int iterDepth; int i; int tdif = 0; ClrForSearch(brd, sinfo); for(iterDepth = 1; iterDepth <= sinfo->toDepth; iterDepth++) // increase depth for each iteration { if(!sinfo->infinite) tdif = -GetTime(); bestScore = AlphaBeta(brd, -INFINITE, INFINITE, iterDepth, sinfo, true); if(!sinfo->infinite) tdif += GetTime(); // if we received a stop signal, simply break out and use the best move found so far if(sinfo->stop) break; // Fill 'pvLine' with the sequence of best moves found moveNum = GetPvLine(brd, iterDepth); // print some search progress depending on the 'post' format if(post == 1){ printf("%d %d %d %" PRIu64, iterDepth, bestScore, (GetTime()-sinfo->startTime)/10, sinfo->nodes ); for(i = 0; i < moveNum; i++){ printf(" %s", StrXmove(brd->pvLine[i])); } printf("\n"); } else if (post == 2) { printf("score:%7d nodes:%9" PRIu64 " eff: %3d%% ", bestScore, sinfo->nodes, (int)(100*sinfo->fhf/sinfo->fh)); for(i = 0; i < moveNum; i++){ printf("%s ", StrMove(brd->pvLine[i])); } printf("\n"); } bestMove = brd->pvLine[0]; if(!sinfo->infinite && sinfo->startTime + TIME_MULTIPLIER*tdif > sinfo->stopTime) break; } return bestMove; }
int Minimax::AlphaBeta(Board *board, GameInfo *gameInfo, Move &move, int depth, const int quiescenceDepth, int alpha, int beta) { // If we are at the end of the normal alpha beta search, perform a quiescence search with the given quiescence depth. if (depth == 0) return Quiescence(board, gameInfo, quiescenceDepth, alpha, beta); MoveList moveList; // Generate move list and check game state. GameInfo::State state = gameInfo->updateState(board, moveList); switch (state) { case GameInfo::STALEMATE: case GameInfo::FIFTY_MOVE_RULE: // Returns a score which will always be disregarded. return LARGEST_NUM + 1; case GameInfo::CHECKMATE: // Return arbitrarily large negative score (But not -LARGEST_NUM, as it would be cut off). return -LARGE_NUM; } MoveList::iterator bestMoveItr = moveList.begin(); for (MoveList::iterator moveItr = moveList.begin(); moveItr != moveList.end(); moveItr++) { Move childMove = *moveItr; board->executeMove(childMove); // Save any irreversible game info before making a move. GameInfo::Irreversible irreversible(gameInfo); gameInfo->executeMove(childMove); // Here, the child's evaluation is taken to be the negation of its return value, so that seperate if statements for maximising and minimising //aren't required. int childEval = -AlphaBeta(board, gameInfo, move, depth - 1, quiescenceDepth, -beta, -alpha); board->reverseMove(childMove); gameInfo->reverseMove(irreversible); // If the child evaluates to a score greater than or equal to beta, there is a beta cutoff. This means that there is no further point exploring this // node's moves, as it is known that this node will at least be as bad if not worse than another node elsewhere in the game tree. if (childEval >= beta) { // If a non-capture move caused a beta-cutoff, increase its history weighting. The depth squared is added to the heuristic so that moves near //the leaf nodes don't dominate the heuristic (Leaf node score would be 0 * 0). if (!move.isCapture()) Move::HistoryHeuristic[move.subject_from][move.subject_to] += depth * depth; move = *bestMoveItr; return beta; } // If the child's evaluation is greater than alpha, this is the best move at the moment. if (childEval > alpha) { alpha = childEval; bestMoveItr = moveItr; } } move = *bestMoveItr; return alpha; }
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; }
int AlphaBetaEngine::AlphaBeta(int depth, int alpha, int beta) { int side = (m_nSearchDepth - depth)%2; int childNodeCount, score; if(depth <= 0) { return m_pEval->Evaluate(CurPosition, side); } childNodeCount = m_pMG->CreatePossibleMove(CurPosition, depth , side); #ifdef _DEBUG_NUM branchNum += childNodeCount; #endif for (int i=0; i<childNodeCount; i++) { m_pMG->m_MoveList[depth][i].Score = 7 -abs(m_pMG->m_MoveList[depth][i].StonePos.x-m_pMG->m_MoveList[depth][i].StonePos.y); } MergeSort(m_pMG->m_MoveList[depth], childNodeCount); for(int i=0; i<childNodeCount; ++i) { MakeMove(&m_pMG->m_MoveList[depth][i], side); score = -AlphaBeta(depth -1, -beta, -alpha); UnMakeMove(&m_pMG->m_MoveList[depth][i]); if(score >alpha) { alpha = score; if(depth == m_nSearchDepth) { m_cmBestMove = m_pMG->m_MoveList[depth][i]; } if(alpha > beta) { #ifdef _DEBUG_NUM cutoffNum += (childNodeCount -i); #endif break;//cutoff } } } return alpha; }
/* Call AlphaBeta short && display some information */ void ComputerThink(void) { short best; tickstart = clock(); nodecount = 0; best = AlphaBeta(-INFINITY, INFINITY, MAX_PLY); /* Display some information */ tickend = clock(); textcolor(7); gotoxy(50, 4); printf("Depth : %d", MAX_PLY); gotoxy(50, 5); printf("Node total : %ld ", nodecount); gotoxy(50, 6); printf("Brand factor : %.2f ", (float)brandtotal/gencount); gotoxy(50, 7); printf("Time (second) : %.2f ", (tickend-tickstart)/1000.0); gotoxy(50, 8); printf("Nodes per second : %ld ", (long)(nodecount*1000.0/(tickend-tickstart+1))); gotoxy(50, 9); printf("Score : %d ", best); gotoxy(50,11); printf("Computer move : %c%d%c%d ", (char)(newmove.from%SIZE_X+65), (short)(SIZE_X-newmove.from/SIZE_X), (char)(newmove.dest%SIZE_X+65), (short)(SIZE_X-newmove.dest/SIZE_X)); }
GameResult RunAIGame::play(Depth depth, BoardWidth size, RulesType rules, bool contenderFirst) { for (int i=0; i<=1; i++) { PenteGame *p = _players[i]; p->restartGame(); p->setColour(i+1); p->setNormalDepth(depth); p->setBoardSize(size); p->setRules(rules); } int toMove = P1; AlphaBeta ab_games[2] = { AlphaBeta(*_players[0]), AlphaBeta(*_players[1]) }; GameResult res = GameResult(); res._depth = std::to_string((int)depth); res._size = std::to_string((int)size); res._rules = rules; res._contenderP = (contenderFirst ? "P1" : "P2"); Colour winner = EMPTY; while (winner == EMPTY) { Timer tmr; Loc bestMove = ab_games[toMove-1].getBestMove(); if (!_silent) { std::cout << bestMove << std::endl; } res._times[toMove-1] += tmr.elapsed(); assert(_players[0]->isLegalMove(bestMove)); _players[0]->makeMove(bestMove, toMove); _players[1]->makeMove(bestMove, toMove); toMove = otherPlayer(toMove); winner = _players[1]->getWonBy(); if (!_silent) { // TODO: Use another flag for games _players[0]->print(); #if 0 const PriorityLevel &p1Threes = _players[0]->_posStats.getPriorityLevel(P1, Line3); const PriorityLevel &p2Threes = _players[0]->_posStats.getPriorityLevel(P2, Line3); const PriorityLevel &p1Fours = _players[0]->_posStats.getPriorityLevel(P1, Line4); const PriorityLevel &p2Fours = _players[0]->_posStats.getPriorityLevel(P2, Line4); cout << "P1 3s: " << p1Threes.getNumCands() << "; P2 3s: " << p2Threes.getNumCands() << "; P1 4s: " << p1Fours.getNumCands() << "; P2 4s: " << p2Fours.getNumCands() << endl; #endif } } res._winnerWasContender = ((winner==P2) xor contenderFirst); return res; }
Node Janggi::AlphaBeta(Node node, int depth, int alpha, int beta, Turn turn) { if (depth==0 || //terminal node #if WIN32 abs(node.GetValue()) >= (INT_MAX / 2) // win or lose ) { #else fabs(node.GetValue()) >= (INT_MAX/2) // win or lose ) { #endif node.SetLeafValue(node.GetValue()); return node; //only one child. herself. } vector<Node> children = node.GetChildren(turn); int best_value; Node best_node; if (turn == TURN_CHO) { //maximizing player best_value = INT_MIN; best_node.SetLeafValue(best_value); for (Node n : children) { int v = AlphaBeta(n, depth-1, alpha, beta, TURN_HAN).GetLeafValue(); if ( beta <= alpha ) break; // beta cut-off alpha = max(alpha, v); if(v > best_value) { best_value = v; n.SetLeafValue(v); best_node = n; } } } else { //TRUN_HAN . minizing player best_value = INT_MAX; best_node.SetLeafValue(best_value); for (Node n : children) { int v = AlphaBeta(n, depth-1, alpha, beta, TURN_CHO).GetLeafValue(); if ( beta <= alpha ) break; // alpha cut-off beta = min(beta, v); if (v < best_value) { best_value = v; n.SetLeafValue(v); best_node = n; } } } //debug if ( depth == MINMAX_DEPTH) { int i=0; for (Node n: children) { Board b= n.board; printf("%d) %d,%d -> %d,%d\n", i++, n.GetAction().prev.x, n.GetAction().prev.y, n.GetAction().next.x, n.GetAction().next.y); } printf("best : %d,%d -> %d,%d. best_score = %d\n", best_node.GetAction().prev.x, best_node.GetAction().prev.y, best_node.GetAction().next.x, best_node.GetAction().next.y, best_value); } return best_node; }
int AlphaBeta(board_t *brd, int alpha, int beta, int depth, searchinfo_t *sinfo, int null) { if(depth == 0){ //return Eval(brd); return Quiece(brd, alpha, beta, sinfo); } if(!(sinfo->nodes & 0xfff)) CheckUp(sinfo); sinfo->nodes++; ASSERT(CheckBrd(brd)); // if we are not the root of the tree and we have a repetition // or we exceeded the fifty move rule, then we have a draw and return 0 if((IsRep(brd) || brd->fifty >= 100) && brd->ply) return 0; if(brd->ply >= MAXDEPTH-1) return Eval(brd); // if we are too deep, we return // test if we are in check int check = SqAttacked(brd, LOCATEBIT(brd->bb[brd->side][King]), brd->side^1); if(check) depth++; int score = -INFINITE; int pvMain = NO_MOVE; // check the transposition table if we have searched the current position before // if so, return what we found if(TestHashTable(brd, &pvMain, &score, alpha, beta, depth)) return score; // Before we search, we try how we do if we don't make a move // i.e. make a null move if( null && !check && brd->ply && depth >= 4 && (brd->all[brd->side]^brd->bb[brd->side][Pawn]^brd->bb[brd->side][King]) ) { MakeMoveNull(brd); // We cannot do two null moves in a row so we set the null argument here to false score = -AlphaBeta(brd, -beta, -beta + 1, depth-4, sinfo, false); TakeBackNull(brd); if(sinfo->stop){ return 0; } if(score >= beta){ return beta; } } mlist_t list; int i; int legal = 0; int bestMove = NO_MOVE; int bestScore = -INFINITE; int oldAlpha = alpha; score = -INFINITE; GenMoves(brd, &list); // we tested our transposition table for the best move 'pvMain' // if it exists we will set this move as the first move to be searched if(pvMain != NO_MOVE){ if(MakeMove(brd, pvMain)){ score = -AlphaBeta(brd, -beta, -alpha, depth-1, sinfo, true); TakeBack(brd); bestScore = score; if(score > alpha){ if(score >= beta){ if(!(pvMain & FLAGCAP)){ brd->betaMoves[1][brd->ply] = brd->betaMoves[0][brd->ply]; brd->betaMoves[0][brd->ply] = pvMain; } return beta; } alpha = score; bestMove = pvMain; } } /*/ for(i = 0; i < list.len; i++){ if(list.move[i].move == pvMain){ list.move[i].score = 5000000; break; } }//*/ } for(i = 0; i < list.len; i++) // Loop through all moves { if(sinfo->stop) return 0; SelectNextMove(&list, i); if(!MakeMove(brd, list.move[i].move)) continue; legal++; // we have found a legal move so we need not check for mate afterwards // call AlphaBeta in a negamax fashion score = -AlphaBeta(brd, -beta, -alpha, depth-1, sinfo, true); TakeBack(brd); if(score > bestScore){ bestScore = score; if(score > alpha){ if(score >= beta){ if(legal==1) sinfo->fhf++; // count the number of beta cutoffs searched first sinfo->fh++; // compared to all beta cutoffs (measure of efficiency) if(!(list.move[i].move & FLAGCAP)){ brd->betaMoves[1][brd->ply] = brd->betaMoves[0][brd->ply]; brd->betaMoves[0][brd->ply] = list.move[i].move; } // Store the move in the transposition table as a beta (killer) move StorePvMove(brd, bestMove, depth, beta, HFBETA); return beta; } alpha = score; bestMove = list.move[i].move; } } } if(legal == 0){ // We havn't found a legal move if(check){ // if we are in check it is mate; but we want the shortest path // to it so we'll subtract the path length return -MATE + brd->ply; } return 0; // Stalemate } if(oldAlpha != alpha){ // Store exact (normal) transposition entry StorePvMove(brd, bestMove, depth, bestScore, HFEXACT); } else { // Store alpha cutoff transposition entry StorePvMove(brd, bestMove, depth, alpha, HFALPHA); } return alpha; }
Move Engine::IterativeDeepening(int mode, uint64_t wtime, uint64_t btime, uint64_t winc, uint64_t binc, bool print) { int status = pos.getGameStatus(); if(status==STATUS_WHITEMATED || status == STATUS_BLACKMATED || status == STATUS_STALEMATE) { return CONS_NULLMOVE; } vector<Move> moves; pos.generateMoves(moves); if (moves.size() == 1) //only 1 legal move return moves.at(0); //init prepareSearch(); timeMode = mode; AllocatedTime = 1; uint64_t mytime = 1; uint64_t opptime = 1; if (mode == MODE_MOVETIME) { AllocatedTime = wtime; } else { if (pos.turn == COLOR_WHITE) { mytime = wtime; opptime = btime; } else { mytime = btime; opptime = wtime; } AllocatedTime = max((uint64_t)1, mytime / 15); } if(mode==MODE_DEPTH) { MAXDEPTH = wtime; } else { MAXDEPTH = 100; } if (opptime < mytime / 4 && timeMode == MODE_DEFAULT) { AllocatedTime = max((uint64_t)1, mytime / 4); //if opponent is in time trouble lets take our sweet time } #ifdef BLITZKRIEG_DEBUG if(print) cout << "Allocated Time: " << AllocatedTime << endl; #endif vector<Move> line; line.reserve(128); int score = AlphaBeta(1,CONS_NEGINF,CONS_INF,&line,false,false); //int score = think(1,CONS_NEGINF,CONS_INF,&line); //PrincipalVariation = line; int val = 0; int lastscore = 0; timer.Start(); int takeback = 0; int initialmovenumber = pos.movelist.size(); Move bestmove = line.at(line.size()-1); /*for (int i = 0;i < 128;i++) { PrincipalVariation[i] = CONS_NULLMOVE; }*/ //cout << "takeback set " << takeback << " " << PrincipalVariation.size() << endl; takeback = setjmp(env); if(takeback!=0) { while(pos.movelist.size()>initialmovenumber) { pos.takebackMove(); takeback--; } if (print) { cout << "info string "; //cout << "Eval time: " << evaltime.time << ", Sort time: " << sorttime.time << ", Quisc time: " << quisctime.time << ", movegen time: " << movegentime.time << ", Timer: " << timer.ElapsedMilliseconds(); cout << "Nodes: " << nodes << ", Pruned nodes: " << prunednodes << ": " << ((double)(prunednodes * 100) / nodes) << "%, Futility nodes: " << futilitynodes << ": " << ((double)(futilitynodes * 100) / nodes) << "%"; cout << ", Avg. beta: " << ((double)betacutoff_sum / betacutoff_counter); cout << ", First beta: " << ((double)(firstbetacutoffcount*100) / betacutoff_counter) << "%"; cout << ", Latemove researches: " << latemoveresearch; cout << ", PV researches: " << pvresearch; //cout << ", Bad null: " << badavoidnull; cout << ", Aspiration Resets: " << aspirationresets; cout << ", Nullcutoffs: " << nullcutoffs; /*cout << ", Avg. alpha first: " << ((double)alphafirst_sum / alpha_counter); cout << ", Avg. alpha last: " << ((double)alphalast_sum / alpha_counter);*/ cout << ", Fake Hits: " << ((double)(Table.hits * 100) / nodes); cout << ", TT hits: " << tthitcount << ": " << ((double)(tthitcount * 100) / nodes) << "%" << endl; Table.hits = 0; } /*if (PvSize < 0) { cout << "info string ERROR: pv size is 0\n"; return CONS_NULLMOVE; }*/ ply = 0; return bestmove; } incheck[0] = pos.underCheck(pos.turn); for (int i = 2;i <= MAXDEPTH;i++) { //mr = think(i,CONS_NEGINF,CONS_INF); //mr = think(i,score - 100,score + 100); //aspiration search //if(mr.eval <= score-150 || mr.eval >= score+150) //{ // cout << "Aspiration fail " << mr.eval << endl; // mr = think(i,CONS_NEGINF,CONS_INF); //} //int low = 8; //int high = 8; /*PvSize = -1; PvPly = -1;*/ int delta = 32; int alpha = max(score - delta, int(CONS_NEGINF)); int beta = min(score + delta, int(CONS_INF)); while (true) { //line = deque<Move>(); ply = 0; //PvSize = -1; line.clear(); val = AlphaBeta(i, alpha, beta, &line, true, true); checkup(); //cout << "asp. " << alpha << " " << beta << endl; /*for (int i = 0;i < 2;i++) { for (int j = 0;j < 100;j++) { KillerScores[i][j] = CONS_NEGINF; } }*/ if (val <= alpha) { beta = (alpha + beta) / 2; alpha = max(score - delta, int(CONS_NEGINF)); //cout << "val is " << val << endl; //low = low << 1; } else if (val >= beta) { alpha = (alpha + beta) / 2; beta = min(score + delta, int(CONS_INF)); //cout << "val is " << val << endl; //high = high << 1; } else break; delta += delta / 2; aspirationresets++; } lastscore = score; score = val; assert(score > CONS_NEGINF && score < CONS_INF); timer.Stop(); if (print) { cout << "info score cp " << score << " depth " << i << " seldepth " << SelectiveDepth << " nodes " << nodes << " nps " << getNPS(nodes, timer.ElapsedMilliseconds()) << " time " << timer.ElapsedMilliseconds() << " pv "; for (int j = line.size() - 1;j >= 0;j--) { cout << line.at(j).toString() << " "; } cout << endl; /*for (int j = 0;j < 128;j++) { if (PrincipalVariation[j].isNullMove()) break; cout << PrincipalVariation[j].toString() << " "; }*/ } PrincipalVariation = line; bestmove = line.at(line.size()-1); if (timeMode == MODE_DEFAULT) { if (score > lastscore + 100 || score < lastscore - 100) //score changed? allocate more time { AllocatedTime = min(AllocatedTime + mytime / 30, max((uint64_t)1, mytime / 4)); } } } if (print) { cout << "Nodes: " << nodes << endl; cout << "info string Eval time: " << evaltime.ElapsedMilliseconds() << ", Sort time: " << sorttime.ElapsedMilliseconds() << ", Quisc time: " << quisctime.ElapsedMilliseconds() << ", movegen time: " << movegentime.ElapsedMilliseconds() << endl; } /*if (PvSize < 0) { cout << "info string ERROR: principal variation size is 0\n"; return CONS_NULLMOVE; }*/ //Move bestmove = PrincipalVariation[0]; ply = 0; return bestmove; }
void IterativeDeep(BOARD *board, CONTROL *control) { MOVE iPV[PVLEN]; char sPV[SPVLEN]; char str_mov[MVLEN]; int eval = 0, pvlen = 0; int alpha = -INFINITE; int beta = INFINITE; int widening = ASP_WINDOW; unsigned long long nps = 0; MOVE killers[MAXDEPTH][2]; control->best_move = 0; /*printf("time %llu %llu\n", control->max_time, control->wish_time);*/ for(unsigned int depth = 1; depth <= control->max_depth;){ clock_t curr_time = clock(); memset(sPV, 0, SPVLEN); control->node_count = 0; eval = AlphaBeta(board, depth, alpha, beta, 0, control, 1, killers); if(control->stop && !control->ponder){ break; } pvlen = RetrievePV(board, iPV, depth+10); for(int i = 0; i < pvlen; i++){ MoveToAlgeb(iPV[i], str_mov); strcat(sPV, str_mov); } curr_time = (clock() - curr_time)/CPMS; if(curr_time){ nps = 1000*(control->node_count/curr_time); } if(eval > MATE_VALUE/2 && -eval > MATE_VALUE/2){ printf("info depth %u time %llu nodes %llu nps %llu score cp %i pv %s\n", depth, (unsigned long long)curr_time, control->node_count, nps, eval, sPV); }else if(-eval < MATE_VALUE/2){ printf("info depth %u time %llu nodes %llu nps %llu score mate %i pv %s\n", depth, (unsigned long long)curr_time, control->node_count, nps, (pvlen+1)/2, sPV); }else if(eval < MATE_VALUE/2){ printf("info depth %u time %llu nodes %llu nps %llu score mate %i pv %s\n", depth, (unsigned long long)curr_time, control->node_count, nps, -(pvlen+1)/2, sPV); } if(eval <= alpha || eval >= beta){ alpha = -INFINITE; beta = INFINITE; }else{ if(3*curr_time > control->wish_time*CPMS - (clock()-control->init_time)){ control->stop = 1; } alpha = eval - ASP_WINDOW; beta = eval + ASP_WINDOW; depth++; } } control->stop = 1; MoveToAlgeb(control->best_move, str_mov); printf("bestmove %s", str_mov); if(pvlen > 1){ MoveToAlgeb(iPV[1], str_mov); printf("ponder %s", str_mov); } printf("\n"); }
/* alpha (lower bound): Keeps track of the highest score obtained at a * maximizing node higher up in the tree and is used to perform cut-offs at * minimizing nodes. * beta (upper bound): Keeps track of the lowest score obtained at a * minimizing node higher up in the tree and is used to perform cut-offs at * maximizing nodes. */ bool AlphaBetaParallel::AlphaBeta(const GameBoard* board, uint32_t depth, uint32_t max_depth, float alpha, float beta, float& chosen_score, GameMove*& chosen_move) { // if we've reached the leaves, evaluate board if (depth == max_depth) { chosen_score = game_->evaluateBoard(board); return true; } // initialize scores float score; if (board->getTurn() == WHITE) score = alpha; else score = beta; // initialize chosen move chosen_move = NULL; // generate all possible moves std::list<GameMove*> moves_list; game_->generateMoves(board, moves_list); if (moves_list.empty()) { chosen_score = game_->evaluateBoard(board); return true; } // calculate the PVS std::list<GameMove*>::iterator it = moves_list.begin(); { GameBoard* new_board; GameMove* new_move; float game_tree_value; game_->applyMove(board, new_board, *it); // find score of new position if (board->getTurn() == WHITE) { AlphaBeta(new_board, depth + 1, max_depth, score, beta, game_tree_value, new_move); if (game_tree_value >= beta) { chosen_move = *it; // CORRECT? chosen_score = beta; } else if (game_tree_value > score) { score = game_tree_value; chosen_move = *it; } } else { AlphaBeta(new_board, depth + 1, max_depth, alpha, score, game_tree_value, new_move); if (game_tree_value <= alpha) { chosen_score = alpha; chosen_move = new_move; } else if (game_tree_value < score) { score = game_tree_value; chosen_move = *it; } } delete new_board; } it++; std::list<GameMove*>::iterator mov_it; std::vector<GameMove*> mvec; for ( ; it != moves_list.end(); ++it) mvec.push_back(*it); bool pruned = false; #pragma omp parallel \ private(score) \ shared(board, depth, max_depth, alpha, beta, pruned) { #pragma omp for for (uint32_t i=0; i<mvec.size(); i++) { #pragma omp flush (pruned) if (!pruned) { // generate new board position GameBoard* new_board; GameMove* new_move; float game_tree_value; game_->applyMove(board, new_board, mvec[i]); // find score of new position if (board->getTurn() == WHITE) { AlphaBeta(new_board, depth + 1, max_depth, score, beta, game_tree_value, new_move); #pragma omp flush (beta) if (game_tree_value >= beta) { #pragma omp critical chosen_move = mvec[i]; // CORRECT? chosen_score = beta; pruned = true; } if (game_tree_value > score) { #pragma omp critical score = game_tree_value; chosen_move = mvec[i]; } } else { AlphaBeta(new_board, depth + 1, max_depth, alpha, score, game_tree_value, new_move); #pragma omp flush (alpha) if (game_tree_value <= alpha) { #pragma omp critical chosen_score = alpha; chosen_move = new_move; pruned = true; } if (game_tree_value < score) { #pragma omp critical score = game_tree_value; chosen_move = mvec[i]; } } delete new_board; } } } if (!pruned) chosen_score = score; it = moves_list.begin(); for ( ; it != moves_list.end(); ++it) if (*it != chosen_move) delete *it; return true; }
static int AlphaBeta(BOARD *board, unsigned int depth, int alpha, int beta, int root, CONTROL *control, char skip_null, MOVE killers[][2]) { int nmoves, nlegal = 0; MOVE moves[MAXMOVES]; MOVE best_move = 0; char str_mov[MVLEN]; int val = ERRORVALUE; char hash_flag = HASH_ALPHA; int reduce = 0, LMR = 0; if(depth){ if(root > 0){ val = GetHashEval(&hash_table, board->zobrist_key, depth, alpha, beta); if(val != ERRORVALUE) return val; } if(depth > 2 && !InCheck(board, 0)){ if(!skip_null && board->piece_material[board->white_to_move] != 0){ MOVE null_mv = NULL_MOVE; MakeMove(board, &null_mv); val = -AlphaBeta(board, depth-3, -beta, -beta+1, root+1, control, 1, killers); Takeback(board, null_mv); if(val >= beta) return beta; } reduce = 1; /*Try Late Move reductions.*/ } nmoves = MoveGen(board, moves, 1); int good = SortMoves(board, moves, nmoves, killers[root]); for(int i = 0; i < nmoves; i++){ MakeMove(board, &moves[i]); control->node_count++; if(!LeftInCheck(board)){ if(root == 0){ if(!control->best_move) control->best_move = moves[i]; /* Better than nothing. */ if(depth > 6 && !control->ponder){ MoveToAlgeb(moves[i], str_mov); printf("info depth %i hashfull %i currmove %s currmovenumber %i\n", depth, hash_table.full/(hash_table.size/1000), str_mov, i+1); } } nlegal++; val = AssesDraw(board); if(val) { if(best_move){ LMR = (reduce && i > good && !CAPTMASK(moves[i]) && !InCheck(board, 0)) ? 1 : 0; val = -AlphaBeta(board, depth-LMR-1, -alpha-1, -alpha, root+1, control, 0, killers); if(val > alpha){ val = -AlphaBeta(board, depth-1, -alpha-1, -alpha, root+1, control, 0, killers); if(val > alpha && val < beta){ val = -AlphaBeta(board, depth-1, -beta, -alpha, root+1, control, 0, killers); } } }else val = -AlphaBeta(board, depth-1, -beta, -alpha, root+1, control, 0, killers); } Takeback(board, moves[i]); if(!control->ponder && control->stop) return alpha; if(val >= beta){ UpdateTable(&hash_table, board->zobrist_key, val, moves[i], depth, HASH_BETA); if(CAPTMASK(moves[i]) == 0 && killers[root][0] != moves[i] && killers[root][1] != moves[i]){ killers[root][1] = killers[root][0]; killers[root][0] = moves[i]; } return beta; } if(val > alpha){ alpha = val; hash_flag = HASH_EXACT; best_move = moves[i]; if(root == 0) control->best_move = best_move; } if(root == 0 && ((clock() - control->init_time) > control->wish_time*CPMS)){ /* if short of time, don't search anymore after current move */ control->stop = 1; return alpha; } }else Takeback(board, moves[i]); } if(nlegal == 0){ if(InCheck(board, 0)){ /*UpdateTable(&hash_table, board->zobrist_key, MATE_VALUE+root, 0, depth, HASH_EXACT, hash_table.entries);*/ return MATE_VALUE; }else{ /*UpdateTable(&hash_table, board->zobrist_key, DRAW_VALUE, 0, depth, HASH_EXACT, hash_table.entries);*/ return DRAW_VALUE; /*Stalemate*/ } }else UpdateTable(&hash_table, board->zobrist_key, alpha, best_move, depth, hash_flag); }else if(InCheck(board, 0)){ alpha = AlphaBeta(board, 1, alpha, beta, root+1, control, 1, killers); }else{ alpha = Quiescent(board, alpha, beta, root, control, killers); } return alpha; }
/* @brief alpah-beta搜索函数,寻找最适合的一个放子点 @param board 棋局 @param depth 当前深度 @param alpha MAX结点的搜索下限 @param beta MIN结点的搜索上限 @param team 当前要下子的一方 @return 此时的alpha值 */ int AlphaBeta(int **oriBoard, int depth, int alpha, int beta, PieceTeam team) { int **board = copy2DIntArray(oriBoard, kBoardRow, kBoardCol); if (depth == 0) { // 评估分综合双方棋局得到 int s1 = Evaluate(board, team); int s2 = Evaluate(board, AnotherTeam(team)); int score = s1-s2; return score; } SeqIntPt candi = getCandidate(board); // 先对所有可扩展结点进行估价,并排序 SortType sortedCandi; for (SeqIntPt::iterator iter=candi.begin(); iter!=candi.end(); ++iter){ int score = sortEvaluation(board, team, *iter); sortedCandi.insert(SortNode(score, iter->r, iter->c)); } // 根据启发函数对可扩展结点排序后的顺序来扩展 for(SortType::iterator it=sortedCandi.begin(); it!=sortedCandi.end(); ++it) { GBIntPoint pos = it->pos; if (board[pos.r][pos.c] != PieceTeamNone) continue; board[pos.r][pos.c] = team; // 第一层的剪枝优化:如果己方或对方在此处有必赢棋局,直接放在此处 if (depth == InDepth) { int tscore = oneStepEvaluation(board, team, pos); // printf("candidate: %d, %d; score: %d\n",pos.r, pos.c, tscore); if (tscore>alpha){ //评分80及以上的局势都是必赢的局 // for (int i=kBoardRow-1; i>=0; --i) { // for (int j=0; j<kBoardCol; ++j) { // printf("%d ", board[i][j]); // } // printf("\n"); // } // printf("%d\n", tscore); // Evaluate(board, team); alpha = tscore; BestPiece.r = pos.r; BestPiece.c = pos.c; } } // 递归搜索 int val = -AlphaBeta(board, depth - 1, -beta, -alpha, AnotherTeam(team)); // 还原现场 board[pos.r][pos.c] = PieceTeamNone; // alpha-beta 剪枝 if (val >= beta) { delete2DIntArray(board); return beta; } if (val>alpha && board[pos.r][pos.c]==PieceTeamNone) { alpha = val; if (depth == InDepth){ // 第一层,更新最优位置 BestPiece.r = pos.r; BestPiece.c = pos.c; } } } delete2DIntArray(board); return alpha; }
static int AlphaBeta (BOARD *board, int depth, int alpha, int beta, int root, CONTROL *control, char skip_null, MOVE killers[][2]) { int nmoves, good = 0, nlegal = 0; MOVE moves[MAXMOVES]; MOVE best_move = 0; char str_mov[MVLEN]; int val = ERRORVALUE; char hash_flag = HASH_ALPHA; int in_check = InCheck(board, 0); if (root > control->seldepth) control->seldepth = root; if (depth > 0 || in_check) { if (root > 0) { val = GetHashEval(&hash_table, board->zobrist_key, depth, alpha, beta); if (val != ERRORVALUE) return val; } if (depth > 2 && !in_check) { if (!skip_null && board->piece_material[board->white_to_move] != 0) { MOVE null_mv = NULL_MOVE; MakeMove(board, &null_mv); val = -AlphaBeta(board, depth-3, -beta, -beta+1, root+1, control, 1, killers); Takeback(board, null_mv); if (val >= beta) return beta; } } nmoves = MoveGen(board, moves, 1); good = SortMoves(board, moves, nmoves, killers[root]); } else { if (!control->ponder && clock() - control->init_time >= control->max_time*CPMS) { control->stop = 1; } val = LazyEval(board); if (val-LAZYBETA >= beta) return beta; if (val+LAZYALPHA < alpha) return alpha; val = StaticEval(board); UpdateTable(&hash_table, board->zobrist_key, val, 0, 0, HASH_EXACT); if (val >= beta) return beta; if (val > alpha) alpha = val; nmoves = CaptureGen(board, moves); nmoves = FilterWinning(board, moves, nmoves); } for (int i = 0; i < nmoves; i++) { MakeMove(board, &moves[i]); control->node_count++; if (LeftInCheck(board)) { Takeback(board, moves[i]); continue; } if (root == 0) { if (!control->best_move) control->best_move = moves[i]; /* Better than nothing. */ if (depth > 6 && !control->ponder) { MoveToAlgeb(moves[i], str_mov); printf("info depth %i seldepth %i hashfull %i currmove %s currmovenumber %i\n", depth, control->seldepth, hash_table.full/(hash_table.size/1000), str_mov, i+1); } } nlegal++; val = AssessDraw(board, control->contempt); if (val == ERRORVALUE) { int ext = 0; //InCheck(board, 0) ? 1 : 0; if (best_move) { int LMR = (depth > 2 && !in_check && i > good && !CAPTMASK(moves[i]) && !InCheck(board, 0)) ? 1 : 0; val = -AlphaBeta(board, depth+ext-LMR-1, -alpha-1, -alpha, root+1, control, 0, killers); if (val > alpha) { val = -AlphaBeta(board, depth+ext-1, -alpha-1, -alpha, root+1, control, 0, killers); if (val > alpha && val < beta) { val = -AlphaBeta(board, depth+ext-1, -beta, -alpha, root+1, control, 0, killers); } } } else { val = -AlphaBeta(board, depth+ext-1, -beta, -alpha, root+1, control, 0, killers); } } Takeback(board, moves[i]); if (!control->ponder && control->stop) return alpha; if (val >= beta) { UpdateTable(&hash_table, board->zobrist_key, val, moves[i], depth, HASH_BETA); if (CAPTMASK(moves[i]) == 0 && killers[root][0] != moves[i] && killers[root][1] != moves[i]) { killers[root][1] = killers[root][0]; killers[root][0] = moves[i]; } return beta; } if (val > alpha) { alpha = val; hash_flag = HASH_EXACT; best_move = moves[i]; if (root == 0) control->best_move = best_move; } if (root == 0 && ((clock() - control->init_time) > control->wish_time*CPMS)) { /* if short of time, don't search anymore after current move */ control->stop = 1; return alpha; } } if (nlegal == 0) { if (in_check) { /*UpdateTable(&hash_table, board->zobrist_key, MATE_VALUE+root, 0, depth, HASH_EXACT, hash_table.entries);*/ return MATE_VALUE; } else if (depth > 0) { /*UpdateTable(&hash_table, board->zobrist_key, DRAW_VALUE, 0, depth, HASH_EXACT, hash_table.entries);*/ return DRAW_VALUE; /*Stalemate*/ } } else { UpdateTable(&hash_table, board->zobrist_key, alpha, best_move, depth, hash_flag); } return alpha; }
int CAlphaBeta_TTEngine::AlphaBeta(int nDepth, int alpha, int beta) { int score; int Count,i; BYTE type; int side; i=IsGameOver(CurPosition,nDepth); if(i!=0) return i; //察看当前节点是否在置换表中有有效数据 side=(m_nMaxDepth-nDepth)%2; score=LookUpHashTable(alpha,beta,nDepth,side); if(score!=66666) return score;//命中,直接返回表中的值 //叶子节点取估值 if(nDepth<=0) { score=m_pEval->Eveluate(CurPosition,side,m_nUserChessColor); EnterHashTable(exact,score,nDepth,side);//将求得的估值放进置换表 return score; } Count=m_pMG->CreatePossibleMove(CurPosition,nDepth,side,m_nUserChessColor); if(nDepth==m_nMaxDepth) { //在根节点设定进度条 progress->setTotalSteps(Count); progress->setProgress(1); } int eval_is_exact=0;//数据类型标志 for(i=0;i<Count;i++)//对当前节点的下一步每一可能的走法 { if(nDepth==m_nMaxDepth) progress->nextStep(); Hash_MakeMove(&m_pMG->m_MoveList[nDepth][i],CurPosition);//产生该走法所对应子节点的哈希值 type=MakeMove(&m_pMG->m_MoveList[nDepth][i]); //产生子节点 score=-AlphaBeta(nDepth-1,-beta,-alpha);//递归搜索子节点 Hash_UnMakeMove(&m_pMG->m_MoveList[nDepth][i],type,CurPosition);//恢复当前节点的哈希值 UnMakeMove(&m_pMG->m_MoveList[nDepth][i],type); //撤销子节点 if(score>=beta)//beta剪枝 { EnterHashTable(lower_bound,score,nDepth,side);//将节点下边界存入置换表 return score;//返回下边界 } if(score>alpha) { alpha=score; //取最大值 eval_is_exact=1;//设定确切值标志 if(nDepth==m_nMaxDepth) m_cmBestMove=m_pMG->m_MoveList[nDepth][i]; } } //将搜索结果放进置换表 if(eval_is_exact) EnterHashTable(exact,alpha,nDepth,side); //确切值 else EnterHashTable(upper_bound,alpha,nDepth,side);//上边界 return alpha;//返回最佳值/上界 }
int AlphaBeta(int depth, int alpha, int beta, int turn)// turn=1 if blue; else 0; { int val; int * legal_columns; int * legal_pieces; int max_legal; int i; /*check win*/ val = checkComp(evaluated_column, total_rows, board); if (val != 0) // if finds win, return { #ifdef ZZZ printf("FOUND WIN: column%d val:%d\n", evaluated_column, val); dispboard(); #endif return val; } if(depth == 0) { val = Evaluate(); return val; } /* GenerateLegalMoves(); */ max_legal = 0; legal_columns = (int*)calloc(columns*2,sizeof(int)); if (legal_columns == NULL) return alpha; legal_pieces = (int*)calloc(columns*2,sizeof(int)); if (legal_pieces == NULL) { free(legal_columns); return alpha; } if (turn == 1) { for (i = 0; i < columns; i++) { if (board[order[i] * total_rows + rows - 1] == SPACE) { legal_columns[max_legal] = order[i]; legal_pieces[max_legal++] = BLUE; legal_columns[max_legal] = order[i]; legal_pieces[max_legal++] = GREEN; } } } else { for (i = 0; i < columns; i++) { if (board[order[i] * total_rows + rows - 1] == SPACE) { legal_columns[max_legal] = order[i]; legal_pieces[max_legal++] = RED; legal_columns[max_legal] = order[i]; legal_pieces[max_legal++] = GREEN; } } } turn = turn==1?0:1; // swithch turn if(max_legal == 0)// full board return alpha; /* while (MovesLeft()) { */ for (i = 0; i < max_legal; i++) { /* MakeNextMove(); */ AddToBoard(legal_columns[i], legal_pieces[i]); /* val = Min(depth - 1); */ evaluated_column = legal_columns[i]; /* FOR DEBUGGING */ /* FOR DEBUGGING */ static int count = 0; #ifdef ZZZ printf("\t\tMAX called %d times.\n", ++count); dispboard(); #endif /* FOR DEBUGGING */ /* FOR DEBUGGING */ val = -AlphaBeta(depth-1, -beta, -alpha, turn); #ifdef ZZZ printf("MAX::Depth:%d column:%d piece:%d val:%d best:%d\n", maxdepthval - depth, evaluated_column, legal_pieces[i], val, alpha); #endif /* UnmakeMove(); */ RemoveFromBoard(legal_columns[i]); /* if (val > best) */ /* best = val; */ if (val > alpha) { alpha = val; if (depth == maxdepthval) { piece = legal_pieces[i]; column = legal_columns[i]; // if(best == 1000)// blocking case // piece = BLUE; #ifdef ZZZ printf("MAX::Best has changed:%d, column:%d, piece:%d \n", alpha, column, piece); #endif } } /* } */ } free(legal_columns); free(legal_pieces); return alpha; }