int board_solve(board_t *board) { if(board->count == 0) { return 0; } else { uint8_t u, l, offset = 0, lx = 0, ly = 0, u_max = 0, o_min = 9; board_t current; // Identify the maximum number of indentified squares per // unit (except those completely identified). for (u = 0; u < 9; u++) { if(board->unit_count[u] > u_max && board->unit_count[u] < 9) { u_max = board->unit_count[u]; } } // Find the square with the minimum number of possible options // within a unit with the maximum number of identified // squares. for (u = 0; u < 9; u++) { if(board->unit_count[u] != u_max) { continue; } uint8_t x, y, ui = (u % 3) * 3, uj = (u / 3) * 3; for (y = uj; y < (uj + 3); y++) { for (x = ui; x < (ui + 3); x++) { uint8_t o = board_offset(x, y); if(board->values[o] == 0 && board->options_count[o] < o_min ) { o_min = board->options_count[o]; lx = x; ly = y; offset = o; } } } } // Use this square to explore recursively for (l = 1; l < 10; l++) { uint16_t m = value_to_option(l); // We iterate on the valid options for the square if(!(m & board->options[offset])) { continue; } board_copy(¤t, board); // Work on a copy of the board if(board_set(¤t, lx, ly, l) == 0 && board_check_single(¤t) == 0 && board_solve(¤t) == 0) { // The value we tried was a success copy back the result board_copy(board, ¤t); return 0; } } } return 1; }
/*----------------------------------------------------------------------------*/ int aigo_findmoves (long pstr, long posi, long *p_moves) { GO_GAMER *gamer = (GO_GAMER*) pstr; GO_POSI *pos = (GO_POSI *) posi; GO_BOARD *a = pos->a; int num = 0; if (0) { // кажется не очень продуктивным :-( лучше делать оченку точнее GO_WORK *aigo_work = gamer->work; work_get_groups (aigo_work, a); int num_add; GO_BOARD *tmp = board_copy (a); num = find_moves_defs (aigo_work, pos->stone, tmp, p_moves, num); num = find_moves_caps (aigo_work, pos->stone, tmp, p_moves, num); num = find_moves_cont (aigo_work, tmp, p_moves, num); num_add = 15 - num; if (num_add < 0) num_add = 0; num = find_moves_random (tmp, num_add, p_moves, num); //num = find_moves_all (tmp, p_moves, num); // добрать остальные свободные ходы } else { //-------------------------------- num = find_moves_all (a, p_moves, num); } return (num); }
//copy a single move void copy_move(move * original_move, move* new_copy){ new_copy->start = original_move->start; new_copy->end = original_move->end; new_copy->promotion = original_move->promotion; new_copy->is_castle = original_move->is_castle; board_copy(original_move->board, new_copy->board); }
/* * return moves. in each move: * start = start_cord * end = one of the cords in end_cords (there can be at most 31 end cords) * board = currend board + piece moved from start to end. * this method is not relevant for pawns. */ moves cords_to_moves(cord start_cord, cord end_cords[32], char board[BOARD_SIZE][BOARD_SIZE], int color) { cord end_cord; int i = 0; move * new_move; moves new_moves = { 0 }; while (is_valid_cord(end_cord = end_cords[i++])) { new_move = malloc(sizeof(move)); if (new_move == NULL) { free_list(&new_moves, &free); return error_moves; } new_move->start = start_cord; new_move->end = end_cord; new_move->promotion = FALSE; new_move->is_castle = FALSE; board_copy(board, new_move->board); move_from_to(new_move->board, start_cord, end_cord); // check if psaudo-legal move is legal if (is_king_checked(color, new_move->board)){ // free(new_move); continue; } else if (!add_node(&new_moves, new_move, sizeof(move))){ free(new_move); free_list(&new_moves, &free); return error_moves; } free(new_move); } return new_moves; }
static coord_t * random_genmove(struct engine *e, struct board *b, struct time_info *ti, enum stone color, bool pass_all_alive) { /* Play a random coordinate. However, we must also guard * against suicide moves; repeat playing while it's a suicide * unless we keep suiciding; in that case, we probably don't * have any other moves available and we pass. */ coord_t coord; int i = 0; bool suicide = false; do { /* board_play_random() actually plays the move too; * this is desirable for MC simulations but not within * the genmove. Make a scratch new board for it. */ struct board b2; board_copy(&b2, b); board_play_random(&b2, color, &coord, NULL, NULL); suicide = (coord != pass && !group_at(&b2, coord)); board_done_noalloc(&b2); } while (suicide && i++ < 100); return coord_copy(suicide ? pass : coord); }
moves pawn_moves(settings * set, cord curr, int color) { moves piece_simple_moves; piece_simple_moves.len = 0; cord dest; move * single_move; moves promotions; int dest_color; int y_dir = (color == WHITE) ? 1 : -1; dest.y = curr.y + y_dir; for (int x = -1; x <= 1; x++) { single_move = malloc(sizeof(move)); if (single_move == NULL) { free_list(&piece_simple_moves, &free); return error_moves; } single_move->start = curr; single_move->promotion = FALSE; single_move->is_castle = FALSE; dest.x = curr.x + x; if (is_valid_cord(dest)) { dest_color = which_color(board_piece(set->board, dest)); //logical XOR: check if pawn can eat XOR move up if (color == dest_color) { free(single_move); continue; } if ((x == 0) != (dest_color == other_player(color))) { single_move->end = dest; board_copy(set->board, single_move->board); move_from_to(single_move->board, curr, dest); // check if psaudo-legal move is legal if (is_king_checked(color, single_move->board)) { free(single_move); continue; } if (dest.y == promotion_row(color)) { promotions = promote(single_move); if (promotions.len == -1){ free(single_move); free_list(&piece_simple_moves, &free); return promotions; } concat(&piece_simple_moves, promotions); } else if (!add_node(&piece_simple_moves, single_move, sizeof(move))) { //could not add node to linked list free(single_move); free_list(&piece_simple_moves, &free); return error_moves; } free(single_move); } } } return piece_simple_moves; }
solver_c::rate_t solver_c::rate(const board_c& board) const noexcept { if(board.status.is_draw()) return 0; switch(speed) { case SPEED_FAST: switch(board.next_player.player) { case player_c::PLAYER_X: if(board.status.is_win_o()) return board.size*board.size; break; case player_c::PLAYER_O: if(board.status.is_win_x()) return board.size*board.size; break; } break; case SPEED_SLOW: switch(board.next_player.player) { case player_c::PLAYER_X: if(board.status.is_win_o()) return 1; break; case player_c::PLAYER_O: if(board.status.is_win_x()) return 1; break; } break; } board_c board_copy(board); move_c* move = best_move(board_copy); board_copy.play(*move); delete move; rate_t new_rate = rate(board_copy); switch(speed) { case SPEED_FAST: if(new_rate > 0) new_rate--; else if(new_rate < 0) new_rate++; break; case SPEED_SLOW: if(new_rate > 0) new_rate++; else if(new_rate < 0) new_rate--; break; } return -new_rate; }
int AI::get_move(const Board *board_state) { std::vector<int> moves; int size = board_state->get_valid_moves(&moves); unsigned seed = ((unsigned)std::chrono::system_clock::now().time_since_epoch().count()); std::default_random_engine generator (seed); switch (Difficulty) { case AI::Easy: { std::uniform_int_distribution<int> distribution(0,size); return moves[distribution(generator)]; // random move } break; case AI::Hard: { // Takes a winning move, or a move that doesn't result in a loss before the next turn // ==================================================================// // TODO - Implement Hard AI // ==================================================================// std::uniform_int_distribution<int> distribution(0,size); for (int i = 0; i < size; i++) { int move = moves[i]; if (check_next_move(*board_state, move, this->identity) == 1) { return move; } } for (int i = 0; i < size; i++) { int move = moves[i]; if (check_next_move(*board_state, move, this->identity) == 0) { return move; } } return moves[0]; } break; case AI::Impossible: { int best_rank = -1; int move_idx = 0; for (int idx = 0; idx < size; ++idx) { Board board_copy(*board_state); int cur_rank = rank_move(board_copy, moves[idx], this->identity); if (cur_rank > best_rank) { move_idx = idx; best_rank = cur_rank; } } return moves[move_idx]; // Perfect Play } break; default: break; } }
void game_get_board(const game_t * game, board_t * board, int pos) { int start; int i; ASSERT(game!=NULL); ASSERT(board!=NULL); ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK if (pos < 0) pos = game->pos; if (pos >= game->pos) { // forward from current position start = game->pos; board_copy(board,game->board); } else { // backward => replay the whole game start = 0; board_copy(board,game->start_board); } for (i = start; i < pos; i++) move_do(board,game->move[i]); }
move_c* solver_c::modest_reverse_move(const board_c& board) const { if(!board.status.is_playable()) throw error_not_playable(); move_c moves[board.size*board.size]; int moves_number = 0; for(move_c& move : board.all_moves_on_empty) { board_c board_copy(board); board_copy.play(move); switch(board.next_player.player) { case player_c::PLAYER_X: if(!board_copy.status.is_win_x()) { moves[moves_number].set(move); moves_number++; } break; case player_c::PLAYER_O: if(!board_copy.status.is_win_o()) { moves[moves_number].set(move); moves_number++; } break; } } if(moves_number > 0) { move_c* move; switch(select) { case SELECT_RANDOM: move = new move_c(moves[util_c::random_int(0, moves_number-1)]); break; case SELECT_FIRST: move = new move_c(moves[0]); break; case SELECT_LAST: move = new move_c(moves[moves_number-1]); break; } return move; } return worst_move(board); }
bool pseudo_is_legal(int move, const board_t * board) { board_t new_board[1]; ASSERT(move_is_ok(move)); ASSERT(board_is_ok(board)); ASSERT(move_is_pseudo(move,board)); board_copy(new_board,board); move_do(new_board,move); return !is_in_check(new_board,colour_opp(new_board->turn)); }
/* find and return the best computer's next move acording to minimax algorithm. * in case of an error - return a move with .steps_len = -1 * (envelope function that calls minimax()) */ moves best_next_moves(settings set, int maximizer) { // minimax function moves best_moves = { 0 }; move * temp_best_move; moves possible_moves = make_all_moves(&set); int best_score = INT_MIN; int curr_alpha = INT_MIN; if (possible_moves.len == -1) { //error return possible_moves; } int is_best_difficulty = (set.minimax_depth == BEST_DIFFICULTY); int depth = (!is_best_difficulty) ? set.minimax_depth : get_best_depth(&set, maximizer); move_node * curr = possible_moves.first; while (curr != NULL) { //get the score of each next possible moves, according to minimax algorithm settings next_set; memcpy(&next_set, &set, sizeof(settings)); next_set.next = other_player(set.next); board_copy(((move*)curr->data)->board, next_set.board); int curr_score = minimax(next_set, curr_alpha, INT_MAX, FALSE, depth - 1, is_best_difficulty); if (curr_score == SCORE_ERROR) { free_list(&possible_moves, &free); free_list(&best_moves, &free); return error_moves; } if (curr_score > curr_alpha) curr_alpha = curr_score; temp_best_move = curr->data; if (curr_score > best_score) { // if new score is higher - free previous best moves free_list(&best_moves, &free); best_score = curr_score; } if (!(curr_score < best_score)) { if (!add_node(&best_moves, temp_best_move, sizeof(move))) { free_list(&best_moves, &free); free_list(&possible_moves, &free); return error_moves; } } curr = curr->next; } free_list(&possible_moves, &free); if (DEBUG) printf("CHOSEN SCORE: %d\n", best_score); return best_moves; }
bool game_init(game_t * game, const char fen[]) { ASSERT(game!=NULL); ASSERT(fen!=NULL); if (!board_from_fen(game->start_board,fen)) return false; game->size = 0; board_copy(game->board,game->start_board); game->pos = 0; game_update(game); return true; }
move_c* solver_c::best_move(const board_c& board) const { if(!board.status.is_playable()) throw error_not_playable(); rate_t rates[board.size][board.size]; for(move_c& move : board.all_moves_on_empty) { board_c board_copy(board); board_copy.play(move); rates[move.x][move.y] = rate(board_copy); } move_c moves[board.size*board.size]; int moves_number = 0; for(move_c& move : board.all_moves_on_empty) if(moves_number == 0) { moves[0].set(move); moves_number = 1; } else if(compare_rate(rates[move.x][move.y], rates[moves[0].x][moves[0].y])) { moves[0].set(move); moves_number = 1; } else if(rates[move.x][move.y] == rates[moves[0].x][moves[0].y]) { moves[moves_number].set(move); moves_number++; } move_c* move; switch(select) { case SELECT_RANDOM: move = new move_c(moves[util_c::random_int(0, moves_number-1)]); break; case SELECT_FIRST: move = new move_c(moves[0]); break; case SELECT_LAST: move = new move_c(moves[moves_number-1]); break; } return move; }
static coord_t * proof_genmove(struct engine *e, struct board *b, struct time_info *ti, enum stone color, bool pass_all_alive) { coord_t *coord; fprintf(stderr, "HELLO WORLD!"); struct board b2; board_copy(&b2, b); for (int i=0; i<=19; i++){ for (int j=0; j<=19; j++){ coord = coord_init(i,j,board_size(&b2)); if (board_is_valid_play(&b2, color, *coord)) return coord; } } *coord = -1; return coord; }
move get_castling_move(settings * set, cord curr, int color) { cord c0 = { 0, curr.y }; cord c1 = { 1, curr.y }; cord c2 = { 2, curr.y }; cord c3 = { 3, curr.y }; cord c5 = { 5, curr.y }; cord c6 = { 6, curr.y }; cord c7 = { 7, curr.y }; move castle = error_move; cord king_dest; cord king_loc = { 4, (color == WHITE) ? 0 : 7 }; castle.start = curr; castle.is_castle = TRUE; castle.promotion = FALSE; board_copy(set->board, castle.board); int king_moved = (color == WHITE) ? set->white_king_moved : set->black_king_moved; int rook1_moved = (color == WHITE) ? set->white_rook_1_moved : set->black_rook_1_moved; int rook2_moved = (color == WHITE) ? set->white_rook_2_moved : set->black_rook_2_moved; int relevant_rook_moved = (!rook1_moved && (curr.x == 0) || !rook2_moved && (curr.x == 7)); if (!king_moved && !is_king_checked(color, set->board) && !relevant_rook_moved) { if ((curr.x == 0) && //relevant rook is rook1 (big castle) ((board_piece(set->board, c1) == EMPTY) && (board_piece(set->board, c2) == EMPTY) && (board_piece(set->board, c3) == EMPTY) && !is_cord_checked(c3, color, set->board))) { castle.end = c3; king_dest = c6; } else if ((curr.x == 7) && (board_piece(set->board, c5) == EMPTY) && (board_piece(set->board, c6) == EMPTY) && !is_cord_checked(c6, color, set->board)) { castle.end = c5; king_dest = c6; } move_from_to(castle.board, castle.start, castle.end); move_from_to(castle.board, king_loc, king_dest); } return castle; }
void game_goto(game_t * game, int pos) { int i; ASSERT(game!=NULL); ASSERT(pos>=0&&pos<=game->size); if (pos < game->pos) { // going backward => replay the whole game board_copy(game->board,game->start_board); game->pos = 0; } for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]); ASSERT(i==pos); game->pos = pos; game_update(game); }
bool line_to_san(const move_t line[], const board_t * board, char string[], int size) { board_t new_board[1]; int pos; int move; char move_string[256]; ASSERT(line_is_ok(line)); ASSERT(board_is_ok(board)); ASSERT(string!=NULL); ASSERT(size>=StringSize); // init string[0]='\0'; if (size < StringSize) return false; // return false; board_copy(new_board,board); pos = 0; // loop while ((move = *line++) != MoveNone) { if (pos != 0) { if (pos >= size) return false; string[pos++] = ' '; } if (!move_is_legal(move,new_board) || !move_to_san(move,new_board,&string[pos],size-pos)) { if (Strict || UseDebug) { move_to_can(move,new_board,move_string,sizeof(move_string)); my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string); board_disp(new_board); if (Strict) my_fatal("line_to_san(): illegal move\n"); } break; } pos += (int)strlen(&string[pos]); move_do(new_board,move); } if (pos >= size) return false; string[pos] = '\0'; return true; }
static void perft(const board_t * board, int depth) { int me; list_t list[1]; int i, move; board_t new_board[1]; ASSERT(board_is_ok(board)); ASSERT(depth_is_ok(depth)); ASSERT(!is_in_check(board,colour_opp(board->turn))); // init NodeNb++; // leaf if (depth == 0) { LeafNb++; return; } // more init me = board->turn; // move loop gen_moves(list,board); for (i = 0; i < list_size(list); i++) { move = list_move(list,i); board_copy(new_board,board); move_do(new_board,move); if (!is_in_check(new_board,me)) perft(new_board,depth-1); } }
AIMoves *ai_threats(const Board *original) { AIMoves *moves; AIWEIGHT u_sum = 0; int i; b = board_new(); board_copy(original, b); /* Clear threat tallys */ for (i = 0; i < connect_k; i++) { threat_counts[i][0] = 0; threat_counts[i][1] = 0; } /* Horizontal lines */ for (i = 0; i < board_size; i++) u_sum += threat_line(0, i, 1, 0); /* Vertical lines */ for (i = 0; i < board_size; i++) u_sum += threat_line(i, 0, 0, 1); /* SE diagonals */ for (i = 0; i < board_size - connect_k + 1; i++) u_sum += threat_line(i, 0, 1, 1); for (i = 1; i < board_size - connect_k + 1; i++) u_sum += threat_line(0, i, 1, 1); /* SW diagonals */ for (i = connect_k - 1; i < board_size; i++) u_sum += threat_line(i, 0, -1, 1); for (i = 1; i < board_size - connect_k + 1; i++) u_sum += threat_line(board_size - 1, i, -1, 1); moves = ai_marks(b, PIECE_THREAT(1)); moves->utility = u_sum; board_free(b); return moves; }
bool game_is_ok(const game_t * game) { board_t board[1]; int pos, move; if (game == NULL) return false; if (game->size < 0 || game->size > GameSize) return false; if (game->pos < 0 || game->pos > game->size) return false; // optional heavy DEBUG mode if (!UseSlowDebug) return true; if (!board_is_ok(game->start_board)) return false; board_copy(board,game->start_board); for (pos = 0; pos <= game->size; pos++) { if (pos == game->pos) { if (!board_equal(game->board,board)) return false; } if (pos >= game->size) break; if (game->key[pos] != board->key) return false; move = game->move[pos]; if (!move_is_legal(move,board)) ; move_do(board,move); } if (game->status != game_comp_status(game)) return false; return true; }
bool line_to_can(const move_t line[], const board_t * board, char string[], int size) { board_t new_board[1]; int pos; int move; ASSERT(line_is_ok(line)); ASSERT(board_is_ok(board)); ASSERT(string!=NULL); ASSERT(size>=StringSize); // init if (size < StringSize) return false; board_copy(new_board,board); pos = 0; // loop while ((move = *line++) != MoveNone) { if (pos != 0) { if (pos >= size) return false; string[pos++] = ' '; } if (!move_to_can(move,new_board,&string[pos],size-pos)) return false; pos += (int)strlen(&string[pos]); move_do(new_board,move); } if (pos >= size) return false; string[pos] = '\0'; return true; }
void game_disp(const game_t * game) { board_t board[1]; int i, move; ASSERT(game_is_ok(game)); board_copy(board,game->start_board); board_disp(board); for (i = 0; i < game->pos; i++) { move = game->move[i]; move_disp(move,board); move_do(board,move); } my_log("POLYGLOT\n"); board_disp(board); }
bool line_from_can (move_t line[], const board_t * board, const char string[], int size) { int pos; char new_string[StringSize], *p; int move; board_t new_board[1]; ASSERT(line!=NULL); ASSERT(board_is_ok(board)); ASSERT(string!=NULL); ASSERT(size>=LineSize); // init pos = 0; board_copy(new_board,board); // loop strcpy(new_string,string); // HACK for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { move = move_from_can(p,new_board); ASSERT(move!=MoveNone); ASSERT(move_is_legal(move,new_board)); if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves if (pos >= size) return false; line[pos++] = move; move_do(new_board,move); } if (pos >= size) return false; line[pos] = MoveNone; return true; }
/* * compute computer's next move and play. * return move in case of success, in case of lose/tie - return LOSE_CODE / TIE_CODE. * in case of an error - exit */ move computer_turn(settings * game_settings) { moves best_moves = best_next_moves(*game_settings, game_settings->next); //find next move move_node * random_best_move; move best_move; if (best_moves.len == -1) { // there was an error return error_move; } if (best_moves.len == 0) { // no possible moves - player wins best_move.promotion = NO_MOVE_CODE; return best_move; } else { // play best_move int r = rand() % best_moves.len; random_best_move = best_moves.first; for (int i = 0; i < r; i++) { random_best_move = random_best_move->next; }; best_move = *(move*)random_best_move->data; board_copy(best_move.board, game_settings->board); free_list(&best_moves, &free); game_settings->is_next_checked = (is_king_checked(other_player(game_settings->next), game_settings->board)); return best_move; } }
static void search_update() { int move; int move_nb; board_t board[1]; ASSERT(!Uci->searching); // launch a new search if needed if (State->state == THINK || State->state == PONDER || State->state == ANALYSE) { // opening book if (State->state == THINK && option_get_bool("Book")) { game_get_board(Game,Uci->board); move = book_move(Uci->board,option_get_bool("BookRandom")); if (move != MoveNone && move_is_legal(move,Uci->board)) { my_log("POLYGLOT *BOOK MOVE*\n"); search_clear(); // clears Uci->ponder_move Uci->best_move = move; board_copy(board,Uci->board); move_do(board,move); Uci->ponder_move = book_move(board,false); // expected move = best book move Uci->best_pv[0] = Uci->best_move; Uci->best_pv[1] = Uci->ponder_move; // can be MoveNone Uci->best_pv[2] = MoveNone; comp_move(Uci->best_move); return; } } // engine search my_log("POLYGLOT START SEARCH\n"); // options uci_send_option(Uci,"UCI_Chess960","%s",option_get_bool("Chess960")?"true":"false"); if (option_get_int("UCIVersion") >= 2) { uci_send_option(Uci,"UCI_Opponent","none none %s %s",(XB->computer)?"computer":"human",XB->name); uci_send_option(Uci,"UCI_AnalyseMode","%s",(XB->analyse)?"true":"false"); } uci_send_option(Uci,"Ponder","%s",ponder()?"true":"false"); // position move = (State->state == PONDER) ? State->exp_move : MoveNone; send_board(move); // updates Uci->board global variable // search if (State->state == THINK || State->state == PONDER) { engine_send_queue(Engine,"go"); if (XB->time_limit) { // fixed time per move engine_send_queue(Engine," movetime %.0f",XB->time_max*1000.0); } else { // time controls if (colour_is_white(Uci->board->turn)) { engine_send_queue(Engine," wtime %.0f btime %.0f",XB->my_time*1000.0,XB->opp_time*1000.0); } else { engine_send_queue(Engine," wtime %.0f btime %.0f",XB->opp_time*1000.0,XB->my_time*1000.0); } if (XB->inc != 0.0) engine_send_queue(Engine," winc %.0f binc %.0f",XB->inc*1000.0,XB->inc*1000.0); if (XB->mps != 0) { move_nb = XB->mps - (Uci->board->move_nb % XB->mps); ASSERT(move_nb>=1&&move_nb<=XB->mps); engine_send_queue(Engine," movestogo %d",move_nb); } } if (XB->depth_limit) engine_send_queue(Engine," depth %d",XB->depth_max); if (State->state == PONDER) engine_send_queue(Engine," ponder"); engine_send(Engine,""); // newline } else if (State->state == ANALYSE) { engine_send(Engine,"go infinite"); } else { ASSERT(false); } // init search info ASSERT(!Uci->searching); search_clear(); Uci->searching = true; Uci->pending_nb++; } }
void search() { int move; int depth; int i; bool search_ready; for (i = 0; i < MultiPVMax; i++){ save_multipv[SearchCurrent->multipv].mate = 0; save_multipv[SearchCurrent->multipv].depth = 0; save_multipv[SearchCurrent->multipv].max_depth = 0; save_multipv[SearchCurrent->multipv].value = 0; save_multipv[SearchCurrent->multipv].time = 0; save_multipv[SearchCurrent->multipv].node_nb = 0; strcpy(save_multipv[SearchCurrent->multipv].pv_string,""); } SearchInput->multipv = option_get_int("MultiPV")-1; SearchCurrent->multipv = 0; ASSERT(board_is_ok(SearchInput->board)); // opening book if (option_get_bool("OwnBook") && !SearchInput->infinite) { move = book_move(SearchInput->board); if (move != MoveNone) { // play book move SearchBest[SearchCurrent->multipv].move = move; SearchBest[SearchCurrent->multipv].value = 1; SearchBest[SearchCurrent->multipv].flags = SearchExact; SearchBest[SearchCurrent->multipv].depth = 1; SearchBest[SearchCurrent->multipv].pv[0] = move; SearchBest[SearchCurrent->multipv].pv[1] = MoveNone; search_update_best(); return; } } // SearchInput gen_legal_moves(SearchInput->list,SearchInput->board); if (LIST_SIZE(SearchInput->list) < SearchInput->multipv+1){ SearchInput->multipv = LIST_SIZE(SearchInput->list)-1; } if (LIST_SIZE(SearchInput->list) <= 1) { SearchInput->depth_is_limited = true; SearchInput->depth_limit = 4; // was 1 } // SearchInfo if (setjmp(SearchInfo->buf) != 0) { ASSERT(SearchInfo->can_stop); ASSERT(SearchBest->move!=MoveNone); search_update_current(); return; } // SearchRoot list_copy(SearchRoot->list,SearchInput->list); // SearchCurrent board_copy(SearchCurrent->board,SearchInput->board); my_timer_reset(SearchCurrent->timer); my_timer_start(SearchCurrent->timer); // init trans_inc_date(Trans); sort_init(); search_full_init(SearchRoot->list,SearchCurrent->board); // analyze game for evaluation if (SearchCurrent->board->piece_size[White] < 3 && SearchCurrent->board->piece_size[Black] < 3){ trans_endgame = true; } else{ trans_endgame = false; } // iterative deepening search_ready = false; for (depth = 1; depth < DepthMax; depth++) { for (SearchCurrent->multipv = 0; SearchCurrent->multipv <= SearchInput->multipv; SearchCurrent->multipv++){ if (DispDepthStart && SearchCurrent->multipv == 0) send("info depth %d",depth); SearchCurrent->max_extensions = depth * 10; SearchRoot->bad_1 = false; SearchRoot->change = false; board_copy(SearchCurrent->board,SearchInput->board); if (UseShortSearch && depth <= ShortSearchDepth) { search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchShort); } else { search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchNormal); } search_update_current(); if (DispDepthEnd && SearchCurrent->multipv == SearchInput->multipv) { send("info depth %d seldepth %d time %.0f nodes " S64_FORMAT " nps %.0f",depth,SearchCurrent->max_depth,SearchCurrent->time*1000.0,SearchCurrent->node_nb,SearchCurrent->speed); } // update search info if (depth >= 1) SearchInfo->can_stop = true; if (depth == 1 && LIST_SIZE(SearchRoot->list) >= 2 && LIST_VALUE(SearchRoot->list,0) >= LIST_VALUE(SearchRoot->list,1) + EasyThreshold) { SearchRoot->easy = true; } if (depth > 1) { SearchRoot->bad_2 = SearchRoot->bad_1; SearchRoot->bad_1 = false; ASSERT(SearchRoot->bad_2==(SearchBest->value<=SearchRoot->last_value-BadThreshold)); } SearchRoot->last_value = SearchBest[SearchCurrent->multipv].value; // stop search? if (SearchInput->depth_is_limited && SearchCurrent->multipv >= SearchInput->multipv && depth >= SearchInput->depth_limit) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time * 2 >= SearchInput->time_limit_1 && !SearchRoot->bad_2) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 * EasyRatio && SearchRoot->easy) { ASSERT(!SearchRoot->bad_2); ASSERT(!SearchRoot->change); SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 * EarlyRatio && !SearchRoot->bad_2 && !SearchRoot->change) { SearchRoot->flag = true; } if (SearchInfo->can_stop && (SearchInfo->stop || (SearchRoot->flag && !SearchInput->infinite))) { search_ready = true; break; } } if (search_ready) break; } }
void Notation::image(const Board & b, const Move & m, OutputFormat format, ostream &image) { if (format == UCI) { return UCIMoveImage(m,image); } else if (format == WB_OUT) { if (TypeOfMove(m) == KCastle) { image << "O-O"; } else if (TypeOfMove(m) == QCastle) { image << "O-O-O"; } else { image << FileImage(StartSquare(m)); image << RankImage(StartSquare(m)); image << FileImage(DestSquare(m)); image << RankImage(DestSquare(m)); if (TypeOfMove(m) == Promotion) { // N.b. ICS requires lower case. image << (char)tolower((int)PieceImage(PromoteTo(m))); } } return; } // format is SAN if (IsNull(m)) { image << "(null)"; return; } PieceType p = PieceMoved(m); ASSERT(p != Empty); if (TypeOfMove(m) == KCastle) { image << "O-O"; } else if (TypeOfMove(m) == QCastle) { image << "O-O-O"; } else { if (p == Pawn) { if (Capture(m) == Empty) { image << FileImage(DestSquare(m)); image << RankImage(DestSquare(m)); } else { image << FileImage(StartSquare(m)); image << 'x'; image << FileImage(DestSquare(m)); image << RankImage(DestSquare(m)); } if (TypeOfMove(m) == Promotion) { image << '='; image << PieceImage(PromoteTo(m)); } } else { image << PieceImage(p); Bitboard attacks = b.calcAttacks(DestSquare(m), b.sideToMove()); unsigned n = attacks.bitCount(); int dups = 0; int filedups = 0; int rankdups = 0; int files[9]; int ranks[9]; if (n > 1) { Square sq; while (attacks.iterate(sq)) { if (TypeOfPiece(b[sq]) == p) { files[dups] = File(sq); if (files[dups] == File(StartSquare(m))) filedups++; ranks[dups] = Rank(sq,White); if (ranks[dups] == Rank(StartSquare(m),White)) rankdups++; ++dups; } } } if (dups > 1) { // need to disambiguate move. if (filedups == 1) { image << FileImage(StartSquare(m)); } else if (rankdups == 1) { image << RankImage(StartSquare(m)); } else { // need both rank and file to disambiguate image << FileImage(StartSquare(m)); image << RankImage(StartSquare(m)); } } if (Capture(m) != Empty) { image << 'x'; } image << FileImage(DestSquare(m)); image << RankImage(DestSquare(m)); } } Board board_copy(b); board_copy.doMove(m); if (board_copy.checkStatus() == InCheck) { Move moves[Constants::MaxMoves]; MoveGenerator mg(board_copy); if (mg.generateEvasions(moves)) image << '+'; else image << '#'; // mate } }
Move Notation::value(const Board & board, ColorType side, InputFormat format, const string &image) { int rank = 0; int file = 0; PieceType piece = Empty; PieceType promotion = Empty; Square dest = InvalidSquare, start = InvalidSquare; int capture = 0; stringstream s(image); string::const_iterator it = image.begin(); int i = 0; while (it != image.end() && isspace(*it)) { it++; i++; } if (it == image.end() || !isalpha(*it)) return NullMove; string img(image,i); // string w/o leading spaces ASSERT(img.length()); it = img.begin(); if (*it == 'O' || *it == '0') { // castling, we presume return parseCastling(board, side, img); } else if (format == WB_IN) { if (img.length() < 4) return NullMove; Square start = SquareValue(img.substr(0,2)); if (!OnBoard(start)) return NullMove; Square dest = SquareValue(img.substr(2,2)); if (!OnBoard(dest)) return NullMove; PieceType promotion = Empty; if (img.length() > 4) { promotion = PieceCharValue(toupper(img[4])); } return CreateMove(board,start,dest,promotion); } int have_start = 0; if (isupper(*it)) { piece = PieceCharValue(*it); it++; } else { piece = Pawn; if ((it+1) != img.end()) { char next = *it; file = next-'a'+1; if (file < 1 || file > 8) return NullMove; char next2 = *(it+1); if (next2 == 'x' || is_file(next2)) { // allow "dc4" as in Informant, instead of dxc4 it++; capture = 1; } else if (isdigit(next2) && img.length()>2) { char next3 = *(it+2); if ((next3 == 'x' || next3 == '-') && img.length()>=5) { // long algebraic notation have_start++; start = SquareValue(next,next2); if (start == InvalidSquare) return NullMove; it+=3; // point to dest piece = TypeOfPiece(board[start]); } } } } if (piece == Empty) { return NullMove; } if (piece != Pawn && !have_start && it != img.end()) { char next = *it; char next2 = '\0'; if (it + 1 != img.end()) next2 = *(it+1); if (is_file(next) && isdigit(next2) && img.length()>=5) { // long algebraic notation, or a SAN move like Qd1d3 start = SquareValue(next,next2); if (IsInvalid(start)) return NullMove; it+=2; have_start++; } // also look for disambiguating rank, e.g. '2' in "N2e4". else if (isdigit(next)) { rank = next - '0'; if (rank < 1 || rank > 8) return NullMove; it++; } else if (is_file(next) && isalpha(next2)) { // disamiguating rank, e.g. "Rfd1" file = next - 'a' + 1; if (file < 1 || file > 8) return NullMove; it++; } } if (it != img.end() && *it == 'x') { capture = 1; it++; } if (it != img.end() && (it+1) != img.end()) { // remainder of move should be a square identifier, e.g. "g7" dest = SquareValue(*it,*(it+1)); it += 2; } if (IsInvalid(dest)) { return NullMove; } if (it != img.end() && *it == '=') { it++; if (it == img.end()) { return NullMove; } else { promotion = PieceCharValue(*it); if (piece != Pawn || promotion == Empty) return NullMove; it++; } } else if (piece == Pawn && it != img.end() && isupper(*it)) { // Quite a few "PGN" files have a8Q instead of a8=Q. promotion = PieceCharValue(*it); if (promotion == Empty || Rank(dest,side) != 8) return NullMove; } else if (piece == Pawn && Rank(dest,side) == 8) { // promotion but no piece specified, treat as error return NullMove; } // Informant does not use "x" for captures. Assume that if the destination // is occupied, this is a capture move. if (board[dest] != EmptyPiece) { capture = 1; } // Do a sanity check on capture moves: if (capture && !IsEmptyPiece(board[dest]) && PieceColor(board[dest]) == board.sideToMove()) { return NullMove; } // Ok, now we need to figure out where the start square is. For pawn // moves this is implicit. int dups = 0; if (!have_start) { if (capture && piece == Pawn && IsEmptyPiece(board[dest]) && Rank(dest,board.sideToMove()) != 8) { // en passant capture, special case int start_rank = (board.sideToMove() == White) ? Rank(dest,White) - 1 : Rank(dest,White) + 1; start = MakeSquare(file, start_rank, White); dups = 1; } else if (piece == Pawn && board[dest] == EmptyPiece) { start = MakeSquare(file,Rank(dest,board.sideToMove())-1,board.sideToMove()); if (board[start] == EmptyPiece && Rank(dest,board.sideToMove())==4) { start = MakeSquare(file,Rank(dest,board.sideToMove())-2,board.sideToMove()); } if (board[start] == EmptyPiece) return NullMove; dups = 1; } else { Bitboard attacks = board.calcAttacks(dest,side); Square maybe; while (attacks.iterate(maybe)) { if (TypeOfPiece(board[maybe]) == piece && PieceColor(board[maybe]) == board.sideToMove()) { if (file && File(maybe) != file) continue; if (rank && Rank(maybe,White) != rank) continue; if (PieceColor(board[maybe]) == board.sideToMove()) { // Possible move to this square. Make sure it is legal. Board board_copy(board); Move emove = CreateMove(board,maybe,dest, promotion); board_copy.doMove(emove); if (!board_copy.anyAttacks( board_copy.kingSquare(board_copy.oppositeSide()), board_copy.sideToMove())) { ++dups; start = maybe; } } } } } } if (dups == 1 || have_start) { if (start == InvalidSquare || board[start] == EmptyPiece) return NullMove; else return CreateMove(board, start, dest, promotion); } else // ambiguous move return NullMove; }
static int parse_bestmove(uci_t * uci, const char string[]) { parse_t parse[1]; char command[StringSize]; char option[StringSize]; char argument[StringSize]; board_t board[1]; ASSERT(uci_is_ok(uci)); ASSERT(string!=NULL); // init strcpy(command,"bestmove"); parse_open(parse,string); parse_add_keyword(parse,"ponder"); // bestmove if (!parse_get_string(parse,argument,StringSize)) { my_fatal("parse_bestmove(): missing argument\n"); } uci->best_move = move_from_can(argument,uci->board); if (uci->best_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument); ASSERT(uci->best_move!=MoveNone); ASSERT(move_is_legal(uci->best_move,uci->board)); // loop while (parse_get_word(parse,option,StringSize)) { parse_get_string(parse,argument,StringSize); if (UseDebug) my_log("POLYGLOT COMMAND \"%s\" OPTION \"%s\" ARGUMENT \"%s\"\n",command,option,argument); if (false) { } else if (my_string_equal(option,"ponder")) { ASSERT(!my_string_empty(argument)); board_copy(board,uci->board); move_do(board,uci->best_move); uci->ponder_move = move_from_can(argument,board); // if (uci->ponder_move == MoveNone) my_fatal("parse_bestmove(): not a move \"%s\"\n",argument); ASSERT(uci->ponder_move!=MoveNone); ASSERT(move_is_legal(uci->ponder_move,board)); } else { my_log("POLYGLOT unknown option \"%s\" for command \"%s\"\n",option,command); } } parse_close(parse); return EVENT_MOVE; }