static int ambiguity(int move, const board_t * board) { int from, to, piece; list_t list[1]; int i, n, m; // init from = move_from(move); to = move_to(move); piece = move_piece(move,board); gen_legal_moves(list,board); // no ambiguity? n = 0; for (i = 0; i < list_size(list); i++) { m = list_move(list,i); if (move_piece(m,board) == piece && move_to(m) == to) { n++; } } if (n == 1) return AMBIGUITY_NONE; // file ambiguity? n = 0; for (i = 0; i < list_size(list); i++) { m = list_move(list,i); if (move_piece(m,board) == piece && move_to(m) == to) { if (square_file(move_from(m)) == square_file(from)) n++; } } if (n == 1) return AMBIGUITY_FILE; // rank ambiguity? n = 0; for (i = 0; i < list_size(list); i++) { m = list_move(list,i); if (move_piece(m,board) == piece && move_to(m) == to) { if (square_rank(move_from(m)) == square_rank(from)) n++; } } if (n == 1) return AMBIGUITY_RANK; // square ambiguity return AMBIGUITY_SQUARE; }
int board_mobility(const board_t * board) { list_t list[1]; ASSERT(board_is_ok(board)); gen_legal_moves(list,board); return list_size(list); }
static bool move_is_legal_debug(int move, const board_t * board) { list_t list[1]; ASSERT(move_is_ok(move)); ASSERT(board_is_ok(board)); gen_legal_moves(list,board); return list_contain(list,move); }
/* TRUE if move from START_POS to END_POS by PLAYER is legal. */ int is_legal_move (int player, int start_pos, int end_pos) { int legal_moves[BOARD_SIZE]; init_moves_board (legal_moves); gen_legal_moves (player, start_pos, legal_moves); if (legal_moves[end_pos] == FALSE) { //printf ("Error: Illegal move %d - %d\n", start_pos, end_pos); } return legal_moves[end_pos]; }
int parse_move(Board *board, const char *notation, Move *move) { char temp[16]; Move moves[MAX_MOVES]; int count = gen_legal_moves(board, moves); for (int i = 0; i < count; i++) { notate_move(board, &moves[i], temp); if (strcmp(notation, temp) == 0) { memcpy(move, &moves[i], sizeof(Move)); return 1; } } return 0; }
int book_move(board_t * board) { int best_move; int best_score; int pos; entry_t entry[1]; int move; int score; list_t list[1]; int i; ASSERT(board!=NULL); if (BookFile != NULL && BookSize != 0) { // draw a move according to a fixed probability distribution best_move = MoveNone; best_score = 0; for (pos = find_pos(board->key); pos < BookSize; pos++) { read_entry(entry,pos); if (entry->key != board->key) break; move = entry->move; score = entry->count; // pick this move? ASSERT(score>0); best_score += score; if (my_random(best_score) < score) best_move = move; } if (best_move != MoveNone) { // convert PolyGlot move into Fruit move; TODO: handle promotes gen_legal_moves(list,board); for (i = 0; i < list->size; i++) { move = list->move[i]; if ((move & 07777) == best_move) return move; } } } return MoveNone; }
/* Search and evaluate AI's moves. MV->START_POS and MV->END_POS store AI's best * move. */ void best_move (struct move *mv) { int legal_moves[BOARD_SIZE]; int curr_util = NEG_INF, i; /* Generate legal moves for each black piece. */ for (i = 0; i < BOARD_SIZE; i++) { if (board[i] < chp_null) { init_moves_board (legal_moves); gen_legal_moves (BPLAYER, i, legal_moves); /* For each legal move, evaluate subsequent moves. If this move * leads to current best score, save it. */ int j; for (j = 0; j < BOARD_SIZE; j++) { if (legal_moves[j] == TRUE) { /* Make move and evaluate subsequent moves. */ int attacked_piece = move_piece (i, j); /* If the move wins the game, automatically make it. */ if (game_over () == TRUE) { mv->start_pos = i; mv->end_pos = j; unmove_piece (i, j, attacked_piece); return; } /* Evaluate subsequent moves and choose the best one. */ int move_util = -1 * abp_search (WPLAYER, SEARCH_DEP - 1, NEG_INF, POS_INF); unmove_piece (i, j, attacked_piece); /* If move is best yet, save it. */ if (move_util > curr_util) { mv->start_pos = i; mv->end_pos = j; curr_util = move_util; } } } } } }
int move_from_san_debug(const char string[], const board_t * board) { list_t list[1]; int i, move; char move_string[256]; ASSERT(string!=NULL); ASSERT(board_is_ok(board)); gen_legal_moves(list,board); for (i = 0; i < list_size(list); i++) { move = list_move(list,i); if (!move_to_san(move,board,move_string,256)) ASSERT(false); if (my_string_equal(move_string,string)) return move; } return MoveNone; }
/* Return TRUE if PLAYER has a legal move. This is strictly for detecting * checkmate, not for generating all legal moves a player has. */ int player_has_moves (int player) { int i, mod = (player == BPLAYER) ? -1 : 1; /* If a board square contains a player's piece, generate all legal moves for * that piece, then check if there are any legal moves. If there are, simply * return TRUE. Else continue for all pieces. */ for (i = 0; i < BOARD_SIZE; i++) { if (board[i] * mod > chp_null) { int moves_array[BOARD_SIZE]; init_moves_board (moves_array); gen_legal_moves (player, i, moves_array); int j; for (j = 0; j < BOARD_SIZE; j++) { if (moves_array[j] == TRUE) { return TRUE; } } } } return FALSE; }
/* Return position score for knight at START_POS owned by PLAYER. */ int knight_pos_score (int player, int start_pos) { int score = 0, legal_moves[BOARD_SIZE]; int mod = (player == BPLAYER) ? -1 : 1; init_moves_board (legal_moves); gen_legal_moves (player, start_pos, legal_moves); int i; for (i = 0; i < BOARD_SIZE; i++) { /* Each legal move increases score. */ if (legal_moves[i] == TRUE) { score++; /* Each enemy piece attacked increases score. */ if (board[i] * mod < chp_null) { printf (":: EVAL: %c attacking piece\n", (player == WPLAYER) ? 'W' : 'B'); score -= board[i] * mod; } } } return score; }
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; } }
bool TEngine::SearchPos(board_t * Board, TFindPos * fp, mv_t pv[], bool full) { //------------------------ if (Eval(Board,fp)) { pv[0] = 0; return true; } //----------------------- if (LastMove) { undo_t undo; move_do(Board,LastMove,&undo); bool eval = Eval(Board,fp); if (Eval(Board,fp)) { move_undo(Board,LastMove, &undo); pv[0] = LastMove; pv[1] = 0; return true; } list_t list; gen_legal_moves(&list,Board); for (int i=0; i<LIST_SIZE(&list); i++) { undo_t undo2; mv_t move2 = LIST_MOVE(&list,i); move_do(Board,move2,&undo2); bool eval = Eval(Board,fp); move_undo(Board,move2, &undo2); if (eval) { move_undo(Board,LastMove, &undo); pv[0] = LastMove; pv[1] = move2; pv[2] = 0; return true;; } } move_undo(Board,LastMove,&undo); } //---------------------------------------------------- list_t list; gen_legal_moves(&list,Board); //---------------------------------------------------- for (int i=0; i<LIST_SIZE(&list); i++) { undo_t undo; mv_t move = LIST_MOVE(&list,i); move_do(Board,move,&undo); bool eval = Eval(Board,fp); move_undo(Board,move,&undo); if (eval) { pv[0] = move; pv[1] = 0; return true; } } //------------------------------------------------------ if (full) { for (int i=0; i<LIST_SIZE(&list); i++) { undo_t undo; mv_t move = LIST_MOVE(&list,i); move_do(Board,move,&undo); list_t list2; gen_legal_moves(&list2,Board); for (int j=0; j<LIST_SIZE(&list2); j++) { undo_t undo2; mv_t move2 = LIST_MOVE(&list2,j); move_do(Board,move2,&undo2); /* char s_move[6], s_move2[6]; move_to_string(move,s_move,6); move_to_string(move2,s_move2,6); */ bool eval = Eval(Board,fp); move_undo(Board,move2,&undo2); if (eval) { pv[0] = move; pv[1] = move2; pv[2] = 0; move_undo(Board,move,&undo); return true; } } move_undo(Board,move,&undo); } } //------------------------------------------------------- return false; }
void notate_move(Board *board, Move *move, char *result) { Move moves[MAX_MOVES]; int count = gen_legal_moves(board, moves); int piece = board->squares[move->src]; int capture = board->squares[move->dst]; char rank1 = '1' + move->src / 8; char file1 = 'a' + move->src % 8; char rank2 = '1' + move->dst / 8; char file2 = 'a' + move->dst % 8; int show_rank1 = 0; int show_file1 = 0; if (PIECE(piece) == PAWN) { if (file1 != file2) { capture = 1; } if (capture) { show_file1 = 1; } } // ambiguity int ambiguous = 0; int unique_rank = 1; int unique_file = 1; for (int i = 0; i < count; i++) { Move *other = moves + i; if (move->dst != other->dst) { continue; // different target } if (move->src == other->src) { continue; // same move } if (piece != board->squares[other->src]) { continue; // different piece } ambiguous = 1; if (move->src % 8 == other->src % 8) { unique_file = 0; } if (move->src / 8 == other->src / 8) { unique_rank = 0; } } if (ambiguous) { if (unique_rank && unique_file) { show_file1 = 1; } else if (unique_rank) { show_rank1 = 1; } else if (unique_file) { show_file1 = 1; } else { show_rank1 = 1; show_file1 = 1; } } // castle int castle = 0; if (PIECE(piece) == KING) { castle = 1; if (move->src == 4 && move->dst == 6) { strcpy(result, "O-O"); result += 3; } else if (move->src == 4 && move->dst == 2) { strcpy(result, "O-O-O"); result += 5; } else if (move->src == 60 && move->dst == 62) { strcpy(result, "O-O"); result += 3; } else if (move->src == 60 && move->dst == 58) { strcpy(result, "O-O-O"); result += 5; } else { castle = 0; } } if (!castle) { // piece switch (PIECE(piece)) { case KNIGHT: *result++ = 'N'; break; case BISHOP: *result++ = 'B'; break; case ROOK: *result++ = 'R'; break; case QUEEN: *result++ = 'Q'; break; case KING: *result++ = 'K'; break; } // source if (show_file1) { *result++ = file1; } if (show_rank1) { *result++ = rank1; } // capture if (capture) { *result++ = 'x'; } // target *result++ = file2; *result++ = rank2; // promotion if (move->promotion) { *result++ = '='; switch (move->promotion) { case KNIGHT: *result++ = 'N'; break; case BISHOP: *result++ = 'B'; break; case ROOK: *result++ = 'R'; break; case QUEEN: *result++ = 'Q'; break; } } } // check Undo undo; do_move(board, move, &undo); if (is_check(board)) { if (has_legal_moves(board)) { *result++ = '+'; } else { *result++ = '#'; } } undo_move(board, move, &undo); // null terminator *result++ = 0; }