int quiescence(int alpha, int beta) { int static_evaluation = evaluate(alpha, beta); if(static_evaluation >= beta) return beta; if(static_evaluation > alpha) alpha = static_evaluation; Move movelist[256]; int n = generate_captures(movelist); sorting_captures(movelist, n); for(int i = 0; i < n; i += 1) { Move i_move = movelist[i]; make_move(i_move); int score = -quiescence(-beta, -alpha); unmake_move(i_move); if(score >= beta) { return beta; } if(score > alpha) { alpha = score; } } return alpha; }
int PVS(int alpha, int beta, int depth) { if(is_draw_by_repetition_or_50_moves()) return DRAW; if(depth == 0) return quiescence(alpha, beta); Move movelist[256]; int n = generate_moves(movelist); if(n == 0) { if(!in_check(turn_to_move)) return DRAW; return LOSING + ply - begin_ply; } sorting_moves(movelist, n); int bool_search_pv = 1; Move bestmove = 0; for(int i = 0; i < n; i += 1) { Move i_move = movelist[i]; make_move(i_move); int score; if(bool_search_pv) { score = -PVS(-beta, -alpha, depth - 1); } else { score = -ZWS(-alpha, depth - 1, 1); if(score > alpha) score = -PVS(-beta, -alpha, depth - 1); } unmake_move(i_move); if(score >= beta) { hash_save_entry(depth, beta, i_move, MORE_THAN_BETA); if(!move_broken(i_move)) { history[board[move_from(i_move)]][move_to(i_move)] = depth * depth; } return beta; } if(score > alpha) { bestmove = i_move; alpha = score; } bool_search_pv = 0; } if(bestmove != 0) hash_save_entry(depth, alpha, bestmove, BETWEEN_ALPHA_AND_BETA); else hash_save_entry(depth, alpha, 0, LESS_THAN_ALPHA); return alpha; }
int ZWS(int beta, int depth, int can_reduce) { if(is_draw_by_repetition_or_50_moves()) return DRAW; Entry *entry = hash_get_entry(); if(entry != NULL && entry->depth >= depth) { int eval = entry->eval, flag = entry->flag; if(flag != LESS_THAN_ALPHA && eval >= beta) return beta; if(flag != MORE_THAN_BETA && eval < beta) return beta - 1; } if(depth == 0) return quiescence(beta - 1, beta); /*if(depth <= 6 && evaluate(beta - 1, beta) >= beta) { return beta; }*/ if(depth > 2 && can_reduce && !in_check(turn_to_move)) { int R = depth > 6 ? 3: 2; make_null_move(); int score = -ZWS(-beta + 1, depth - R - 1, 0); unmake_null_move(); if(score >= beta) return beta; } Move movelist[256]; int n = generate_moves(movelist); if(n == 0) { if(!in_check(turn_to_move)) return DRAW; return LOSING + ply - begin_ply; } sorting_moves(movelist, n); for(int i = 0; i < n; i += 1) { Move i_move = movelist[i]; make_move(i_move); int score = -ZWS(-beta + 1, depth - 1, can_reduce); unmake_move(i_move); if(score >= beta) { hash_save_entry(depth, beta, i_move, MORE_THAN_BETA); return beta; } } hash_save_entry(depth, beta - 1, 0, LESS_THAN_ALPHA); return beta - 1; }
/* Quiescence Search */ move_t quiescence(board_t *b, int32_t alpha, int32_t beta) { uint8_t i; move_t m, best; move_list_t *list; /* Initialize the best possible move as blank */ SET_BLANK_MOVE(best); m.eval = heuristic(b, onmove); if(m.eval >= beta) { best.eval = m.eval; return best; } else if(m.eval > alpha) { alpha = m.eval; } /* Get the next possible Good captures only */ list = gen_move_list(b, TRUE); /*TODO: Re-order the move list (SEE - Static Exchange Eval) */ /*reorder_move_list(b, list); */ /* For each possible next move... */ for(i = 0; i < list->size; i++) { /* Let's see the board after that move... */ move(b, list->move[i]); /* Quiescence Search recursion */ m = quiescence(b, -beta, -alpha); m.eval = -m.eval; /* Restores the previous board (before the possible move) */ unmove(b); /* Beta cutoff */ if(m.eval >= beta) { best = list->move[i]; best.eval = m.eval; break; /* Alpha cutoff */ } else if(m.eval > alpha) { best = list->move[i]; alpha = best.eval = m.eval; /* Best possible move until now */ } else if(i == 0 || m.eval > best.eval) { best = list->move[i]; best.eval = m.eval; } } /* Clear temporary information and return */ clear_move_list(list); return best; }
int Board::alphaBeta(int depthLeft, int alpha, int beta, int doNullMove) { int check = 0; int oldAlpha = alpha; int numSearched = 0; int bestMove = 0; int hashMove = 0; int stage; int i = currentState->firstMove; int result; nodes++; nodesUntilUpdate--; if(nodesUntilUpdate <= 0) { switch(game->interfaceUpdate()) { case OUT_OF_TIME: abortingSearch = 1; return 0; break; case STOP_SEARCH: abortingSearch = 1; return 0; break; } nodesUntilUpdate = nodesPerUpdate; } if(isRepetition()) { returnMove = 0; return DRAW; } HashEntry *e; e = hash->probe(currentState->hashKey); if(e!=NULL) { hashHits++; //Is it useful for replacing this search - otherwise just find a best move hashMove = e->bestMove; returnMove = hashMove; #ifndef DISABLE_HASH if(depth > 0 && e->depth >= depthLeft) { switch(e->flags & 3) { case HASH_EXACT: return e->score; break; case HASH_LOWER: if(e->score >= beta) return e->score; if(e->score > alpha) alpha = e->score; break; case HASH_UPPER: if(e->score <= alpha) return e->score; if(e->score < beta) beta = e->score; break; } if(e->flags & HASH_NO_NULL) { doNullMove = 0; } } #endif } #ifdef DEBUG_HASH if(hashMove > 0 && !testLegality(hashMove)) { print(); cout << "Illegal hash move! "; printMove(hashMove); cout << endl; } #endif if(depthLeft == 0) { int value = quiescence(alpha, beta); //hash->store(0, value, 0, HASH_EXACT); return value; } check = inCheck(); /* if(doNullMove && !check && !nullRisk() && depth >= 2) { int nullDepth = depthLeft - 2; makeNullMove(); if(nullDepth > 0) { result = alphaBeta(nullDepth, -beta, -beta+1, NO_NULL_MOVE); } else { result = quiescence(-beta, -beta+1); } retractNullMove(); if(nullDepth > 0 && result >= beta) { result = alphaBeta(nullDepth, beta-1, beta, DO_NULL_MOVE); numMoves = currentState->firstMove; } if(result >= beta) { returnMove = 0; return beta; } } */ if(!hashMove && depthLeft >= 3) { result = alphaBeta(depthLeft - 2, alpha, beta, DO_NULL_MOVE); numMoves = currentState->firstMove; //Failed low so have to research with new bounds if(result <= alpha) result = alphaBeta(depthLeft - 2, -MATE, alpha + 1, DO_NULL_MOVE); numMoves = currentState->firstMove; hashMove = returnMove; } if(hashMove > 0) { stage = HASH_MOVE; } else { stage = ALL_MOVES; } while(stage != FINISHED) { switch(stage) { case HASH_MOVE: moveStack[numMoves++] = hashMove; stage = ALL_MOVES; break; case ALL_MOVES: if(check) { generateCheckEvasions(); sortNonCaptures(i, hashMove); stage = FINISHED; } else { generateCaptures(); sortCaptures(i, hashMove); stage = NON_CAPTURES; } break; case NON_CAPTURES: generateNonCaptures(); sortNonCaptures(i, hashMove); stage = FINISHED; break; } for(; i<numMoves; i++) { int move = moveStack[i]; makeMove(move); #ifdef DEBUG_BITBOARDS if(isMessedUp()) { printMoves(); print(); cout << "Hash move = "; printMove(hashMove); cout << endl; cout << "MakeMove" << endl; exit(0); } #endif if(isLegal()) { numSearched++; result = -alphaBeta(depthLeft - 1, -beta, -alpha, DO_NULL_MOVE); retractMove(move); if(abortingSearch) { returnMove = bestMove; return result; } if(result > alpha) { if(result >= beta) { returnMove = move; hash->store(move, result, depthLeft, HASH_LOWER); #ifdef EXTRA_STATS cutoffs++; if(i == currentState->firstMove) firstCutoffs++; #endif return result; } /* if(depth == 0) { printMove(move); cout << " "; printScore(result); cout << " hashMove: "; printMove(hashMove); cout << endl; }*/ alpha = result; bestMove = move; } } else { //Illegal move retractMove(move); } #ifdef DEBUG_BITBOARDS if(isMessedUp()) { printMoves(); print(); cout << "Hash move = "; printMove(hashMove); cout << endl; cout << "RetractMove" << endl; exit(0); } #endif } } //While we have moves //No legal moves.. if(numSearched ==0) { returnMove = 0; if(check) { return -(MATE - depth); } else { return DRAW; } } if(alpha == oldAlpha) { hash->store(bestMove, alpha, depthLeft, HASH_UPPER); } else { hash->store(bestMove, alpha, depthLeft, HASH_EXACT); } returnMove = bestMove; return alpha; }
int BOARD::quiescence(int alpha,int beta) { if((info.nodes & 2047) ==0) check(); info.nodes++; if(repeat() || fifty >=100) return 0; if(ply >MAXDEPTH -1) return evaluate(); int value=evaluate(); if(value >= beta) return beta; if(value >alpha) alpha=value; int legal=0; int oldalpha=alpha; int bestmove=NOMOVE; int score=-INFINITE; MOVE_LIST moveList; moveList.count=0; generateAllCap(moveList); std::sort(moveList.l,moveList.l+moveList.count,so); for(int i=0;i<moveList.count;i++) { //pickBest(i,moveList); if(!makeMove(moveList.l[i].move)) continue; score=-quiescence(-beta,-alpha); unmakeMove(); if(info.stopped) return 0; legal++; if(score >alpha) { if(score >=beta) { if(legal==1) info.fhf++; info.fh++; return beta; //beta - cutoff } alpha=score; bestmove=moveList.l[i].move; } } if(alpha != oldalpha) storePv(bestmove); return alpha; }
int BOARD::alphabeta(int depth,int alpha,int beta,bool donull) { if(depth==0) { //info.nodes++; return quiescence(alpha,beta); //return evaluate(); } if((info.nodes & 2047) == 0) check(); info.nodes++; if((repeat() || fifty >=100) & ply) return 0; if(ply >MAXDEPTH -1) return evaluate(); bool kingsafe; int pos=(int)log2(board[side+4] & -board[side+4]); kingsafe=isSafe(pos,side); if(!kingsafe) depth++; int score = -INFINITE; /* if(donull && ply && kingsafe && depth >4 && bigPiece[side] >0) { makeNullMove(); score=-alphabeta(depth-4,-beta,-beta+1,false); unmakeNullMove(); if(info.stopped) return 0; if(score>=beta) return beta; }*/ int legal=0; int oldalpha=alpha; int bestmove=NOMOVE; score=-INFINITE; MOVE_LIST moveList; moveList.count=0; generateAllMoves(moveList); int pvMove=getPvMove(); if(pvMove != NOMOVE) { for(int i=0;i<moveList.count;i++) { if(moveList.l[i].move == pvMove) { moveList.l[i].score=2000000; break; } } } std::sort(moveList.l,moveList.l+moveList.count,so); for(int i=0;i<moveList.count;i++) { //pickBest(i,moveList); if(!makeMove(moveList.l[i].move)) continue; legal++; score=-alphabeta(depth-1,-beta,-alpha,donull); unmakeMove(); if(info.stopped) return 0; if(score >alpha) { if(score >=beta) { if(legal==1) info.fhf++; info.fh++; if(CAP(moveList.l[i].move) == EMPTY) { searchKillers[1][depth]=searchKillers[0][depth]; searchKillers[0][depth]=moveList.l[i].move; } return beta; //beta - cutoff } alpha=score; bestmove=moveList.l[i].move; if(CAP(moveList.l[i].move) == EMPTY) searchHistory[cboard[FROM(bestmove)]][TO(bestmove)]+=depth; } } if(legal == 0) { if(!kingsafe) return -MATE + ply; else return 0; } if(alpha != oldalpha) storePv(bestmove); return alpha; }