BOOL test_alt_move_gen() { BOOL ok = TRUE; struct t_move_list moves[1], xmoves[2]; set_fen(position, "5rN1/4P3/1B6/1B3k2/8/4P3/6PP/2RQK2R w K -"); generate_captures(position, moves); generate_quiet_checks(position, moves); generate_no_capture_no_checks(position, moves); generate_moves(position, xmoves); ok &= (equal_move_lists(xmoves, moves)); flip_board(position); generate_captures(position, moves); generate_quiet_checks(position, moves); generate_no_capture_no_checks(position, moves); generate_moves(position, xmoves); ok &= (equal_move_lists(xmoves, moves)); return ok; }
void do_perft(position_t *pos, scored_move_t *ms, int ply, int depth) { scored_move_t *msbase = ms; uint8 stm = Stm(ply); scored_move_t *mv; if (Checked(stm^1)) return; if (Checked(stm)) { ms = generate_evasions(pos, ms, ply); for (mv = msbase; mv < ms; mv++) if (PieceType(Capture(mv->move)) == KING) return; } else { ms = generate_captures(pos, ms, ply); for (mv = msbase; mv < ms; mv++) if (PieceType(Capture(mv->move)) == KING) return; ms = generate_noncaptures(pos, ms, ply); } for (mv = msbase; mv < ms; mv++) { make_move(pos, mv->move, ply); if (depth - 1) do_perft(pos, ms, ply + 1, depth - 1); else if (!Checked(stm)) total_moves++; unmake_move(pos, mv->move, ply); } }
MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLegal) { assert(pos.is_ok()); MoveStack *last, *cur = mlist; Bitboard pinned = pos.pinned_pieces(pos.side_to_move()); // Generate pseudo-legal moves if (pos.is_check()) last = generate_evasions(pos, mlist); else last = generate_noncaptures(pos, generate_captures(pos, mlist)); if (pseudoLegal) return last; // Remove illegal moves from the list while (cur != last) if (pos.pl_move_is_legal(cur->move, pinned)) cur++; else cur->move = (--last)->move; return last; }
BOOL test_capture_gen() { BOOL ok = TRUE; struct t_move_list moves[1]; set_fen(position, "8/pppr2pp/3pKp2/2Q3bn/8/b6k/PPP1P2P/3R2n1 w - -"); generate_captures(position, moves); ok &= (moves->count == 12); flip_board(position); generate_captures(position, moves); ok &= (moves->count == 12); return ok; }
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; }
BOOL test_hash_table() { t_move_list moves[1]; t_hash_record *h; BOOL ok = TRUE; set_fen(position, "8/pppr2pp/3pKp2/2Q3bn/8/b6k/PPP1P2P/3R2n1 w - -"); generate_captures(position, moves); poke(position->hash, 1, 2, 2, HASH_LOWER, moves->move[0]); h = probe(position->hash); if (h != NULL){ ok &= h->bound == HASH_LOWER; ok &= h->depth == 2; ok &= h->score == 1; ok &= h->move == moves->move[0]; ok &= h->key == position->hash; } return ok; }
Move MovePicker::get_next_move() { Move move; while(true) { // If we already have a list of generated moves, pick the best move from // the list, and return it: move = this->pick_move_from_list(); if(move != MOVE_NONE) { assert(move_is_ok(move)); return move; } // Next phase: phaseIndex++; switch(PhaseTable[phaseIndex]) { case PH_TT_MOVE: if(ttMove != MOVE_NONE) { assert(move_is_ok(ttMove)); Move m = generate_move_if_legal(*pos, ttMove, pinned); if(m != MOVE_NONE) { assert(m == ttMove); return m; } } break; case PH_MATE_KILLER: if(mateKiller != MOVE_NONE) { assert(move_is_ok(mateKiller)); Move m = generate_move_if_legal(*pos, mateKiller, pinned); if(m != MOVE_NONE) { assert(m == mateKiller); return m; } } break; case PH_GOOD_CAPTURES: // pinned = pos->pinned_pieces(pos->side_to_move()); numOfMoves = generate_captures(*pos, moves); this->score_captures(); movesPicked = 0; break; case PH_BAD_CAPTURES: badCapturesPicked = 0; break; case PH_NONCAPTURES: numOfMoves = generate_noncaptures(*pos, moves); this->score_noncaptures(); movesPicked = 0; break; case PH_EVASIONS: assert(pos->is_check()); // pinned = pos->pinned_pieces(pos->side_to_move()); numOfMoves = generate_evasions(*pos, moves); this->score_evasions(); movesPicked = 0; break; case PH_QCAPTURES: // pinned = pos->pinned_pieces(pos->side_to_move()); numOfMoves = generate_captures(*pos, moves); this->score_qcaptures(); movesPicked = 0; break; case PH_QCHECKS: numOfMoves = generate_checks(*pos, moves, dc); movesPicked = 0; break; case PH_STOP: return MOVE_NONE; default: assert(false); return MOVE_NONE; } } assert(false); return MOVE_NONE; }
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; }
DWORD san2move(struct board_t *brd,char san[128]) { short c,d,idx,to,from,pcs,file,row,found,cap; short mvalid[MAXMOVES]; char buf[128]; char *str; DWORD promotion,mvs[MAXMOVES]; to=from=file=row=-1; cap=FALSE; pcs=PAWN; promotion=0; for(c=0;c<=127;c++) buf[c]=san[c]; buf[127]='\0'; str=buf; /* primo passaggio: cerchiamo di individuare subito gli arrocchi */ if(strncmp(buf,"O-O",strlen("O-O"))==0) { pcs=KING; from=((brd->color==WHITE)?(E1):(E8)); to=((brd->color==WHITE)?(G1):(G8)); goto third; } if(strncmp(buf,"O-O-O",strlen("O-O-O"))==0) { pcs=KING; from=((brd->color==WHITE)?(E1):(E8)); to=((brd->color==WHITE)?(C1):(C8)); goto third; } /* secondo passaggio: togliamo i caratteri inutili "x+#" e leggiamo la posizione SAN "normale" */ for(c=0;c<strlen(buf);c++) { if((buf[c]=='+')||(buf[c]=='#')||(buf[c]=='x')) { if(buf[c]=='x') cap=TRUE; for(d=c;d<strlen(buf);d++) buf[d]=buf[d+1]; } if((buf[c]=='=')&&(strlen(buf)==(c+2))) { promotion=promflags(buf[c+1]); buf[c]='\0'; } } if(strspn(buf,"123456789NBRQKabcdefgh")!=strlen(buf)) return 0; if((c=inarray(*san,"PNBRQK"))!=-1) { if(c==PAWN) return 0; pcs=c; *str++; } if((strlen(str)>=5)||(strlen(str)<=1)) return 0; if(strlen(str)==4) { if((from=findcoord(str))==-1) return 0; if((to=findcoord(str+2))==-1) return 0; } if(strlen(str)==3) { row=inarray(*str,"12345678"); file=inarray(*str,"abcdefgh"); if((to=findcoord(str+1))==-1) return 0; } if(strlen(str)==2) { if((to=findcoord(str))==-1) return 0; } third: /* terzo passaggio: generiamo tutte le mosse possibili ed escludiamo tutte quelle che non combaciano con i dati in nostro possesso */ idx=0; if(cap==TRUE) generate_captures(brd,mvs,&idx); else generate_moves(brd,mvs,&idx); for(c=0;c<idx;c++) { makemove(brd,mvs[c]); mvalid[c]=FALSE; if(is_in_check(brd,brd->color^1)==FALSE) { mvalid[c]=TRUE; if(((mvs[c]>>6)&0x3F)!=to) mvalid[c]=FALSE; else if(((mvs[c]>>12)&0x7)!=pcs) mvalid[c]=FALSE; else if((from!=-1)&&((mvs[c]&0x3F)!=from))