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); } }
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; }
void perft_divide(FILE* stream, Board* board, unsigned int depth) { int i, totalMoves = 0; Move moves[256]; if (depth <= 0) { return; } int num_moves = generate_moves(board, moves); for (i = 0; i < num_moves; ++i) { int numDividedMoves = 0; char moveString[8]; sprint_move(moveString, moves[i]); printf("%s ", moveString); make_move(board, moves[i]); numDividedMoves = perft_perft(board, depth - 1); unmake_move(board, moves[i]); totalMoves += numDividedMoves; printf("%i\n", numDividedMoves); } fprintf(stream, "\nMoves: %i\n", num_moves); fprintf(stream, "Nodes: %i\n", totalMoves); }
void backtrack(int a[], int k, void* input) { int c[MAXCANDIDATES]; int ncandidates; if (is_a_solution(a, k, input)) { process_solution(a, k, input); } else { k = k + 1; construct_candidates(a, k, input, c, &ncandidates); for (int i = 0; i < ncandidates; i++) { a[k] = c[i]; make_move(a, k, input); backtrack(a, k, input); unmake_move(a, k, input); if (finished) return; } } }
void record_a_move(int x, int y, int to_x, int to_y, int captures_only, int depth) { //printf("record(%d,%d,%d,%d,%d,%d)\n",x,y,to_x,to_y,captures_only,depth); if (captures_only && board.cells[to_x][to_y] == 0) return; if (board.cells[x][y]) ++attacked_squares[depth][to_x][to_y]; if (attacked_squares_only == 0) { int check; moves[depth][move_counter[depth]].x = x; moves[depth][move_counter[depth]].y = y; moves[depth][move_counter[depth]].piece = board.cells[x][y]; moves[depth][move_counter[depth]].to_x = to_x; moves[depth][move_counter[depth]].to_y = to_y; moves[depth][move_counter[depth]].captured_piece = board.cells[to_x][to_y]; make_move(&moves[depth][move_counter[depth]]); board.side = !board.side; // these switches are dumb check = in_check(depth); board.side = !board.side; unmake_move(&moves[depth][move_counter[depth]]); if (!check) ++move_counter[depth]; } }
Bitmap xperft(int depth) { Bitmap x, k, desde, hasta, r; desde = (Bitmap) board.ply_moves[board.ply - 1]; hasta = (Bitmap) board.ply_moves[board.ply]; if (depth > 1) { x = 0; // xfen();xl(); for (k = desde; k < hasta; k++) { // b0 = board; //DBG make_move(board.moves[k]); movegen(); r = xperft(depth - 1); x += r; unmake_move(); } return x; } else { return hasta - desde; } }
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; }
void hash_expand_pv( int side_to_move, int mode, int flags, int max_selectivity ) { int i; int pass_count; int new_pv_depth; int new_pv[61]; int new_side_to_move[61]; HashEntry entry; determine_hash_values( side_to_move, board ); new_pv_depth = 0; pass_count = 0; while ( pass_count < 2 ) { new_side_to_move[new_pv_depth] = side_to_move; if ( (new_pv_depth < pv_depth[0]) && (new_pv_depth == 0) ) { if ( (board[pv[0][new_pv_depth]] == EMPTY) && make_move( side_to_move, pv[0][new_pv_depth], TRUE ) ) { new_pv[new_pv_depth] = pv[0][new_pv_depth]; new_pv_depth++; pass_count = 0; } else { hash1 ^= hash_flip_color1; hash2 ^= hash_flip_color2; pass_count++; } } else { find_hash( &entry, mode ); if ( (entry.draft != NO_HASH_MOVE) && (entry.flags & flags) && (entry.selectivity <= max_selectivity) && (board[entry.move[0]] == EMPTY) && make_move( side_to_move, entry.move[0], TRUE ) ) { new_pv[new_pv_depth] = entry.move[0]; new_pv_depth++; pass_count = 0; } else { hash1 ^= hash_flip_color1; hash2 ^= hash_flip_color2; pass_count++; } } side_to_move = OPP( side_to_move ); } for ( i = new_pv_depth - 1; i >= 0; i-- ) unmake_move( new_side_to_move[i], new_pv[i] ); for ( i = 0; i < new_pv_depth; i++ ) pv[0][i] = new_pv[i]; pv_depth[0] = new_pv_depth; }
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; }
BOOL test_make_unmake() { BOOL ok = TRUE; int i, j; struct t_move_list moves[1]; struct t_undo undo[1]; set_fen(position, "rnbqkb1r/ppppp1pp/7n/5p2/4P3/8/PPPP1PPP/RNBQKBNR w KQkq -"); assert(integrity(position)); for (j = WHITE; j <= BLACK; j++) { generate_moves(position, moves); for (i = 0; i < moves->count; i++) { assert(integrity(position)); if (make_move(position, moves->pinned_pieces, moves->move[i], undo)) { assert(integrity(position)); unmake_move(position, undo); assert(integrity(position)); } } flip_board(position); } ok = integrity(position); set_fen(position, "r3Rbk1/2p2p1p/p2p4/1p1P2q1/8/PBPQ2pP/1P3P1P/3R2K1 b - -"); assert(integrity(position)); for (j = WHITE; j <= BLACK; j++) { generate_moves(position, moves); for (i = 0; i < moves->count; i++) { assert(integrity(position)); if (make_move(position, moves->pinned_pieces, moves->move[i], undo)) { assert(integrity(position)); unmake_move(position, undo); assert(integrity(position)); } } flip_board(position); } ok &= integrity(position); return ok; }
/** pgn_save(): pgn_save saves the current game into a pgn file. If the file already exists, it appends the game to the end. Created 091407; last modified 091407 **/ void pgn_save(char *file_name) { FILE *pgn_file; char text[80]; GAME_ENTRY *current_entry; pgn_file = fopen(file_name, "at"); if (pgn_file == NULL) { print("%s: file not found.\n"); return; } /* Make sure we have the game result, then print the PGN tags. */ check_result(FALSE); strcpy(pgn_game.tag.result, result_str[zct->game_result]); fprintf(pgn_file, "[Event \"%s\"]\n", pgn_game.tag.event); fprintf(pgn_file, "[Site \"%s\"]\n", pgn_game.tag.site); fprintf(pgn_file, "[Date \"%s\"]\n", pgn_game.tag.date); fprintf(pgn_file, "[Round \"%s\"]\n", pgn_game.tag.round); fprintf(pgn_file, "[White \"%s\"]\n", pgn_game.tag.white); fprintf(pgn_file, "[Black \"%s\"]\n", pgn_game.tag.black); fprintf(pgn_file, "[Result \"%s\"]\n", pgn_game.tag.result); if (strcmp(pgn_game.tag.fen, "") != 0) fprintf(pgn_file, "[FEN \"%s\"]\n", pgn_game.tag.fen); fprintf(pgn_file, "\n"); /* Return to the beginning of the game. */ current_entry = board.game_entry; while (board.game_entry > board.game_stack) unmake_move(); /* Start with the proper move number indicator, depending on the side. We have to check that at least one move has been made before this. */ if (board.game_entry < current_entry) { sprint(text, 80, "%i.%s%M ", board.move_number, board.side_tm == WHITE ? "" : "..", board.game_entry->move); make_move(board.game_entry->move); } /* Wade through the rest of the game. */ while (board.game_entry < current_entry) { if (board.side_tm == WHITE) sprint(text, 80, "%s%i.", text, board.move_number); sprint(text, 80, "%s%M ", text, board.game_entry->move); make_move(board.game_entry->move); if (strlen(text) >= 70) { fprintf(pgn_file, "%s\n", text); strcpy(text, ""); } } fprintf(pgn_file, "%s%s\n\n", text, result_str[zct->game_result]); fclose(pgn_file); }
// undo moves until player is a human and he can make a move void _droidzebra_undo_turn(int *side_to_move) { int human_can_move = 0; int curr_move; if (score_sheet_row == 0 && *side_to_move == BLACKSQ) return; _droidzebra_undo_stack_push(disks_played); do { *side_to_move = OPP(*side_to_move); if (*side_to_move == WHITESQ) score_sheet_row--; human_can_move = skill[*side_to_move] == 0 && !( (auto_make_forced_moves && move_count[disks_played - 1] == 1) || (*side_to_move == WHITESQ && white_moves[score_sheet_row] == PASS) || (*side_to_move == BLACKSQ && black_moves[score_sheet_row] == PASS) ); if (*side_to_move == WHITESQ) { curr_move = white_moves[score_sheet_row]; if (white_moves[score_sheet_row] != PASS) unmake_move(WHITESQ, white_moves[score_sheet_row]); white_moves[score_sheet_row] = PASS; } else { curr_move = black_moves[score_sheet_row]; if (black_moves[score_sheet_row] != PASS) unmake_move(BLACKSQ, black_moves[score_sheet_row]); black_moves[score_sheet_row] = PASS; } droidzebra_message_debug( "undo: side_to_move %d, undo_move %d, score_sheet_row %d, disks_played %d, move_count %d", *side_to_move, curr_move, score_sheet_row, disks_played, move_count[disks_played]); } while (!(score_sheet_row == 0 && *side_to_move == BLACKSQ) && !human_can_move); clear_endgame_performed(); }
t_nodes do_perft(struct t_board *board, int depth) { struct t_move_list move_list[1]; struct t_move_list bad_move_list[1]; bad_move_list->count = 0; bad_move_list->imove = 0; struct t_undo undo[1]; t_nodes nodes = 0; int i; assert(integrity(board)); if (board->in_check) { generate_evade_check(board, move_list); if (depth == 1) return move_list->count; } else { //generate_captures(board, move_list); //generate_quiet_moves(board, move_list); generate_moves(board, move_list); //if (!equal_move_lists(move_list, xmove_list)){ // write_board(board, "board.txt"); // write_move_list(xmove_list, "all.txt"); // write_move_list(move_list, "inc.txt"); //} if (depth == 1) return legal_move_count(board, move_list); } for (i = move_list->count - 1; i >= 0; i--) { assert(lookup_move(board, move_as_str(move_list->move[i])) == move_list->move[i]); if (make_next_move(board, move_list, bad_move_list, undo)) { assert(integrity(board)); //nodes++; if (depth > 1) nodes += do_perft(board, depth - 1); else nodes++; unmake_move(board, undo); assert(integrity(board)); } else assert(integrity(board)); } return nodes; }
void add_root_move(position_t *pos, search_stack_t *sstack, move_t move, root_move_list_t *list) { undo_info_t u[1]; if(move_is_legal(pos, move)) { list->moves[list->num].move = move; list->moves[list->num].nodes = 0; list->moves[list->num].cumulative_nodes = 0; sstack[0].move = move; make_move(pos, move, u); // list->moves[list->num].depth_1_score = search(pos, sstack, 1, 0, 0); list->moves[list->num].score = WORSTSCORE; unmake_move(pos, move, u); list->num++; } }
void record_a_spawn(piece, to_x, to_y, depth) { int check; moves[depth][move_counter[depth]].x = -1; moves[depth][move_counter[depth]].y = -1; moves[depth][move_counter[depth]].piece = piece; moves[depth][move_counter[depth]].to_x = to_x; moves[depth][move_counter[depth]].to_y = to_y; moves[depth][move_counter[depth]].captured_piece = 0; make_move(&moves[depth][move_counter[depth]]); board.side = !board.side; // these switches are dumb check = in_check(depth); board.side = !board.side; unmake_move(&moves[depth][move_counter[depth]]); if (!check) ++move_counter[depth]; }
U64 perft(int depth) { Move movelist[256]; int n; U64 result = 0; if(depth == 0) return 1; n = generate_moves(movelist); for(int i = 0; i < n; i += 1) { Move i_move = movelist[i]; make_move(i_move); result += perft(depth - 1); unmake_move(i_move); } return result; }
int Search::capture_quiescence_eval_search(bool white_turn, int alpha, int beta, Board& board) { if (board.b[WHITE][KING] == 0) { return -10000; } else if (board.b[BLACK][KING] == 0) { return 10000; } int static_eval = evaluate(board); if (static_eval > alpha && white_turn) { return static_eval; } if (static_eval < beta && !white_turn) { return static_eval; } MoveList capture_moves = get_captures(board, white_turn); if (capture_moves.empty()) { // the end point of the quiescence search return static_eval; } for (unsigned int i = 0; i < capture_moves.size(); ++i) { pick_next_move(capture_moves, i); Move move = capture_moves[i]; quiescence_node_count++; make_move(board, move); int res = capture_quiescence_eval_search(!white_turn, alpha, beta, board); unmake_move(board, move); if (res > alpha && white_turn) { alpha = res; } if (res < beta && !white_turn) { beta = res; } if (beta <= alpha || time_to_stop()) { break; } } if (white_turn) { return alpha; } return beta; }
BOOL test_ep_capture() { uci_set_mode(); uci_isready(); set_hash(512); set_own_book(TRUE); uci_position(position, "position fen 2r2bk1/1pNb4/3p3q/p2Pp2n/2P1PpPP/5P2/PPn1Q3/2KR3R b - g3"); struct t_move_list moves[1]; t_undo undo[1]; generate_moves(position, moves); for (int i = 0; i < moves->count; i++){ if (make_move(position, moves->pinned_pieces, moves->move[i], undo)) unmake_move(position, undo); } return TRUE; }
void backtrack(int a[], int k, data input) { int c[MAXCANDIDATES]; /* candidates for next position */ int ncandidates; /* next position candidates count */ int i; if (is_a_solution(a, k, input)) process_solution(a, k, input); else { ++k; construct_candidates(a, k, input, c, &ncandidates); for (i=0; i<ncandidates; ++i) { a[k] = c[i]; make_move(a, k, input); backtrack(a, k, input); unmake_move(a, k, input); if (finished) return; } } }
void update_best_line_from_hash(struct t_board *board, int ply) { struct t_pv_data *pv = &(board->pv_data[ply]); t_move_record *move; t_hash_record *hash_record; t_undo undo[1]; hash_record = probe(board->hash); if (hash_record != NULL && hash_record->bound == HASH_EXACT && hash_record->move != NULL){ move = hash_record->move; hash_record->age = hash_age; if (is_move_legal(board, move)) make_move(board, 0, move, undo); else return; pv->best_line[pv->best_line_length++] = move; if (!repetition_draw(board)) update_best_line_from_hash(board, ply); unmake_move(board, undo); } }
unsigned int perft_perft(Board* board, unsigned int depth) { int i, nperft = 0; Move moves[256]; if (depth == 0) { return 1; } TTEntry* ttentry = get_tt_entry_at_depth(board->zobrist, depth); if (ttentry) { return ttentry->score; } unsigned int numMoves = generate_moves(board, moves); for (i = 0; i < numMoves; ++i) { make_move(board, moves[i]); if ((board->sideToMove == BLACK && !black_attacks_square(board, bit_scan_forward(board->pieces[WHITE_KING]))) || (board->sideToMove == WHITE && !white_attacks_square(board, bit_scan_forward(board->pieces[BLACK_KING])))) { nperft += perft_perft(board, depth - 1); } unmake_move(board, moves[i]); } TTEntry new_entry; new_entry.key = board->zobrist; new_entry.score = nperft; new_entry.depth = depth; put_tt_entry(&new_entry); return nperft; }
void complete_pv( int side_to_move ) { int i; int actual_side_to_move[60]; full_pv_depth = 0; for ( i = 0; i < pv_depth[0]; i++ ) { if ( make_move( side_to_move, pv[0][i], TRUE ) ) { actual_side_to_move[i] = side_to_move; full_pv[full_pv_depth] = pv[0][i]; full_pv_depth++; } else { full_pv[full_pv_depth] = PASS; full_pv_depth++; side_to_move = OPP( side_to_move ); if ( make_move( side_to_move, pv[0][i], TRUE ) ) { actual_side_to_move[i] = side_to_move; full_pv[full_pv_depth] = pv[0][i]; full_pv_depth++; } else { #ifdef TEXT_BASED int j; printf( "pv_depth[0] = %d\n", pv_depth[0] ); for ( j = 0; j < pv_depth[0]; j++ ) printf( "%c%c ", TO_SQUARE( pv[0][j] ) ); puts( "" ); printf( "i=%d\n", i ); #endif fatal_error( PV_ERROR ); } } side_to_move = OPP( side_to_move ); } for ( i = pv_depth[0] - 1; i >= 0; i-- ) unmake_move( actual_side_to_move[i], pv[0][i] ); }
backtrack(int a[], int k, data input) { int c[MAXCANDIDATES]; /* candidates for next position */ int ncandidates; /* next position candidate count */ int i; /* counter */ if (is_a_solution(a,k,input)) process_solution(a,k,input); else { k = k+1; construct_candidates(a,k,input,c,&ncandidates); for (i=0; i<ncandidates; i++) { a[k] = c[i]; make_move(a,k,input); backtrack(a,k,input); if (finished) return; /* terminate early */ unmake_move(a,k,input); } } }
t_nodes perft(struct t_board *board, int depth) { struct t_move_list move_list[1]; struct t_undo undo[1]; t_nodes total_nodes = 0; t_nodes move_nodes = 0; unsigned long start = time_now(); int i; if (board->in_check) generate_evade_check(board, move_list); else generate_moves(board, move_list); for (i = move_list->count - 1; i >= 0; i--) { if (make_move(board, move_list->pinned_pieces, move_list->move[i], undo)) { move_nodes = 0; if (depth > 1) move_nodes += do_perft(board, depth - 1); printf(move_as_str(move_list->move[i])); printf(" = %u\n", move_nodes); unmake_move(board, undo); total_nodes += move_nodes; } } unsigned long finish = time_now(); if (finish == start) printf("Total Nodes: %I64d\n", total_nodes); else printf("Total Nodes: %I64d in %d milliseconds = nps %I64d\n", total_nodes, finish - start, 1000 * total_nodes / (finish - start)); return total_nodes; }
void generate_subsequences(const std::string& from , int index , std::string& to , std::unordered_set<std::string>& subsequences) { if(be_a_solution(from, index)) { process_solution(to, subsequences); } else { //construct_candidates char candidates[2] = {from[index], '\0'}; int sz=to.size(); for(size_t i=0; i<2; ++i) { if(candidates[i]!='\0') to.push_back(candidates[i]); //make_move generate_subsequences(from, index+1, to, subsequences); unmake_move(to, sz); } } }
/** stop_search(): This checks for time and input to see if need to stop searching. Created 091006; last modified 030709 **/ BOOL stop_search(void) { CMD_RESULT cmd_result; BOOL stop = FALSE; GAME_ENTRY *current; if (zct->stop_search) stop = TRUE; /* Check for input, because we might enter this function more than once before fully stopping when unwinding the stack. */ else if (zct->input_buffer[0]) stop = TRUE; else if (time_is_up()) stop = TRUE; else if (input_available()) { /* Return to the root position. Some commands, such as "display" work on the root position instead of the current one. */ current = board.game_entry; while (board.game_entry > root_entry) unmake_move(); /* When pondering, the root entry is after the ponder move. */ if (zct->engine_state == PONDERING) unmake_move(); /* Read the command and parse it. */ read_line(); cmd_result = command(zct->input_buffer); /* Command() returns CMD_STOP_SEARCH when we need to exit the search to handle a command. */ if (cmd_result == CMD_STOP_SEARCH) stop = TRUE; /* If the command was a move, either stop or make the move. */ else if (zct->engine_state != NORMAL && cmd_result == CMD_BAD && input_move(zct->input_buffer, INPUT_CHECK_MOVE)) { /* If we are pondering, check if the move entered was the ponder move. If so, we don't need to stop. */ if (zct->engine_state == PONDERING && input_move(zct->input_buffer, INPUT_GET_MOVE) == zct->ponder_move) { zct->input_buffer[0] = '\0'; make_move(zct->ponder_move); zct->engine_state = NORMAL; update_clocks(); } else stop = TRUE; } else if (cmd_result == CMD_BAD) { zct->input_buffer[0] = '\0'; if (zct->protocol != UCI) print("Error.\n"); } /* Check for ping here in UCI mode. */ if (zct->ping && zct->protocol == UCI) { print("readyok\n"); zct->ping = 0; } /* Go back to the position we were in before checking. This is kind of hacky in that it relies on the game history after undoing all the moves to be the same. */ while (board.game_entry < current) make_move(board.game_entry->move); } /* If we're stopping the search, set a flag to make sure we don't come back here and decide to keep going, thereby introducing bugs... */ if (stop) zct->stop_search = TRUE; return stop; }
/** search_maintenance(): In every node during a search, do some checks for SMP events, timeout, etc. If the search needs to exit, we store the return value in return_value and return TRUE, otherwise we return FALSE. Created 031609; last modified 031609 **/ BOOL search_maintenance(SEARCH_BLOCK **sb, VALUE *return_value) { #ifdef SMP int r; /* Handle any asynchronous messages we have. */ if (smp_block[board.id].message_count) handle_smp_messages(sb); /* Check for synchronous messages, and exit if necessary. */ if (smp_block[board.id].input) { if (handle_smp_input(*sb)) { *return_value = 0; return TRUE; } } /* If another processor has backed up to the root, they set a flag because only the main processor can return to search_root(). */ if (board.id == 0 && smp_data->return_flag) { ASSERT(board.split_point == board.split_point_stack); ASSERT(smp_data->split_count == 0); /* Back up the game board. */ while (board.game_entry > root_entry + 1) unmake_move(); /* This is kind of hacky... */ if (board.game_entry == root_entry) make_move((zct->next_root_move - 1)->move); SMP_DEBUG(print("cpu 0 returning...\n%B",&board)); smp_data->return_flag = FALSE; set_active(); /* Return the score and PV. */ copy_pv(board.pv_stack[1], smp_data->return_pv); *return_value = smp_data->return_value; return TRUE; } #endif /* Do the standard periodic check for time or input. */ if (search_check()) { #ifdef SMP /* Flag the other processors down. */ for (r = 1; r < zct->process_count; r++) smp_tell(r, SMP_PARK, 0); /* Unsplit all of our split points, after waiting for the child processors to detach. */ while (*board.split_point != NULL) { while ((*board.split_point)->child_count > 1) ; unsplit(*sb, (*board.split_point)->id); } #endif /* We're good to go. Stop the search. */ while (board.game_entry > root_entry + 1) unmake_move(); /* This is kind of hacky... */ if (board.game_entry == root_entry) make_move((zct->next_root_move - 1)->move); /* Return a really good score, so the root move appears to be a mated-in-0. This just invalidates the score. */ *return_value = MATE; return TRUE; } return FALSE; }
int extended_compute_move( int side_to_move, int book_only, int book, int mid, int exact, int wld ) { int i, j; int index; int changed; int this_move; int disc_diff, corrected_diff; int best_move, temp_move; int best_score; int best_pv_depth; int stored_echo; int shallow_eval; int empties; int current_mid, current_exact, current_wld; int first_iteration; int unsearched; int unsearched_count; int unsearched_move[61]; int best_pv[60]; unsigned int transform1[60], transform2[60]; CandidateMove book_move; EvaluatedMove temp; EvaluationType book_eval_info; EvalResult res; /* Disable all time control mechanisms and randomization */ toggle_abort_check( FALSE ); toggle_midgame_abort_check( FALSE ); toggle_perturbation_usage( FALSE ); start_move( 0, 0, disc_count( BLACKSQ ) + disc_count( WHITESQ ) ); clear_ponder_times(); determine_hash_values( side_to_move, board ); empties = 60 - disks_played; best_move = 0; game_evaluated_count = 0; reset_counter( &nodes ); generate_all( side_to_move ); if ( book_only || book ) { /* Evaluations for database moves */ int flags = 0; if ( empties <= exact ) flags = FULL_SOLVED; else if ( empties <= wld ) flags = WLD_SOLVED; fill_move_alternatives( side_to_move, flags ); game_evaluated_count = get_candidate_count(); for ( i = 0; i < game_evaluated_count; i++ ) { int child_flags; book_move = get_candidate( i ); evaluated_list[i].side_to_move = side_to_move; evaluated_list[i].move = book_move.move; evaluated_list[i].pv_depth = 1; evaluated_list[i].pv[0] = book_move.move; evaluated_list[i].eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, book_move.score, 0.0, 0, TRUE ); child_flags = book_move.flags & book_move.parent_flags; if ( child_flags & (FULL_SOLVED | WLD_SOLVED) ) { if ( child_flags & FULL_SOLVED ) evaluated_list[i].eval.type = EXACT_EVAL; else evaluated_list[i].eval.type = WLD_EVAL; if ( book_move.score > 0 ) { evaluated_list[i].eval.res = WON_POSITION; /* Normalize the scores so that e.g. 33-31 becomes +256 */ evaluated_list[i].eval.score -= CONFIRMED_WIN; evaluated_list[i].eval.score *= 128; } else if ( book_move.score == 0 ) evaluated_list[i].eval.res = DRAWN_POSITION; else { /* score < 0 */ evaluated_list[i].eval.res = LOST_POSITION; /* Normalize the scores so that e.g. 30-34 becomes -512 */ evaluated_list[i].eval.score += CONFIRMED_WIN; evaluated_list[i].eval.score *= 128; } } else evaluated_list[i].eval.type = MIDGAME_EVAL; } } if ( book_only ) { /* Only book moves are to be considered */ if ( game_evaluated_count > 0 ) { best_move = get_book_move( side_to_move, FALSE, &book_eval_info ); set_current_eval( book_eval_info ); } else { pv_depth[0] = 0; best_move = PASS; book_eval_info = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); set_current_eval( book_eval_info ); } } else { /* Make searches for moves not in the database */ int shallow_depth; int empties = 60 - disks_played; book = FALSE; best_score = -INFINITE_EVAL; if ( game_evaluated_count > 0 ) { /* Book PV available */ best_score = evaluated_list[0].eval.score; best_move = evaluated_list[0].move; } negate_current_eval( TRUE ); /* Store the available moves, clear their evaluations and sort them on shallow evaluation. */ if ( empties < 12 ) shallow_depth = 1; else { int max_depth = MAX( mid, MAX( exact, wld ) ); if ( max_depth >= 16 ) shallow_depth = 6; else shallow_depth = 4; } unsearched_count = 0; for ( i = 0; i < move_count[disks_played]; i++ ) { this_move = move_list[disks_played][i]; unsearched = TRUE; for ( j = 0; j < game_evaluated_count; j++ ) if ( evaluated_list[j].move == this_move ) unsearched = FALSE; if ( !unsearched ) continue; unsearched_move[unsearched_count] = this_move; unsearched_count++; (void) make_move( side_to_move, this_move, TRUE ); if ( shallow_depth == 1 ) /* Compute move doesn't allow depth 0 */ shallow_eval = -static_evaluation( OPP( side_to_move ) ); else { EvaluationType shallow_info; (void) compute_move( OPP( side_to_move ), FALSE, 0, 0, FALSE, book, shallow_depth - 1, 0, 0, TRUE, &shallow_info ); if ( shallow_info.type == PASS_EVAL ) { /* Don't allow pass */ (void) compute_move( side_to_move, FALSE, 0, 0, FALSE, book, shallow_depth - 1, 0, 0, TRUE, &shallow_info ); if ( shallow_info.type == PASS_EVAL ) { /* Game over */ disc_diff = disc_count( side_to_move ) - disc_count( OPP( side_to_move ) ); if ( disc_diff > 0 ) corrected_diff = 64 - 2 * disc_count( OPP( side_to_move) ); else if ( disc_diff == 0 ) corrected_diff = 0; else corrected_diff = 2 * disc_count( side_to_move ) - 64; shallow_eval = 128 * corrected_diff; } else shallow_eval = shallow_info.score; } else /* Sign-correct the score produced */ shallow_eval = -shallow_info.score; } unmake_move( side_to_move, this_move ); evals[disks_played][this_move] = shallow_eval; } do { changed = FALSE; for ( i = 0; i < unsearched_count - 1; i++ ) if ( evals[disks_played][unsearched_move[i]] < evals[disks_played][unsearched_move[i + 1]] ) { temp_move = unsearched_move[i]; unsearched_move[i] = unsearched_move[i + 1]; unsearched_move[i + 1] = temp_move; changed = TRUE; } } while ( changed ); /* Initialize the entire list as being empty */ for ( i = 0, index = game_evaluated_count; i < unsearched_count; i++, index++ ) { evaluated_list[index].side_to_move = side_to_move; evaluated_list[index].move = unsearched_move[i]; evaluated_list[index].eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); evaluated_list[index].pv_depth = 1; evaluated_list[index].pv[0] = unsearched_move[i]; if ( empties > MAX( wld, exact ) ) { transform1[i] = abs( my_random() ); transform2[i] = abs( my_random() ); } else { transform1[i] = 0; transform2[i] = 0; } } stored_echo = echo; echo = FALSE; best_pv_depth = 0; if ( mid == 1 ) { /* compute_move won't be called */ pv_depth[0] = 0; piece_count[BLACKSQ][disks_played] = disc_count( BLACKSQ ); piece_count[WHITESQ][disks_played] = disc_count( WHITESQ ); } /* Perform iterative deepening if the search depth is large enough */ #define ID_STEP 2 if ( exact > empties ) exact = empties; if ( (exact < 12) || (empties > exact) ) current_exact = exact; else current_exact = (8 + (exact % 2)) - ID_STEP; if ( wld > empties ) wld = empties; if ( (wld < 14) || (empties > wld) ) current_wld = wld; else current_wld = (10 + (wld % 2)) - ID_STEP; if ( ((empties == exact) || (empties == wld)) && (empties > 16) && (mid < empties - 12) ) mid = empties - 12; if ( mid < 10 ) current_mid = mid; else current_mid = (6 + (mid % 2)) - ID_STEP; first_iteration = TRUE; do { if ( current_mid < mid ) { current_mid += ID_STEP; /* Avoid performing deep midgame searches if the endgame is reached anyway. */ if ( (empties <= wld) && (current_mid + 7 >= empties) ) { current_wld = wld; current_mid = mid; } if ( (empties <= exact) && (current_mid + 7 >= empties) ) { current_exact = exact; current_mid = mid; } } else if ( current_wld < wld ) current_wld = wld; else current_exact = exact; for ( i = 0; (i < unsearched_count) && !force_return; i++ ) { EvaluationType this_eval; this_move = unsearched_move[i]; /* Locate the current move in the list. This has to be done because the moves might have been reordered during the iterative deepening. */ index = 0; while ( evaluated_list[index].move != this_move ) index++; /* To avoid strange effects when browsing back and forth through a game during the midgame, rehash the hash transformation masks for each move unless the endgame is reached */ set_hash_transformation( transform1[i], transform2[i] ); /* Determine the score for the ith move */ prefix_move = this_move; (void) make_move( side_to_move, this_move, TRUE ); if ( current_mid == 1 ) { /* compute_move doesn't like 0-ply searches */ shallow_eval = static_evaluation( OPP( side_to_move ) ); this_eval = create_eval_info( MIDGAME_EVAL, UNSOLVED_POSITION, shallow_eval, 0.0, 0, FALSE ); } else (void) compute_move( OPP( side_to_move ), FALSE, 0, 0, FALSE, book, current_mid - 1, current_exact - 1, current_wld - 1, TRUE, &this_eval ); if ( force_return ) { /* Clear eval and exit search immediately */ this_eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); unmake_move( side_to_move, this_move ); break; } if ( this_eval.type == PASS_EVAL ) { /* Don't allow pass */ if ( current_mid == 1 ) { /* compute_move doesn't like 0-ply searches */ shallow_eval = static_evaluation( side_to_move ); this_eval = create_eval_info( MIDGAME_EVAL, UNSOLVED_POSITION, shallow_eval, 0.0, 0, FALSE ); } else (void) compute_move( side_to_move, FALSE, 0, 0, FALSE, book, current_mid - 1, current_exact - 1, current_wld - 1, TRUE, &this_eval ); if ( this_eval.type == PASS_EVAL ) { /* Game over */ disc_diff = disc_count( side_to_move ) - disc_count( OPP( side_to_move ) ); if ( disc_diff > 0 ) { corrected_diff = 64 - 2 * disc_count( OPP( side_to_move) ); res = WON_POSITION; } else if ( disc_diff == 0 ) { corrected_diff = 0; res = DRAWN_POSITION; } else { corrected_diff = 2 * disc_count( side_to_move ) - 64; res = LOST_POSITION; } this_eval = create_eval_info( EXACT_EVAL, res, 128 * corrected_diff, 0.0, 60 - disks_played, FALSE ); } } else { /* Sign-correct the score produced */ this_eval.score = -this_eval.score; if ( this_eval.res == WON_POSITION ) this_eval.res = LOST_POSITION; else if ( this_eval.res == LOST_POSITION ) this_eval.res = WON_POSITION; } if ( force_return ) break; else evaluated_list[index].eval = this_eval; /* Store the PV corresponding to the move */ evaluated_list[index].pv_depth = pv_depth[0] + 1; evaluated_list[index].pv[0] = this_move; for ( j = 0; j < pv_depth[0]; j++ ) evaluated_list[index].pv[j + 1] = pv[0][j]; /* Store the PV corresponding to the best move */ if ( evaluated_list[index].eval.score > best_score ) { best_score = evaluated_list[index].eval.score; best_move = this_move; best_pv_depth = pv_depth[0]; for ( j = 0; j < best_pv_depth; j++ ) best_pv[j] = pv[0][j]; } unmake_move( side_to_move, this_move ); /* Sort the moves evaluated */ if ( first_iteration ) game_evaluated_count++; if ( !force_return ) do { changed = FALSE; for ( j = 0; j < game_evaluated_count - 1; j++ ) if ( compare_eval( evaluated_list[j].eval, evaluated_list[j + 1].eval ) < 0 ) { changed = TRUE; temp = evaluated_list[j]; evaluated_list[j] = evaluated_list[j + 1]; evaluated_list[j + 1] = temp; } } while ( changed ); display_status(stdout, FALSE); } first_iteration = FALSE; /* Reorder the moves after each iteration. Each move is moved to the front of the list, starting with the bad moves and ending with the best move. This ensures that unsearched_move will be sorted w.r.t. the order in evaluated_list. */ for ( i = game_evaluated_count - 1; i >= 0; i-- ) { int this_move = evaluated_list[i].move; j = 0; while ( (j != unsearched_count) && (unsearched_move[j] != this_move) ) j++; if ( j == unsearched_count ) /* Must be book move, skip */ continue; /* Move the move to the front of the list. */ while ( j >= 1 ) { unsearched_move[j] = unsearched_move[j - 1]; j--; } unsearched_move[0] = this_move; } } while ( !force_return && ((current_mid != mid) || (current_exact != exact) || (current_wld != wld)) ); echo = stored_echo; game_evaluated_count = move_count[disks_played]; /* Make sure that the PV and the score correspond to the best move */ pv_depth[0] = best_pv_depth + 1; pv[0][0] = best_move; for ( i = 0; i < best_pv_depth; i++ ) pv[0][i + 1] = best_pv[i]; negate_current_eval( FALSE ); if ( move_count[disks_played] > 0 ) set_current_eval( evaluated_list[0].eval ); } /* Reset the hash transformation masks prior to leaving */ set_hash_transformation( 0, 0 ); /* Don't forget to enable the time control mechanisms when leaving */ toggle_abort_check( TRUE ); toggle_midgame_abort_check( TRUE ); toggle_perturbation_usage( TRUE ); max_depth_reached++; prefix_move = 0; return best_move; }
uint64_t test_perft_rec(state_t *state, int depth, int verbose) { /* Given a position, it will recursivly apply every possible * move for a given depth and count the leaf nodes. */ if (depth == 0) { return 1; } hash_node_t *hash_node = hash_get_node(state->zobrist); /* Check if hashing is enabled */ if (hash_node) { if (hash_node->hash == state->zobrist && hash_node->depth == depth) { ++_cache_hits; return hash_node->score; } else { ++_cache_misses; } } int moves[100]; int count = 0, count2 = 0; move_generate_moves(state, moves, &count); move_generate_tactical(state, moves + count, &count2); count += count2; /* Check for invalid position or board with no pieces :) */ if (count <= 0) { return 0; } uint64_t nodes = 0; int i; for (i = 0; i < count; ++i) { make_move(state, moves[i], depth); if (move_is_attacked(state, state->king_idx[Flip(state->turn)], state->turn)) { unmake_move(state, moves[i], depth); continue; } uint64_t res = test_perft_rec(state, depth - 1, 0); nodes += res; if (verbose && res > 0) { char move_str[16]; util_move_to_lan(moves[i], move_str); printf("%s: %lld\n", move_str, res); } unmake_move(state, moves[i], depth); } hash_add_node(state->zobrist, nodes, depth, 0, 0); return nodes; }
void perform_extended_solve( int side_to_move, int actual_move, int book, int exact_solve ) { int i; int mid, wld, exact; int best_move; int disc_diff, corrected_diff; EvaluatedMove temp; EvalResult res; /* Disable all time control mechanisms */ toggle_abort_check( FALSE ); toggle_midgame_abort_check( FALSE ); toggle_perturbation_usage( FALSE ); start_move( 0, 0, disc_count( BLACKSQ ) + disc_count( WHITESQ ) ); clear_ponder_times(); determine_hash_values( side_to_move, board ); reset_counter( &nodes ); /* Set search depths that result in Zebra solving after a brief midgame analysis */ mid = 60; wld = 60; if ( exact_solve ) exact = 60; else exact = 0; game_evaluated_count = 1; /* Calculate the score for the preferred move */ evaluated_list[0].side_to_move = side_to_move; evaluated_list[0].move = actual_move; evaluated_list[0].eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); evaluated_list[0].pv_depth = 1; evaluated_list[0].pv[0] = actual_move; prefix_move = actual_move; negate_current_eval( TRUE ); (void) make_move( side_to_move, actual_move, TRUE ); (void) compute_move( OPP( side_to_move ), FALSE, 0, 0, FALSE, book, mid - 1, exact - 1, wld - 1, TRUE, &evaluated_list[0].eval ); if ( evaluated_list[0].eval.type == PASS_EVAL ) { /* Don't allow pass */ (void) compute_move( side_to_move, FALSE, 0, 0, FALSE, book, mid - 1, exact - 1, wld - 1, TRUE, &evaluated_list[0].eval ); if ( evaluated_list[0].eval.type == PASS_EVAL ) { /* Game has ended */ disc_diff = disc_count( side_to_move ) - disc_count( OPP( side_to_move ) ); if ( disc_diff > 0 ) { corrected_diff = 64 - 2 * disc_count( OPP( side_to_move) ); res = WON_POSITION; } else if ( disc_diff == 0 ) { corrected_diff = 0; res = DRAWN_POSITION; } else { corrected_diff = 2 * disc_count( side_to_move ) - 64; res = LOST_POSITION; } evaluated_list[0].eval = create_eval_info( EXACT_EVAL, res, 128 * corrected_diff, 0.0, 60 - disks_played, FALSE ); } } else { /* Sign-correct the score produced */ evaluated_list[0].eval.score = -evaluated_list[0].eval.score; if ( evaluated_list[0].eval.res == WON_POSITION ) evaluated_list[0].eval.res = LOST_POSITION; else if ( evaluated_list[0].eval.res == LOST_POSITION ) evaluated_list[0].eval.res = WON_POSITION; } if ( force_return ) evaluated_list[0].eval = create_eval_info( UNDEFINED_EVAL, UNSOLVED_POSITION, 0, 0.0, 0, FALSE ); else { evaluated_list[0].pv_depth = pv_depth[0] + 1; evaluated_list[0].pv[0] = actual_move; for ( i = 0; i < pv_depth[0]; i++ ) evaluated_list[0].pv[i + 1] = pv[0][i]; } unmake_move( side_to_move, actual_move ); prefix_move = 0; negate_current_eval( FALSE ); max_depth_reached++; /* Compute the score for the best move and store it in the move list if it isn't ACTUAL_MOVE */ best_move = compute_move( side_to_move, FALSE, 0, 0, FALSE, book, mid, exact, wld, TRUE, &evaluated_list[1].eval ); if ( !force_return && (best_move != actual_move) ) { /* Move list will contain best move first and then the actual move */ game_evaluated_count = 2; evaluated_list[1].side_to_move = side_to_move; evaluated_list[1].move = best_move; evaluated_list[1].pv_depth = pv_depth[0]; for ( i = 0; i < pv_depth[0]; i++ ) evaluated_list[1].pv[i] = pv[0][i]; temp = evaluated_list[0]; evaluated_list[0] = evaluated_list[1]; evaluated_list[1] = temp; } /* The PV and current eval should when correspond to the best move when leaving */ pv_depth[0] = evaluated_list[0].pv_depth; for ( i = 0; i < pv_depth[0]; i++ ) pv[0][i] = evaluated_list[0].pv[i]; set_current_eval( evaluated_list[0].eval ); /* Don't forget to enable the time control mechanisms when leaving */ toggle_abort_check( TRUE ); toggle_midgame_abort_check( TRUE ); toggle_perturbation_usage( FALSE ); }