/* remove n from q1 and put it in q2 if nid not in q2 */ int lqremoveputifn(void *q1p, void *q2p, int (*searchfn1)(void* elementp,void* skeyp1), void* skeyp1, int (*searchfn2)(void* elementp,void* skeyp2), void * skeyp2){ if(NULL != q1p && NULL != q2p){ void * node; int ret = -1; pthread_mutex_t *q1_lock = &(((lqtype *)q1p)->q_lock); pthread_mutex_t *q2_lock = &(((lqtype *)q2p)->q_lock); int rc = pthread_mutex_lock(q1_lock); rc = pthread_mutex_lock(q2_lock); if(NULL == searchfn2 || qsearch(((lqtype *)q2p)->queue, searchfn2, skeyp2) == NULL){ node = qremove(((lqtype *)q1p)->queue, searchfn1, skeyp1); if(NULL != node){ qput(((lqtype *)q2p)->queue, node); ret = 0; } } rc = pthread_mutex_unlock(q2_lock); rc = pthread_mutex_unlock(q1_lock); return ret; } else { printf("should open queues before using it\n"); return -1; } }
/* returns first matching element */ void* lqsearch(void *qp, int (*searchfn)(void* elementp,void* keyp), void* skeyp){ if(NULL != qp){ pthread_mutex_t *q_lock = &(((lqtype *)qp)->q_lock); int rc = pthread_mutex_lock(q_lock); void * ret = qsearch(((lqtype *)qp)->queue, searchfn, skeyp); rc = pthread_mutex_unlock(q_lock); return ret; } else { printf("should open queue before using it\n"); return NULL; } }
int Board::qsearch(int ply, int alpha, int beta) { // quiescence search int i, j, val; if (timedout) return 0; triangularLength[ply] = ply; if (isOwnKingAttacked()) return alphabetapvs(ply, 1, alpha, beta); if(EVAL_FUNC == 0){ val = board.eval(); }else { val = board.evalJL(PARAM_EVAL_MATERIAL, PARAM_EVAL_ESPACIAL, PARAM_EVAL_DINAMICA, PARAM_EVAL_POS_TABLERO, ply); } if (val >= beta) return val; if (val > alpha) alpha = val; // generate captures & promotions: // captgen returns a sorted move list moveBufLen[ply+1] = captgen(moveBufLen[ply]); for (i = moveBufLen[ply]; i < moveBufLen[ply+1]; i++) { makeMove(moveBuffer[i]); { if (!isOtherKingAttacked()) { inodes++; if (--countdown <=0) readClockAndInput(); val = -qsearch(ply+1, -beta, -alpha); unmakeMove(moveBuffer[i]); if (val >= beta) return val; if (val > alpha) { alpha = val; triangularArray[ply][ply] = moveBuffer[i]; for (j = ply + 1; j < triangularLength[ply+1]; j++) { triangularArray[ply][j] = triangularArray[ply+1][j]; } triangularLength[ply] = triangularLength[ply+1]; } } else unmakeMove(moveBuffer[i]); } } return alpha; }
/*! @decl int(0..0) _xpm_write_rows(Image.Image img, Image.Image alpha, @ *! int bpc, array(string) colors, array(string) pixels) *! *! Fills in @[img] and @[alpha] according to xpm data in @[bpc], @[colors] *! and @[pixels]. *! *! @param bpc *! Bytes per color. Number of bytes used to encode each color in @[pixels]. *! *! @param colors *! Array of color definitions. *! *! A color definition is on the format @tt{"ee c #RRGGBB"@}, *! where @tt{ee@} is a @[bpc] long string used to encode the color, *! @tt{c@} is a literal @tt{"c"@}, and @tt{RRGGBB@} is a hexadecimal *! RGB code. *! *! @param pixels *! Raw picture information. *! *! @array pixels *! @elem string 0 *! Size information on the format *! (@expr{sprintf("%d %d %d %d", h, w, ncolors, bpn)@}). *! @elem string 1..ncolors *! Same as @[colors]. *! @elem string ncolors_plus_one..ncolors_plus_h *! Line information. Strings of length @[bpn]*w with encoded *! pixels for each line. *! @endarray */ void f__xpm_write_rows( INT32 args ) { struct object *img; struct object *alpha; struct array *pixels; struct array *colors; struct image *iimg, *ialpha; rgb_group *dst, *adst; INT_TYPE y,x, bpc; get_all_args("_xpm_write_rows",args,"%o%o%i%a%a", &img,&alpha,&bpc,&colors,&pixels); #if 0 fprintf(stderr, "_xpm_write_rows("); print_svalue(stderr, Pike_sp-5); fprintf(stderr, ", "); print_svalue(stderr, Pike_sp-4); fprintf(stderr, ", "); print_svalue(stderr, Pike_sp-3); fprintf(stderr, ", "); print_svalue(stderr, Pike_sp-2); fprintf(stderr, ", "); print_svalue(stderr, Pike_sp-1); fprintf(stderr, ")\n"); #endif /* 0 */ iimg = (struct image *)get_storage( img, image_program ); ialpha = (struct image *)get_storage( alpha, image_program ); if(!iimg || !ialpha) Pike_error("Sluta pilla på interna saker..\n"); if (pixels->size < iimg->ysize + colors->size) { SIMPLE_ARG_ERROR("_xpm_write_rows", 5, "pixel array is too short."); } for(y = 0; y < iimg->ysize + colors->size + 1; y++) { if ((pixels->item[y].type != T_STRING) || (pixels->item[y].u.string->size_shift)) { SIMPLE_ARG_ERROR("_xpm_write_rows", 5, "Pixel array contains elements other than 8bit strings."); } if (y < colors->size) { if ((colors->item[y].type != T_STRING) || (pixels->item[y].u.string->size_shift)) { SIMPLE_ARG_ERROR("_xpm_write_rows", 5, "Color array contains elements other than 8bit strings."); } } else if (y > colors->size) { if (pixels->item[y].u.string->len < iimg->xsize*bpc) { SIMPLE_ARG_ERROR("_xpm_write_rows", 5, "Pixel array contains too short string (bad bpc?)."); } } } dst = iimg->img; adst = ialpha->img; switch(bpc) { default: for(y = 0; y<iimg->ysize; y++) { char *ss = (char *)pixels->item[y+colors->size+1].u.string->str; for(x = 0; x<iimg->xsize; x++) { rgba_group color=qsearch(ss,bpc,colors); ss+=bpc; if(color.alpha) { dst->r = color.r; dst->g = color.g; (dst++)->b = color.b; adst++; } else { dst++; adst->r = adst->g = adst->b = 0; adst++; } } } break; case 3: { rgba_group **p_colors; int i; p_colors = (rgba_group **)xalloc(sizeof(rgba_group *)*65536); MEMSET(p_colors, 0, sizeof(rgba_group *)*65536); for(i=0; i<colors->size; i++) { struct pike_string *c = colors->item[i].u.string; unsigned char ind = ((unsigned char *)(c->str))[2]; unsigned short id = extract_short((unsigned char *)c->str); if(!p_colors[id]) { p_colors[id] = (rgba_group *)xalloc(sizeof(rgba_group)*128); MEMSET(p_colors[id],0,sizeof(rgba_group)*128); } if(ind > 127) { p_colors[id] = (rgba_group *)realloc(p_colors[id],sizeof(rgba_group)*256); MEMSET(p_colors[id]+sizeof(rgba_group)*128,0,sizeof(rgba_group)*128); } p_colors[id][ind]=parse_color_line( c, bpc ); } for(y = 0; y<iimg->ysize; y++) { unsigned char *ss = (unsigned char *)pixels->item[y+colors->size+1]. u.string->str; rgba_group *color, colorp; for(x = 0; x<iimg->xsize; x++) { color=p_colors[extract_short(ss)]; if(color) colorp = color[((unsigned char *)ss+2)[0]]; else colorp.alpha = 0; if(colorp.alpha) { dst->r = colorp.r; dst->g = colorp.g; (dst++)->b = colorp.b; adst++; } else { adst->r = adst->g = adst->b = 0; dst++; } ss+=bpc; } } for(i=0; i<65536; i++) if(p_colors[i]) free(p_colors[i]); free(p_colors); break; } case 2: { rgba_group p_colors[65536]; int i; for(i=0; i<colors->size; i++) { unsigned short id = extract_short((unsigned char*)colors->item[i].u.string->str); p_colors[id] = parse_color_line( colors->item[i].u.string, bpc ); } for(y = 0; y<iimg->ysize; y++) { unsigned char *ss = (unsigned char *)pixels->item[y+colors->size+1]. u.string->str; for(x = 0; x<iimg->xsize; x++) { rgba_group color=p_colors[extract_short(ss)]; dst->r = color.r; dst->g = color.g; (dst++)->b = color.b; if(!color.alpha) adst->r = adst->g = adst->b = 0; ss+=bpc; adst++; } } break; } case 1: { rgba_group p_colors[256]; int i; for(i=0; i<colors->size; i++) { unsigned char id = *((unsigned char *)colors->item[i].u.string->str); p_colors[id] = parse_color_line( colors->item[i].u.string, bpc ); } for(y = 0; y<iimg->ysize; y++) { unsigned char *ss=(unsigned char *) pixels->item[y+colors->size+1].u.string->str; for(x = 0; x<iimg->xsize; x++) { rgba_group color=p_colors[*ss]; dst->r = color.r; dst->g = color.g; (dst++)->b = color.b; if(!color.alpha) adst->r = adst->g = adst->b = 0; ss+=bpc; adst++; } } break; } } pop_n_elems(args); push_int(0); }
/** * Principle Variation Search (fail-soft) * @param alpha lowerbound value * @param beta upperbound value * @param depth remaining search depth * @return score for the current node */ int search_t::pvs(int alpha, int beta, int depth) { assert(alpha < beta); assert(alpha >= -score::INF); assert(beta <= score::INF); stack->pv_count = 0; sel_depth = MAX(brd.ply, sel_depth); stack->best_move.clear(); /* * If no more depth remaining, return quiescence value */ if (depth < 1) { const int score = qsearch(alpha, beta, 0); return score; } /* * Stop conditions */ //time nodes++; if (abort()) { return alpha; } //ceiling if (brd.ply >= (MAX_PLY - 1)) { return evaluate(this); } assert(depth > 0 && depth <= MAX_PLY); int alpha1 = alpha; //mate distance pruning: if mate(d) in n don't search deeper if ((score::MATE - brd.ply) < beta) { beta = score::MATE - brd.ply; if (alpha >= beta) { return beta; } } if ((-score::MATE + brd.ply) > alpha) { alpha = -score::MATE + brd.ply; if (beta <= alpha) { return alpha; } } //draw by lack of material or fifty quiet moves if (is_draw()) { return draw_score(); } /* * Transposition table lookup */ const bool pv = alpha + 1 < beta; stack->tt_key = brd.stack->tt_key; //needed for testing repetitions int tt_move = 0, tt_flag = 0, tt_score; if (trans_table::retrieve(stack->tt_key, brd.ply, depth, tt_score, tt_move, tt_flag)) { if (pv && tt_flag == score::EXACT) { return tt_score; } else if (!pv && tt_score >= beta && tt_flag == score::LOWERBOUND) { return tt_score; } else if (!pv && tt_score <= alpha && tt_flag == score::UPPERBOUND) { return tt_score; } } stack->tt_move.set(tt_move); /* * Node pruning */ const bool in_check = stack->in_check; const int eval = evaluate(this); const bool do_prune_node = eval >= beta && !in_check && !pv && !score::is_mate(beta) && brd.has_pieces(brd.us()); // beta pruning if (do_prune_node && depth < 4 && beta_pruning) { int bp_score = eval - 50 * depth; if (bp_score >= beta) { return bp_score; } } //null move pruning if (do_prune_node && null_enabled) { int R = 3; forward(); int null_score = -pvs(-beta, -alpha, depth - 1 - R); backward(); if (stop_all) { return alpha; } else if (null_score >= beta) { const int RV = 5; if (null_verify && depth > RV && material::is_eg(this)) { //verification int verified_score = pvs(alpha, beta, depth - 1 - RV); if (verified_score >= beta) { return verified_score; } } else { //no verification return null_score; } } } /* * Internal iterative deepening (IID) */ if (pv && depth > 2 && tt_move == 0) { int iid_score = pvs(alpha, beta, depth - 2); if (score::is_mate(iid_score)) { return iid_score; } else if (stack->best_move.piece) { stack->tt_move.set(&stack->best_move); } } /* * Moves loop */ //if there is no first move, it's checkmate or stalemate move_t * move = move::first(this, depth); if (!move) { return in_check ? -score::MATE + brd.ply : draw_score(); } //set futility pruning delta value bool do_ffp = false; int delta = score::INVALID; if (depth <= 8 && !in_check && !score::is_mate(alpha) && !material::is_eg(this) && ffp_enabled) { int ffp_score = eval + 40 * depth; if (ffp_score <= alpha) { do_ffp = true; delta = ffp_score + 50; } } //prepare and do the loop int best = -score::INF; int searched_moves = 0; const int score_max = score::MATE - brd.ply - 1; stack->best_move.clear(); do { assert(brd.valid(move) && brd.legal(move)); assert(stack->best_move.equals(move) == false); assert(in_searched(move, searched_moves) == false); const int gives_check = brd.gives_check(move); assert(gives_check == 0 || gives_check == 1 || gives_check == 2); /* * Move pruning: skip all futile moves */ const bool is_dangerous = in_check || gives_check || move->capture || move->promotion || move->castle || is_advanced_passed_pawn(move); bool pruned = false; if (do_ffp && searched_moves > 0) { pruned = !is_dangerous; pruned |= gives_check == 0 && (move->capture || move->promotion) && brd.max_gain(move) + delta <= alpha; if (pruned) { pruned_nodes++; continue; } } /* * Move extensions */ int extend = extension(move, depth, pv, gives_check); /* * Move Reductions (Late Move Reductions, LMR) */ int reduce = reduction(depth, searched_moves, is_dangerous); /* * Go forward and search next node */ forward(move, gives_check); int score; if (searched_moves == 0) { score = -pvs(-beta, -alpha, depth - 1 + extend); } else { score = -pvs(-alpha - 1, -alpha, depth - 1 - reduce + extend); if (score > alpha && (pv || reduce > 0)) { //open window research without reductions score = -pvs(-beta, -alpha, depth - 1 + extend); } } backward(move); /* * Handle results: update the best value / do a beta cutoff */ if (stop_all) { return alpha; } else if (score > best) { stack->best_move.set(move); if (score >= beta) { trans_table::store(stack->tt_key, brd.root_ply, brd.ply, depth, score, move->to_int(), score::LOWERBOUND); if (!move->capture && !move->promotion && !move->castle) { update_killers(move); update_history(move); for (int i = 0; i < searched_moves; i++) { move_t * m = &stack->searched[i]; if (!m->capture && !m->promotion && !m->castle) { history[m->piece][m->tsq] >>= searched_moves; } } }
t_chess_value qsearch(struct t_board *board, int ply, int depth, t_chess_value alpha, t_chess_value beta) { //-- Principle Variation struct t_pv_data *pv = &(board->pv_data[ply]); //-- Has the maximum depth been reached if (ply >= MAXPLY || uci.stop) return pv->eval->static_score; //-- Increment the node count qnodes++; //-- Is this the deepest? if (ply > deepest) { deepest = ply; do_uci_depth(); } //-- Mate Distance Pruning if (CHECKMATE - ply <= alpha) { return alpha; } else if (-CHECKMATE + ply >= beta) { return beta; } //-- PV of Next Ply struct t_pv_data *next_pv = &(board->pv_data[ply + 1]); //-- Define the local variables pv->legal_moves_played = 0; t_chess_value best_score; t_chess_value a = alpha; t_chess_value b = beta; t_chess_value e; // Declare local variables t_undo undo[1]; //-- Generate All Moves struct t_move_list moves[1]; moves->hash_move = NULL; //----------------------------------------------- //-- Handling In-Check (e.g. Cannot Stand-Pat) //----------------------------------------------- if (board->in_check) { best_score = -CHECKMATE; //-- Generate moves which get out of check generate_evade_check(board, moves); // Are we in checkmate? if (moves->count == 0) { pv->best_line_length = ply; return -CHECKMATE + ply; } //-- Order the moves order_evade_check(board, moves, ply); //-- Play moves while (make_next_best_move(board, moves, undo)) { //-- Increment the "legal_moves_played" counter pv->legal_moves_played++; pv->current_move = moves->current_move; //-- Evaluate the new board position evaluate(board, next_pv->eval); //-- Search the next ply at reduced depth e = -qsearch(board, ply + 1, depth - 1, -b - 1, -a); //-- Is a research required? if (alpha + 1 != beta && e > a && a + 1 == b) e = -qsearch(board, ply + 1, depth - 1, -beta, -a); unmake_move(board, undo); //-- Is it good enough to cut-off? if (e >= beta) { update_check_killers(pv, 0); return e; } //-- Is it the best so far? if (e > best_score) { best_score = e; //-- Does it improve upon alpha (i.e. is it part of the PV)? if (e > a) { a = e; //-- Update the Principle Variation update_best_line(board, ply); } } // Reset the zero width window b = a + 1; } } else { //-------------------------------------------------------- //-- Normal moves handled differently (e.g. can stand-pat) //-------------------------------------------------------- //-- Does stand-pat cause a cutoff? e = pv->eval->static_score; if (e >= beta) return e; //-- Does the current value raise alpha? best_score = e; if (e > alpha) { a = e; pv->best_line_length = ply; } //-- Generate all captures generate_captures(board, moves); //-- Order the moves order_captures(board, moves); //-- Only search break even captures during the PV //int threshold = 10; //if (beta != alpha + 1) int threshold = 0; //-- Play moves while (make_next_see_positive_move(board, moves, threshold, undo)) { //-- Increment the "legal_moves_played" counter pv->legal_moves_played++; pv->current_move = moves->current_move; //-- Evaluate the new board position evaluate(board, next_pv->eval); //-- Search the next ply at reduced depth e = -qsearch(board, ply + 1, depth - 1, -b, -a); //-- Is a research required? if (alpha + 1 != beta && e > a && a + 1 == b) e = -qsearch(board, ply + 1, depth - 1, -beta, -a); unmake_move(board, undo); //-- Is it good enough to cut-off? if (e >= beta) return e; //-- Is it the best so far? if (e > best_score) { best_score = e; //-- Does it improve upon alpha (i.e. is it part of the PV)? if (e > a) { a = e; update_best_line(board, ply); } } // Reset the zero width window b = a + 1; } } // Return Best Score found return best_score; }
t_chess_value qsearch_plus(struct t_board *board, int ply, int depth, t_chess_value alpha, t_chess_value beta) { //-- Principle Variation struct t_pv_data *pv = &(board->pv_data[ply]); //-- Has the maximum depth been reached if (ply >= MAXPLY || uci.stop) return pv->eval->static_score; //-- Increment the node count qnodes++; /* check to see if this is a repeated position or draw by 50 moves */ if (repetition_draw(board)) { pv->best_line_length = ply; return 0; } //-- Mate Distance Pruning if (CHECKMATE - ply <= alpha) { return alpha; } else if (-CHECKMATE + ply >= beta) { return beta; } else if ((!board->in_check) && (-CHECKMATE + ply + 2 >= beta)) { return beta; } //-- Next Principle Variation struct t_pv_data *next_pv = &(board->pv_data[ply + 1]); //-- Define the local variables pv->legal_moves_played = 0; t_chess_value best_score; t_chess_value a = alpha; t_chess_value b = beta; t_chess_value e; // Declare local variables t_undo undo[1]; //-- Generate All Moves struct t_move_list moves[1]; moves->hash_move = NULL; //----------------------------------------------- //-- Handling In-Check (e.g. Cannot Stand-Pat) //----------------------------------------------- if (board->in_check) { best_score = -CHECKMATE; //-- Generate moves which get out of check generate_evade_check(board, moves); // Are we in checkmate? if (moves->count == 0) { pv->best_line_length = ply; return -CHECKMATE + ply; } t_chess_value(*q_search)(struct t_board *board, int ply, int depth, t_chess_value alpha, t_chess_value beta); if (moves->count == 1) q_search = &qsearch_plus; else { q_search = &qsearch; //-- Order the moves order_evade_check(board, moves, ply); } //-- Play moves while (make_next_best_move(board, moves, undo)) { //-- Increment the "legal_moves_played" counter pv->legal_moves_played++; pv->current_move = moves->current_move; //-- Evaluate the new board position evaluate(board, next_pv->eval); //-- More than one move out of check so just use "vanilla" qsearch e = -q_search(board, ply + 1, depth - 1, -b, -a); //-- Is a research required? if (alpha + 1 != beta && e > a && a + 1 == b) e = -q_search(board, ply + 1, depth - 1, -beta, -a); unmake_move(board, undo); //-- Is it good enough to cut-off? if (e >= beta) { update_check_killers(pv, 0); poke(board->hash, e, ply, depth, HASH_LOWER, pv->current_move); return e; } //-- Is it the best so far? if (e > best_score) { best_score = e; //-- Does it improve upon alpha (i.e. is it part of the PV)? if (e > a) { a = e; //-- Update the Principle Variation update_best_line(board, ply); } } // Reset the zero width window b = a + 1; } } else { //-------------------------------------------------------- //-- Normal moves handled differently (e.g. can stand-pat) //-------------------------------------------------------- //-- Does stand-pat cause a cut-off? e = pv->eval->static_score; if (e >= beta) return e; //-- Does the current value raise alpha? best_score = e; if (e > alpha) { a = e; pv->best_line_length = ply; } //-- Generate all captures generate_captures(board, moves); //-- Order the moves order_captures(board, moves); //-- Play *ALL* captures while (make_next_best_move(board, moves, undo)) { //-- Increment the "legal_moves_played" counter pv->legal_moves_played++; pv->current_move = moves->current_move; //-- Evaluate the new board position evaluate(board, next_pv->eval); //-- Search the next ply at reduced depth e = -qsearch(board, ply + 1, depth - 1, -b, -a); //-- Is a research required? if (alpha + 1 != beta && e > a && a + 1 == b) e = -qsearch(board, ply + 1, depth - 1, -beta, -a); unmake_move(board, undo); //-- Is it good enough to cut-off? if (e >= beta) { return e; } //-- Is it the best so far? if (e > best_score) { best_score = e; //-- Does it improve upon alpha (i.e. is it part of the PV)? if (e > a) { a = e; update_best_line(board, ply); } } // Reset the zero width window b = a + 1; } //-- Reset the move count moves->count = 0; //-- Now Try the checks! generate_quiet_checks(board, moves); ////-- Maybe if there are many, one will be a checkmate? //if (moves->count > 4){ // while (simple_make_next_move(board, moves, undo)) { // assert(board->in_check); // //-- Generate moves // struct t_move_list evade_check_moves[1]; // generate_evade_check(board, evade_check_moves); // //-- Take the move back // unmake_move(board, undo); // //-- Is it Checkmate? // if (evade_check_moves->count == 0){ // pv->best_line_length = ply + 1; // e = +CHECKMATE - ply - 1; // return e; // } // } // //-- Reset the real move count // moves->imove = moves->count; //} //-- Order the moves order_moves(board, moves, ply); //-- Play moves while (make_next_best_move(board, moves, undo)) { //-- Increment the "legal_moves_played" counter pv->legal_moves_played++; pv->current_move = moves->current_move; //-- Evaluate the new board position evaluate(board, next_pv->eval); //-- Search the next ply at reduced depth e = -qsearch_plus(board, ply + 1, depth - 1, -b, -a); //-- Is a research required? if (alpha + 1 != beta && e > a && a + 1 == b) e = -qsearch_plus(board, ply + 1, depth - 1, -beta, -a); unmake_move(board, undo); //-- Is it good enough to cut-off? if (e >= beta) { poke(board->hash, e, ply, depth, HASH_LOWER, pv->current_move); update_killers(pv, 0); return e; } //-- Is it the best so far? if (e > best_score) { best_score = e; //-- Does it improve upon alpha (i.e. is it part of the PV)? if (e > a) { a = e; update_best_line(board, ply); } } // Reset the zero width window b = a + 1; } } //-- Update Hash if (best_score > alpha) poke(board->hash, best_score, ply, depth, HASH_EXACT, pv->best_line[ply]); // Return Best Score found return best_score; }
int Board::alphabetapvs(int ply, int depth, int alpha, int beta) { // PV search int i, j, movesfound, pvmovesfound, val; triangularLength[ply] = ply; if (depth == 0) { followpv = false; return qsearch(ply, alpha, beta); } // repetition check: if (repetitionCount() >= 3) return DRAWSCORE; movesfound = 0; pvmovesfound = 0; moveBufLen[ply+1] = movegen(moveBufLen[ply]); for (i = moveBufLen[ply]; i < moveBufLen[ply+1]; i++) { selectmove(ply, i, depth, followpv); makeMove(moveBuffer[i]); { if (!isOtherKingAttacked()) { inodes++; movesfound++; if (!ply) displaySearchStats(3, ply, i); if (pvmovesfound) { val = -alphabetapvs(ply+1, depth-1, -alpha-1, -alpha); if ((val > alpha) && (val < beta)) { // in case of failure, proceed with normal alphabeta val = -alphabetapvs(ply+1, depth - 1, -beta, -alpha); } } // normal alphabeta else val = -alphabetapvs(ply+1, depth-1, -beta, -alpha); unmakeMove(moveBuffer[i]); if (val >= beta) { // update the history heuristic if (nextMove) blackHeuristics[moveBuffer[i].getFrom()][moveBuffer[i].getTosq()] += depth*depth; else whiteHeuristics[moveBuffer[i].getFrom()][moveBuffer[i].getTosq()] += depth*depth; return beta; } if (val > alpha) { alpha = val; // both sides want to maximize from *their* perspective pvmovesfound++; triangularArray[ply][ply] = moveBuffer[i]; // save this move for (j = ply + 1; j < triangularLength[ply+1]; j++) { triangularArray[ply][j] = triangularArray[ply+1][j]; // and append the latest best PV from deeper plies } triangularLength[ply] = triangularLength[ply+1]; if (!ply) { msStop = timer.getms(); displaySearchStats(2, depth, val); } } } else unmakeMove(moveBuffer[i]); } } // update the history heuristic if (pvmovesfound) { if (nextMove) blackHeuristics[triangularArray[ply][ply].getFrom()][triangularArray[ply][ply].getTosq()] += depth*depth; else whiteHeuristics[triangularArray[ply][ply].getFrom()][triangularArray[ply][ply].getTosq()] += depth*depth; } // 50-move rule: if (fiftyMove >= 100) return DRAWSCORE; // Checkmate/stalemate detection: if (!movesfound) { if (isOwnKingAttacked()) return (-CHECKMATESCORE+ply-1); else return (STALEMATESCORE); } return alpha; }
int Board::alphabetapvs(int ply, int depth, int alpha, int beta) { // PV search int i, j, movesfound, pvmovesfound, val; triangularLength[ply] = ply; if (depth <= 0) { followpv = false; return qsearch(ply, alpha, beta); } // repetition check: if (repetitionCount() >= 3) return DRAWSCORE; // now try a null move to get an early beta cut-off: if (!followpv && allownull) { if ((nextMove && (board.totalBlackPieces > NULLMOVE_LIMIT)) || (!nextMove && (board.totalWhitePieces > NULLMOVE_LIMIT))) { if (!isOwnKingAttacked()) { allownull = false; inodes++; if (--countdown <=0) readClockAndInput(); nextMove = !nextMove; hashkey ^= KEY.side; val = -alphabetapvs(ply, depth - NULLMOVE_REDUCTION, -beta, -beta+1); nextMove = !nextMove; hashkey ^= KEY.side; if (timedout) return 0; allownull = true; if (val >= beta) return val; } } } allownull = true; movesfound = 0; pvmovesfound = 0; moveBufLen[ply+1] = movegen(moveBufLen[ply]); for (i = moveBufLen[ply]; i < moveBufLen[ply+1]; i++) { selectmove(ply, i, depth, followpv); makeMove(moveBuffer[i]); { if (!isOtherKingAttacked()) { inodes++; if (--countdown <=0) readClockAndInput(); movesfound++; if (!ply) displaySearchStats(3, ply, i); if (pvmovesfound) { val = -alphabetapvs(ply+1, depth-1, -alpha-1, -alpha); if ((val > alpha) && (val < beta)) { // in case of failure, proceed with normal alphabeta val = -alphabetapvs(ply+1, depth - 1, -beta, -alpha); } } // normal alphabeta else val = -alphabetapvs(ply+1, depth-1, -beta, -alpha); unmakeMove(moveBuffer[i]); if (timedout) return 0; if (val >= beta) { // update the history heuristic if (nextMove) blackHeuristics[moveBuffer[i].getFrom()][moveBuffer[i].getTosq()] += depth*depth; else whiteHeuristics[moveBuffer[i].getFrom()][moveBuffer[i].getTosq()] += depth*depth; return beta; } if (val > alpha) { alpha = val; // both sides want to maximize from *their* perspective pvmovesfound++; triangularArray[ply][ply] = moveBuffer[i]; // save this move for (j = ply + 1; j < triangularLength[ply+1]; j++) { triangularArray[ply][j] = triangularArray[ply+1][j]; // and append the latest best PV from deeper plies } triangularLength[ply] = triangularLength[ply+1]; if (!ply) displaySearchStats(2, depth, val); } } else unmakeMove(moveBuffer[i]); } } // update the history heuristic if (pvmovesfound) { if (nextMove) blackHeuristics[triangularArray[ply][ply].getFrom()][triangularArray[ply][ply].getTosq()] += depth*depth; else whiteHeuristics[triangularArray[ply][ply].getFrom()][triangularArray[ply][ply].getTosq()] += depth*depth; } // 50-move rule: if (fiftyMove >= 100) return DRAWSCORE; // Checkmate/stalemate detection: if (!movesfound) { if (isOwnKingAttacked()) return (-CHECKMATESCORE+ply-1); else return (STALEMATESCORE); } return alpha; }
int qsearch(s_search_info *info, s_stack *stack, s_board *board, int alpha, int beta) { assert(info != NULL); assert(stack != NULL); assert(board != NULL); assert(alpha < beta); int stand_pat = evaluate(board); if(stack->ply > info->seldepth) { info->seldepth = stack->ply-1; } if(stand_pat >= beta) { return beta; } #ifdef DELTA_PRUNING const int safety = 900; // The value of a queen if(stand_pat < alpha - safety && !is_endgame(board)) { return alpha; } #endif if(stand_pat > alpha) { alpha = stand_pat; } if(stack->ply >= MAX_DEPTH) { return stand_pat; } // Set old permissions s_irreversible permissions; store_irreversible(&permissions, board); s_move moves[MAX_MOVES]; int num_moves = find_moves_captures(board, moves, board->turn); #ifdef SORT_MOVES moves_sort_see(board, moves, num_moves); #endif for(int m = 0; m < num_moves; ++m) { int val = see_capture(board, moves[m]); if(val < -50) { break; } move_make(board, &moves[m]); if(square_attacked(board, board->pieces[KINGS]&board->colour[!board->turn], board->turn)) { // Restore old permissions restore_irreversible(&permissions, board); move_undo(board, &moves[m]); continue; } info->nodes++; int score = -qsearch(info, stack+1, board, -beta, -alpha); // Restore old permissions restore_irreversible(&permissions, board); move_undo(board, &moves[m]); if(score >= beta) { #ifndef NDEBUG info->num_cutoffs[m]++; #endif return beta; } if(score > alpha) { alpha = score; } } return alpha; }