// the quiescence search int Quiece(board_t *brd, int alpha, int beta, searchinfo_t *sinfo) { if(!(sinfo->nodes & 0xfff)) CheckUp(sinfo); sinfo->nodes++; ASSERT(CheckBrd(brd)); //if((IsRep(brd) || brd->fifty >= 100) && brd->ply) return 0; if(brd->ply >= MAXDEPTH-1) return Eval(brd); int score = Eval(brd); // we are probably not going to make our position worse by moving so we can say: if(score >= beta){ // if we are doing already too good return beta; // we have a beta cutoff and we return } if(score > alpha){ // if we are better than alpha alpha = score; // then we can set our minimum alpha to the score } mlist_t list; int i; score = -INFINITE; GenCaps(brd, &list); // Generate all capture moves for(i = 0; i < list.len; i++) // Loop through the moves { if(sinfo->stop) return 0; SelectNextMove(&list, i); if(!MakeMove(brd, list.move[i].move)) continue; score = -Quiece(brd, -beta, -alpha, sinfo); TakeBack(brd); if(score > alpha){ if(score >= beta){ return beta; } alpha = score; } } return alpha; }
// buscamos capturas y jaques y analizamos las posibilidades de escape. int CPartida::Quiesce(int alpha,int beta) { int value,a; if(cancelado + (stHistory >> 6)) // si llenamos el pozo lo dejamos en tablas { return Taux.Evalua(); } IncNodesQ(); u64 hash = Taux.GetHash(); int Valor_i; Valor_i = Taux.Evalua(); // Vamos con material de sobra if(Valor_i >= beta ) { return Valor_i; } a = alpha; if(Valor_i > alpha ) a = Valor_i; value = a; alpha = a; SetHashHistory(hash); CJugada J; int legales = 0; CSort Sort; Sort.Init(Taux,true); for(J = Sort.GetNextQ();J.ToInt();J = Sort.GetNextQ()) { if(cancelado) break; if(J.desglose.captura == rey) { a = ValorMate(1); PopHistory(); return a; } if(J.desglose.peso < (PesoCaptura+PesoCapturaBuena)) continue; Move(J); if(!Taux.EsAtacada(Taux.PosReyes[Taux.ColorJuegan^1],Taux.ColorJuegan^1) ) { legales++; value = -Quiesce(-beta, -a); } TakeBack(); if(value > a) { a = value; if(a >= beta ) { break; } } } // for PopHistory(); return ( a ); }
int Quiescent (int alpha, int beta) { int i = 0; int movescnt = 0; int score = 0; int best = 0; MOVE qMovesBuf[200]; countquiesCalls++; nodes++; /* Do some housekeeping every 1024 nodes */ if ((nodes & 1023) == 0) checkup(stop_time); if (must_stop) return 0; if (reps() >= 2) return 0; best = Eval(alpha, beta); // --- stand pat cutoff? if (best > alpha) { if (best >= beta) return best; alpha = best; } /* As we are in qasearch we generate the captures */ movescnt = GenCaps (side, qMovesBuf); countCapCalls++; #ifdef SEARCH_DEBUG if (movescnt > 200) printf("Too much moves!: %d", movescnt); #endif /* Now the alpha-beta search in quiescent */ for (i = 0; i < movescnt; ++i) { MoveOrder(i, movescnt, qMovesBuf); if (!MakeMove (qMovesBuf[i])) { /* If the current move isn't legal, we take it back * and take the next move in the list */ TakeBack (); continue; } score = -Quiescent (-beta, -alpha); TakeBack (); if ((nodes & 1023) == 0) checkup(stop_time); if (must_stop) return 0; if (score >= beta) return beta; if (score > alpha) alpha = score; } #ifdef SEARCH_DEBUG if (alpha > MATE) printf("alpha too high: %d", alpha); if (alpha < -MATE) printf("alpha too low: %d", alpha); #endif return alpha; }
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; }
int Search (int alpha, int beta, int depth, MOVE * pBestMove, LINE * pline) { /* Vars deffinition */ int i; int value; /* To store the evaluation */ int havemove; /* Either we have or not a legal move available */ int movecnt; /* The number of available moves */ // int score; MOVE moveBuf[200]; /* List of movements */ MOVE tmpMove; LINE line; nodes++; countSearchCalls++; /* Do some housekeeping every 1024 nodes */ if ((nodes & 1023) == 0) checkup(stop_time); if (must_stop) return 0; havemove = 0; /* is there a move available? */ pBestMove->type_of_move = MOVE_TYPE_NONE; /* If we are in a leaf node we cal quiescence instead of eval */ if (depth == 0) { pline->cmove = 0; return Quiescent(alpha, beta); /* Uncomment nest line if want to make tests avoiding qsearch */ //return Eval(alpha, beta); } /* If we're in check we want to search deeper */ if (IsInCheck(side)) ++depth; /* Static null move prunning */ if (ply && !IsInCheck(side)) { int ev = Eval(-MATE, MATE); int evalua = ev - 150; if (evalua >= beta) return beta; } /* Generate and count all moves for current position */ movecnt = GenMoves (side, moveBuf); /* Once we have all the moves available, we loop through the posible * moves and apply an alpha-beta search */ for (i = 0; i < movecnt; ++i) { /* Here must be called OrderMove, so we have the moves are ordered before picking one up from the list*/ MoveOrder(i, movecnt, moveBuf); /* If the current move isn't legal, we take it back * and take the next move in the list */ if (!MakeMove (moveBuf[i])) { TakeBack (); continue; } /* If we've reached this far, then we have a move available */ havemove = 1; value = -Search(-beta, -alpha, depth - 1, &tmpMove, &line); /* We've evaluated the position, so we return to the previous position in such a way that when we take the next move from moveBuf everything is in order */ TakeBack (); /* Once we have an evaluation, we use it in in an alpha-beta search */ if (value > alpha) { /* Este movimiento causo un cutoff, asi que incrementamos el valor de historia para que sea ordenado antes la proxima vez que se busque */ history[moveBuf[i].from][moveBuf[i].dest] += depth; /* This move is so good and caused a cutoff */ if (value >= beta) { return beta; } alpha = value; /* So far, current move is the best reaction for current position */ *pBestMove = moveBuf[i]; /* Update the principal line */ pline->argmove[0] = moveBuf[i]; memcpy(pline->argmove + 1, line.argmove, line.cmove * sizeof(MOVE)); pline->cmove = line.cmove + 1; } } /* Once we've checked all the moves, if we have no legal moves, * then that's checkmate or stalemate */ if (!havemove) { if (IsInCheck (side)) return -MATE + ply; /* add ply to find the longest path to lose or shortest path to win */ else return 0; } /* 3 vecez la misma posicion */ if (reps() >= 2) return 0; if (fifty >= 100) /* 50 jugadas o mas */ return 0; /* Finally we return alpha, the score value */ return alpha; }