static int Quiescent(BOARD *board, int alpha, int beta, int root, CONTROL *control, MOVE killers[][2]) { int nmoves, nlegal = 0; int val; MOVE moves[MAXMOVES]; 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); // nmoves = SortMoves(board, moves, nmoves, killers[root]); for(int i = 0; i < nmoves; i++){ control->node_count++; MakeMove(board, &moves[i]); if(!LeftInCheck(board)){ nlegal++; val = -Quiescent(board, -beta, -alpha, root+1, control, killers); Takeback(board, moves[i]); if(val >= beta){ return beta; } if(val > alpha){ alpha = val; } }else Takeback(board, moves[i]); } return alpha; }
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; }
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; }
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; }