int test_scout() { Board b, orig; Move *moves, *omoves; int status, i, j, n, m; status = WIN; printf("testing scout\n"); setup(&b); setup(&orig); printb(&b); moves = gen_moves(&b, &n); for(i=0; i<n && i<5; i++) { printf("=============================================\napplying move %d\n", i+1); apply_move(&b, moves[i]); omoves = gen_moves(&b, &m); for(j=0; j<m && j<5; j++) { printf("second move %d\n", j+1); apply_move(&b, omoves[j]); printb(&b); printf("eval = %d\n", eval(&b)); undo_move(&b, omoves[j]); } free(omoves); undo_move(&b, moves[i]); } free(moves); return status; }
static int extract_ponder_from_tt(RootMove *rm, Pos *pos) { int ttHit; assert(rm->pvSize == 1); if (!rm->pv[0]) return 0; do_move(pos, rm->pv[0], gives_check(pos, pos->st, rm->pv[0])); TTEntry *tte = tt_probe(pos_key(), &ttHit); if (ttHit) { Move m = tte_move(tte); // Local copy to be SMP safe ExtMove list[MAX_MOVES]; ExtMove *last = generate_legal(pos, list); for (ExtMove *p = list; p < last; p++) if (p->move == m) { rm->pv[rm->pvSize++] = m; break; } } undo_move(pos, rm->pv[0]); return rm->pvSize > 1; }
void backtrack(int a[], int k, Graph *graph){ int ncandidatos, i, c[graph->numero_vertices]; if ( is_solution(a, k, graph) ){ int solucao_encontrada = distancia_total(a, k, graph); if(solucao_atual == 0 || solucao_atual > solucao_encontrada){ solucao_atual = solucao_encontrada; printf("\nNova solucao Melhor: %d\n", solucao_atual); imprimir_rota(a, k, graph); } return; } else { k=k+1; if(k > (graph->numero_vertices +1)) { return; } construct_candidate(a, k, graph, c, &ncandidatos); for ( i=0; i < ncandidatos; i++){ a[k] = c[i]; backtrack(a, k, graph); undo_move(a, k, graph); } } }
/* **AI的核心,得到当前走法的权重 */ int weigh_move(int x, int y, int who, int max_depth, int add) { int bottom, top, i, move_weight = 0, depth_weight = 0, temp; bottom = flips_next; make_move(x, y, who); top = flips_next; for (i = bottom; i < top; ++i) move_weight += (add ? 1 : (-1)) * weight[flips_x[i]][flips_y[i]]; if (max_depth && empties()) { who = OPPOSITE(who); add = !add; bottom = moves_next; get_all(who); top = moves_next; for(i = bottom; i < top; ++i) { temp = weigh_move(moves_x[i], moves_y[i], who, max_depth - 1, add); if(temp < depth_weight) depth_weight = temp; } unget_all(); } undo_move(); return move_weight + depth_weight; }
void nearby_greedy(int *move, int x, int y) { int i, j; double score, bestscore = -1; int best_move[2]; for(i = -1; i <= 1; i++) { for(j = -1; j <= 1; j++) { if((x + i < 0) || (x + i >= BOARD_SIZE) || (y + i < 0) || (y + i >= BOARD_SIZE)) continue; if(!stone_check(x + i, y + j)) continue; move[0] = x + i; move[1] = y + j; score = do_move(move); if(score > bestscore) { bestscore = score; best_move[0] = move[0]; best_move[1] = move[1]; } undo_move(move); } } move[0] = best_move[0]; move[1] = best_move[1]; }
/* Tests `make_move` and `undo_move` by making and undoing every single move for a set of fen positions, then making sure the resulting board is the same as the original board. */ int test_make_undo_move() { static const char* fen_positions[] = { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "1B4n1/5k2/5P2/4p2N/P2QR3/p2pb2K/3Pb2R/8 w - - 0 1", "3b4/N2P1p2/1kP4p/p4n1K/2p5/1PPp2P1/1p6/8 w - - 0 1", "8/4p3/3R4/2P4R/P3Pp2/6kp/8/K7 w - - 0 1", "8/8/p3K3/k1N2B2/3P4/6Pp/5P1p/4R3 w - - 0 1", "K7/8/1P3r2/1P2b1p1/8/5p2/1Q2q2n/7k b - - 0 1", "1q1rr3/P1RN1P1p/Kp3p2/2P2p2/b4pP1/n4kb1/8/3Rn3 b - - 0 1", "8/2P5/Bp4Kn/q7/5P2/k7/8/B7 b - - 0 1", "8/8/1B6/8/P1b4K/8/8/1k6 b - - 0 1", "8/P2kp3/7B/1R3r2/1bK4p/Q4pp1/P6N/8 b - - 0 1" }; board_t board[ELEMENTS_IN(fen_positions)], board_original[ELEMENTS_IN(fen_positions)]; move_t move_list[256]; for (int i = 0; i < ELEMENTS_IN(fen_positions); i++) { set_board_from_fen_string(&board[i], fen_positions[i]); memcpy(&board_original[i], &board[i], sizeof(board_t)); } for (int i = 0; i < ELEMENTS_IN(fen_positions); i++) { move_t* end_of_list = generate_pseudolegal_moves(&board[i], move_list); for (int j = 0; move_list[j] != *end_of_list; j++) { make_move(&board[i], move_list[j]); undo_move(&board[i], move_list[j]); if (!compare_boards(&board[i], &board_original[i])) { fprintf(stderr, "test_make_undo_move -- Test \"%s\" failed: move %d.\n", fen_positions[i], j); return TEST_ERROR; } } } return TEST_SUCCESS; }
/* Makes a move_t from a supplied string (in long algebraic notation), or returns 0 if it's an invalid move. */ move_t move_from_text(const char* text, board_t* board) { int text_length = strlen(text); if (text_length != 4 && text_length != 5) return 0; move_t move = (((text[1]-'1')*8)+(tolower(text[0])-'a')) + ((((text[3]-'1')*8)+(tolower(text[2])-'a'))<<6); if (text_length == 5) if (board->to_move == WHITE) move |= piece_type_from_char(toupper(text[4]))<<23; else move |= piece_type_from_char(tolower(text[4]))<<23; move_t move_list[MAX_MOVES]; move_t* end_of_move_list = generate_pseudolegal_moves(board, move_list); for (int i = 0; &move_list[i] != end_of_move_list; i++) { if ((move_list[i]&0x7800FFF) == move) { if (IS_CASTLE(move_list[i]) && !is_legal_castle(board, move_list[i])) return 0; make_move(board, move_list[i]); if (!is_king_in_check(board, !board->to_move)) { undo_move(board, move_list[i]); return move_list[i]; } } } return 0; }
int quiescent(app_t *app, cnodeptr_t parent, int alpha, int beta) { int i, score = -MATE; node_t node; int delta = 200; init_node(&node); assert(app); app->search.nodes++; /* max depth */ if (app->game.board->ply > (SEARCH_MAXDEPTH - 1)) { return evaluate(app->game.board); } /* draws */ if (repetitions(app) || (app->game.board->half >= 100)) { return 0; } score = evaluate(app->game.board); if (score >= beta) return beta; /* delta pruning based on a material value of delta (this should be disabled in the endgame) */ /* The idea here is that, even if our score can improve alpha, it doesn't improve it by a significant amount, so don't bother searching these nodes */ if (score < (alpha - delta)) return alpha; if (score > alpha) alpha = score; /* generate moves (with separate captures) */ generate_moves(app->game.board, &node.ml, &node.cl); for (i = 0; i < node.cl.count; i++) { /* get the next move ordered */ next_move(i, &node.cl); if (!(do_move(app->game.board, &app->game.undo, node.cl.moves[i]))) continue; score = -quiescent(app, &node, -beta, -alpha); node.made++; undo_move(app->game.board, &app->game.undo); if (score > alpha) { if (score >= beta) { return beta; } /* update alpha */ alpha = score; } } return alpha; }
unsigned long long perft(Board *board, int depth) { if (is_illegal(board)) { return 0L; } if (depth == 0) { return 1L; } int index = board->hash & MASK; Entry *entry = &TABLE[index]; if (entry->key == board->hash && entry->depth == depth) { hits += entry->value; return entry->value; } unsigned long long result = 0; Undo undo; Move moves[MAX_MOVES]; int count = gen_moves(board, moves); for (int i = 0; i < count; i++) { do_move(board, &moves[i], &undo); result += perft(board, depth - 1); undo_move(board, &moves[i], &undo); } entry->key = board->hash; entry->value = result; entry->depth = depth; return result; }
void undo(void) { /* turn off Compose key LED */ setCompLED(0); switch (last_action) { case F_ADD: undo_add(); break; case F_DELETE: undo_delete(); break; case F_MOVE: undo_move(); break; case F_EDIT: undo_change(); break; case F_GLUE: undo_glue(); break; case F_BREAK: undo_break(); break; case F_LOAD: undo_load(); break; case F_SCALE: undo_scale(); break; case F_ADD_POINT: undo_addpoint(); break; case F_DELETE_POINT: undo_deletepoint(); break; case F_ADD_ARROW_HEAD: undo_add_arrowhead(); break; case F_DELETE_ARROW_HEAD: undo_delete_arrowhead(); break; case F_CONVERT: undo_convert(); break; case F_OPEN_CLOSE: undo_open_close(); break; case F_JOIN: case F_SPLIT: undo_join_split(); break; default: put_msg("Nothing to UNDO"); return; } put_msg("Undo complete"); }
static bool check_draw(Pos *pos, Move m) { do_move(pos, m, gives_check(pos, pos->st, m)); bool draw = is_draw(pos); // 64 undo_move(pos, m); return draw; }
/* Try to find a good move for the specified colour */ int suggest_move(c4_t board, char colour) { int c; /* look for a winning move for colour */ for (c=0; c<WIDTH; c++) { /* temporarily move in column c... */ if (do_move(board, c+1, colour)) { /* ... and check to see the outcome */ if (winner_found(board) == colour) { /* it is good, so unassign and return c */ undo_move(board, c+1); return c+1; } else { undo_move(board, c+1); } } } /* ok, no winning move, look for a blocking move */ if (colour == RED) { colour = YELLOW; } else { colour = RED; } for (c=0; c<WIDTH; c++) { /* temporarily move in column c... */ if (do_move(board, c+1, colour)) { /* ... and check to see the outcome */ if (winner_found(board) == colour) { /* it is good, so unassign and return c */ undo_move(board, c+1); return c+1; } else { undo_move(board, c+1); } } } /* no moves found? then pick at random... */ c = rand()%WIDTH; while (board[HEIGHT-1][c]!=EMPTY) { c = rand()%WIDTH; } return c+1; }
// Randomly where we don't own void decent_random(int *move) { move[0] = get_random_int(); move[1] = get_random_int(); while(do_move(move) < 0 || board[move[0]][move[1]] > 0) { move[0] = get_random_int(); move[1] = get_random_int(); } undo_move(move); }
int value(int alpha, int beta, int depth, int max, int algo, int max_depth) { int v = -INF, i, move[2]; if (depth > min(max_depth, NUM_MOVES_REMAINING)){ return eval_fn(); } for (i = 0; i < MAX_NUMBER_OF_POINTS; i++) { if(!next_point(move, i, algo)) break; if(do_move(move) > 0) { if (max) { v = max(v, value(alpha, beta, depth + 1, 0, algo, max_depth)); if (v >= beta) { undo_move(move); return v; } alpha = max(alpha, v); } else { v = min(v, value(alpha, beta, depth + 1, 1, algo, max_depth)); if (v <= alpha) { undo_move(move); return v; } beta = min(beta, v); } undo_move(move); } } return v; }
static uint64_t perft_helper(Pos *pos, Depth depth, uint64_t nodes) { ExtMove *m = (pos->st-1)->endMoves; ExtMove *last = pos->st->endMoves = generate_legal(pos, m); for (; m < last; m++) { do_move(pos, m->move, gives_check(pos, pos->st, m->move)); if (depth == 0) { nodes += generate_legal(pos, last) - last; } else nodes = perft_helper(pos, depth - ONE_PLY, nodes); undo_move(pos, m->move); } return nodes; }
/* Get a list of available book moves. The book can be a tree (AvlNode *book), or a file if <book> is NULL. Returns the combined score of all the moves if successfull. */ static int get_book_move_list(Board *board, MoveLst *move_list, const AvlNode *book) { int i, npos, tot_score; FILE *fp = NULL; ASSERT(1, board != NULL); ASSERT(1, move_list != NULL); npos = 0; tot_score = 0; if (book == NULL) { if ((fp = fopen(settings.book_file, "rb")) == NULL) { my_perror("Can't open file %s", settings.book_file); return -1; } npos = get_pos_count(fp); if (npos <= 0) { fprintf(stderr, "The opening book is empty\n"); return -1; } } gen_moves(board, move_list); for (i = 0; i < move_list->nmoves; i++) { U32 move = move_list->move[i]; int *score = &move_list->score[i]; make_move(board, move); if (get_nrepeats(board, 1) == 0) { U64 key = board->posp->key; if (book == NULL) *score = find_disk_pos(fp, key, npos); else *score = find_ram_pos(key, book); } else *score = VAL_NONE; if (*score != VAL_NONE) tot_score += *score; undo_move(board); } if (book == NULL) my_close(fp, settings.book_file); return tot_score; }
/* Returns 1 if player c has valid moves left. * c = 1 (white) or -1 (black) * If king is in check and no valid moves left, that implies checkmate */ int has_moves(board * brd, int c) { move * t = malloc(sizeof(move)); init_move(&t); generate_all_moves(c, brd, &t); move * t_ = t; while(t_->next != NULL) { if(apply_move(brd, &t_, c)) { undo_move(brd, &t_); free_moves(&t); return 1; } t_ = t_->next; } free_moves(&t); return 0; }
int main(int argc, char* argv[]) { setlocale(LC_ALL, ""); board_t board; RESET_BOARD(board); char buffer[256]; int len; hash_init(); run_all_tests(); print_board(&board); move_t m; while (1) { top: print_board(&board); move_t move = 0; while (move == 0) { printf("enter move> "); fgets(buffer, 255, stdin); if (!strcmp(buffer, "undo\n")) { undo_move(&board, m); goto top; } else if (!strcmp(buffer, "exit\n")) { return 0; } len = strlen(buffer); if (buffer[len-1] == '\n') buffer[len-1] = '\0'; move = move_from_text(buffer, &board); } make_move(&board, move); print_board(&board); printf("Calculating...\n"); m = think(&board); make_move(&board, m); printf("Done calculating...\n"); print_move(m); } return 0; }
std::string Protocol::search_move(bool use_san_notation) { Move m = game.root(depth + 1); if (m.is_null()) { if (game.is_check(game.current_position().side())) { return "LOST"; } return "DRAW"; } else { if (use_san_notation) { std::string res = game.output_move(m); play_move(m.to_string()); if (game.is_check(game.current_position().side())) { res += "+"; } undo_move(); return res; } return m.to_string(); } }
/* Recursively realizes feasible sequences of moves and calls * the evaulation function */ void alpha_better(int *move, int algo, int max_depth) { int best_v = 2 * INF, v = INF, i; int best_move[2]; int max = next_to_set; if(max) best_v = -2 * INF; for (i = 0; i < MAX_NUMBER_OF_POINTS; i = i + 1) { if(!next_point(move, i, algo)) break; if (do_move(move) == -1) continue; if (max) { v = value(-1 * INF, INF, 1, 0, algo, max_depth); if (v > best_v) { best_v = v; best_move[0] = move[0]; best_move[1] = move[1]; } } else { v = value(-1 * INF, INF, 1, 1, algo, max_depth); if (v < best_v) { best_v = v; best_move[0] = move[0]; best_move[1] = move[1]; } } undo_move(move); } move[0] = best_move[0]; move[1] = best_move[1]; }
int test_apply_move() { int status, num_moves, i; Board board; Move *moves; status = WIN; num_moves = 0; setup(&board); printb(&board); moves = gen_moves(&board, &num_moves); printf("found %d moves\n", num_moves); for(i=0; i<35 && i<num_moves; i++) { printf("move %d: %d is moving from %d to %d, capturing %d\n", i, moving_type(moves[i]), moves[i].from, moves[i].to, capturing_type(moves[i])); printf("board after move %d looks like:\n", i+1); apply_move(&board, moves[i]); printb(&board); undo_move(&board, moves[i]); } return status; }
int solve_step(t_pos *pos) { int moves[MAX_MOVES * 2]; int count = find_moves(pos, moves); int i, cell_id, value, ret, cur_status; //print_moves(count, moves); for (i = 0; i < count; ++i) { cell_id = moves[2 * i]; value = moves[2 * i + 1]; ret = OPEN; play_move(pos, cell_id, value); cur_status = solved(pos); if (cur_status != OPEN) { ret = cur_status; } else if (solve_step(pos) == SOLVED) { ret = SOLVED; } undo_move(pos, cell_id, value); if (ret == SOLVED) { return ret; } } return IMPOSSIBLE; }
uint64_t perft(Pos *pos, Depth depth) { uint64_t cnt, nodes = 0; char buf[16]; ExtMove *m = pos->moveList; ExtMove *last = pos->st->endMoves = generate_legal(pos, m); for (; m < last; m++) { if (depth <= ONE_PLY) { cnt = 1; nodes++; } else { do_move(pos, m->move, gives_check(pos, pos->st, m->move)); if (depth == 2 * ONE_PLY) cnt = generate_legal(pos, last) - last; else cnt = perft_helper(pos, depth - 3 * ONE_PLY, 0); nodes += cnt; undo_move(pos, m->move); } printf("%s: %"PRIu64"\n", uci_move(buf, m->move, is_chess960()), cnt); } return nodes; }
/* --------------------------------------------------------------*/ void play_gmp(Gameinfo *gameinfo, int simplified) { SGFTree sgftree; Gmp *ge; GmpResult message; const char *error; int i, j; int passes = 0; /* two passes and its over */ int to_move; /* who's turn is next ? */ int mycolor = -1; /* who has which color */ int yourcolor; if (gameinfo->computer_player == WHITE) mycolor = 1; else if (gameinfo->computer_player == BLACK) mycolor = 0; sgftree_clear(&sgftree); sgftreeCreateHeaderNode(&sgftree, board_size, komi, gameinfo->handicap); ge = gmp_create(0, 1); TRACE("board size=%d\n", board_size); /* * The specification of the go modem protocol doesn't even discuss * komi. So we have to guess the komi. If the komi is set on the * command line, keep it. Otherwise, its value will be 0.0 and we * use 5.5 in an even game, 0.5 otherwise. */ if (komi == 0.0) { if (gameinfo->handicap == 0) komi = 5.5; else komi = 0.5; } if (!simplified) { /* Leave all the -1's so the client can negotiate the game parameters. */ if (chinese_rules) gmp_startGame(ge, -1, -1, 5.5, -1, mycolor, 0); else gmp_startGame(ge, -1, -1, 5.5, 0, mycolor, 0); } else { gmp_startGame(ge, board_size, gameinfo->handicap, komi, chinese_rules, mycolor, 1); } do { message = gmp_check(ge, 1, NULL, NULL, &error); } while (message == gmp_nothing || message == gmp_reset); if (message == gmp_err) { fprintf(stderr, "gnugo-gmp: Error \"%s\" occurred.\n", error); exit(EXIT_FAILURE); } else if (message != gmp_newGame) { fprintf(stderr, "gnugo-gmp: Expecting a newGame, got %s\n", gmp_resultString(message)); exit(EXIT_FAILURE); } gameinfo->handicap = gmp_handicap(ge); if (!check_boardsize(gmp_size(ge), stderr)) exit(EXIT_FAILURE); gnugo_clear_board(gmp_size(ge)); /* Let's pretend GMP knows about komi in case something will ever change. */ komi = gmp_komi(ge); #if ORACLE if (metamachine && oracle_exists) oracle_clear_board(board_size); #endif sgfOverwritePropertyInt(sgftree.root, "SZ", board_size); TRACE("size=%d, handicap=%d, komi=%f\n", board_size, gameinfo->handicap, komi); if (gameinfo->handicap) to_move = WHITE; else to_move = BLACK; if (gmp_iAmWhite(ge)) { mycolor = WHITE; /* computer white */ yourcolor = BLACK; /* human black */ } else { mycolor = BLACK; yourcolor = WHITE; } gameinfo->computer_player = mycolor; sgf_write_header(sgftree.root, 1, get_random_seed(), komi, gameinfo->handicap, get_level(), chinese_rules); gameinfo->handicap = gnugo_sethand(gameinfo->handicap, sgftree.root); sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap); /* main GMP loop */ while (passes < 2) { if (to_move == yourcolor) { int move; /* Get opponent's move from gmp client. */ message = gmp_check(ge, 1, &j, &i, &error); if (message == gmp_err) { fprintf(stderr, "GNU Go: Sorry, error from gmp client\n"); sgftreeAddComment(&sgftree, "got error from gmp client"); sgffile_output(&sgftree); return; } if (message == gmp_undo) { int k; assert(j > 0); for (k = 0; k < j; k++) { if (!undo_move(1)) { fprintf(stderr, "GNU Go: play_gmp UNDO: can't undo %d moves\n", j - k); break; } sgftreeAddComment(&sgftree, "undone"); sgftreeBack(&sgftree); to_move = OTHER_COLOR(to_move); } continue; } if (message == gmp_pass) { passes++; move = PASS_MOVE; } else { passes = 0; move = POS(i, j); } TRACE("\nyour move: %1m\n\n", move); sgftreeAddPlay(&sgftree, to_move, I(move), J(move)); gnugo_play_move(move, yourcolor); sgffile_output(&sgftree); } else { /* Generate my next move. */ float move_value; int move; if (autolevel_on) adjust_level_offset(mycolor); move = genmove(mycolor, &move_value, NULL); gnugo_play_move(move, mycolor); sgffile_add_debuginfo(sgftree.lastnode, move_value); if (is_pass(move)) { /* pass */ sgftreeAddPlay(&sgftree, to_move, -1, -1); gmp_sendPass(ge); ++passes; } else { /* not pass */ sgftreeAddPlay(&sgftree, to_move, I(move), J(move)); gmp_sendMove(ge, J(move), I(move)); passes = 0; TRACE("\nmy move: %1m\n\n", move); } sgffile_add_debuginfo(sgftree.lastnode, 0.0); sgffile_output(&sgftree); } to_move = OTHER_COLOR(to_move); } /* two passes: game over */ gmp_sendPass(ge); if (!quiet) fprintf(stderr, "Game over - waiting for client to shut us down\n"); who_wins(mycolor, stderr); if (showtime) { gprintf("\nSLOWEST MOVE: %d at %1m ", slowest_movenum, slowest_move); fprintf(stderr, "(%.2f seconds)\n", slowest_time); fprintf(stderr, "\nAVERAGE TIME: %.2f seconds per move\n", total_time / movenum); fprintf(stderr, "\nTOTAL TIME: %.2f seconds\n", total_time); } /* play_gmp() does not return to main(), therefore the score * writing code is here. */ { float score = gnugo_estimate_score(NULL, NULL); sgfWriteResult(sgftree.root, score, 1); } sgffile_output(&sgftree); if (!simplified) { /* We hang around here until cgoban asks us to go, since * sometimes cgoban crashes if we exit first. * * FIXME: Check if this is still needed. I made it dependand on * `simplifed' just to avoid changes in GMP mode. */ while (1) { message = gmp_check(ge, 1, &j, &i, &error); if (!quiet) fprintf(stderr, "Message %d from gmp\n", message); if (message == gmp_err) break; } } #if ORACLE if (metamachine && oracle_exists) dismiss_oracle(); #endif if (!quiet) fprintf(stderr, "gnugo going down\n"); }
int alpha_beta(app_t *app, cnodeptr_t parent, int alpha, int beta, int depth) { int palpha = alpha; int i, score = -MATE, highest = -MATE; node_t node; move_t cutoff = 0; piece_t p; init_node(&node); assert(app); app->search.nodes++; node.depth = depth; /* max depth */ if (app->game.board->ply > (SEARCH_MAXDEPTH - 1)) { /* return evaluate(app->board); */ return quiescent(app, parent, alpha, beta); } /* recursive base */ if (depth == 0) { return evaluate(app->game.board); } /* draws */ if (repetitions(app) || (app->game.board->half >= 100)) { return 0; } /* if we are checked, set the nodes checked flag */ if (check(app->game.board, app->game.board->side)) { node.flags |= NODE_CHECK; /* extend our search by 1 depth if we are in check */ /* NOTES: we may want to NOT extend our search here if the parent is in check, because the means we already extended once */ depth++; } /* TODO: - NULL moves - Late-move reduction - Tactical extensions (pins & forks -> depth++) */ /* probe our table */ if (probe_hash(&app->hash, app->game.board, &cutoff, &score, depth, alpha, beta) == TRUE) { app->hash.cut++; return score; } /* generate moves */ generate_moves(app->game.board, &node.ml, &node.ml); /* reset score */ score = -MATE; /* try to match our hash hit move */ if (cutoff != 0) { for (i = 0; i < node.ml.count; i++) { if (node.ml.moves[i] == cutoff) { node.ml.scores[i] = 20000; break; } } } /* search negamax */ for (i = 0; i < node.ml.count; i++) { /* get the next move ordered */ next_move(i, &node.ml); if (!(do_move(app->game.board, &app->game.undo, node.ml.moves[i]))) continue; score = -alpha_beta(app, &node, -beta, -alpha, depth - 1); node.made++; undo_move(app->game.board, &app->game.undo); /* score whatever is best so far */ if (score > highest) { node.best = node.ml.moves[i]; highest = score; /* update alpha */ if (score > alpha) { if (score >= beta) { /* non-captures causing beta cutoffs (killers) */ if (!is_capture(node.ml.moves[i])) { app->game.board->killers[1][app->game.board->ply] = app->game.board->killers[0][app->game.board->ply]; app->game.board->killers[0][app->game.board->ply] = node.ml.moves[i]; } /* store this beta in our transposition table */ store_hash(&app->hash, app->game.board, node.best, beta, HASH_BETA, depth); return beta; } /* update alpha */ alpha = score; /* update our history */ if (!is_capture(node.best)) { p = app->game.board->pos.squares[move_from(node.best)]; app->game.board->history[piece_color(p)][piece_type(p)][move_to(node.best)] += depth; } } } } /* check for checkmate or stalemate */ if (!node.made) { if (node.flags & NODE_CHECK) { return -MATE + app->game.board->ply; } else { return 0; } } if (alpha != palpha) { /* store this as an exact, since we beat alpha */ store_hash(&app->hash, app->game.board, node.best, highest, HASH_EXACT, depth); } else { /* store the current alpha */ store_hash(&app->hash, app->game.board, node.best, alpha, HASH_ALPHA, depth); } return alpha; }
static score_t scout_search(searchNode *node, int depth, uint64_t *node_count_serial) { // Initialize the search node. initialize_scout_node(node, depth); // check whether we should abort if (should_abort_check() || parallel_parent_aborted(node)) { return 0; } // Pre-evaluate this position. leafEvalResult pre_evaluation_result = evaluate_as_leaf(node, SEARCH_SCOUT); // If we decide to stop searching, return the pre-evaluation score. if (pre_evaluation_result.type == MOVE_EVALUATED) { return pre_evaluation_result.score; } // Populate some of the fields of this search node, using some // of the information provided by the pre-evaluation. int hash_table_move = pre_evaluation_result.hash_table_move; node->best_score = pre_evaluation_result.score; node->quiescence = pre_evaluation_result.should_enter_quiescence; // Grab the killer-moves for later use. move_t killer_a = killer[KMT(node->ply, 0)]; move_t killer_b = killer[KMT(node->ply, 1)]; // Store the sorted move list on the stack. // MAX_NUM_MOVES is all that we need. sortable_move_t move_list[MAX_NUM_MOVES]; // Obtain the sorted move list. int num_of_moves = get_sortable_move_list(node, move_list, hash_table_move); int number_of_moves_evaluated = 0; // A simple mutex. See simple_mutex.h for implementation details. simple_mutex_t node_mutex; init_simple_mutex(&node_mutex); // Sort the move list. sort_incremental(move_list, num_of_moves, 0); moveEvaluationResult result; for (int mv_index = 0; mv_index < num_of_moves; mv_index++) { if (mv_index == 1) { sort_full(move_list, num_of_moves); // sortable_move_t new_move_list[MAX_NUM_MOVES]; //memcpy(new_move_list, move_list, num_of_moves*sizeof(sortable_move_t)); //: sort_incremental_full(move_list,num_of_moves); } // Get the next move from the move list. int local_index = number_of_moves_evaluated++; move_t mv = get_move(move_list[local_index]); if (TRACE_MOVES) { print_move_info(mv, node->ply); } // increase node count __sync_fetch_and_add(node_count_serial, 1); evaluateMove(&result, node, mv, killer_a, killer_b, SEARCH_SCOUT, node_count_serial); undo_move(&result.next_node, mv); if (result.type == MOVE_ILLEGAL || result.type == MOVE_IGNORE || abortf || parallel_parent_aborted(node)) { continue; } // A legal move is a move that's not KO, but when we are in quiescence // we only want to count moves that has a capture. if (result.type == MOVE_EVALUATED) { node->legal_move_count++; } // process the score. Note that this mutates fields in node. bool cutoff = search_process_score(node, mv, local_index, &result, SEARCH_SCOUT); if (cutoff) { node->abort = true; break; } } if (parallel_parent_aborted(node)) { return 0; } if (node->quiescence == false) { update_best_move_history(node->position, node->best_move_index, move_list, number_of_moves_evaluated); } tbassert(abs(node->best_score) != -INF, "best_score = %d\n", node->best_score); // Reads node->position->key, node->depth, node->best_score, and node->ply update_transposition_table(node); return node->best_score; }
static int print_pv(app_t *app, int depth) { int count = 0; piece_t p; u8 from; move_t mv; assert(app); assert(app->game.board); #define VIA_PROBE #ifdef VIA_PROBE /* get the current position */ mv = probe_hash_move(&app->hash, app->game.board->key); while ((mv != 0) && (count < depth)) { if (find_move(app, mv)) { from = move_from(mv); p = app->game.board->pos.squares[from]; if (do_move(app->game.board, &app->game.undo, mv)) { app->search.pv[count++] = mv; print_algebraic(p, mv); printf(" "); } else { break; } } else { break; } mv = probe_hash_move(&app->hash, app->game.board->key); } #else while (app->search.pv[count]) { mv = app->search.pv[count++]; if (find_move(app, mv)) { from = move_from(mv); p = app->board->pos.squares[from]; if (do_move(app->board, &app->ul, mv)) { print_algebraic(p, mv); printf(" "); } else { break; } } else { break; } } #endif while (app->game.board->ply) { undo_move(app->game.board, &app->game.undo); } return count; }
/** * @brief Builds move tree. * * Builds a complete move tree recursively. * * @param[in] color Color to move * @param[out] *i_selected Pointer to horizontal coordinate of selected move. * @param[out] *j_selected Pointer to vertical coordinate of selected move. * @return Nothing * @note If no move is selected i and j are INVALID. */ void search_tree( int color, int *i_selected, int *j_selected ) { // Index variables: int k; int d; //int m; //DEBUG int i, j; // Variables for search tree: int depth = 0; int best_value; int search_level_incr; int alpha; int beta; // Variables for move list: int valid_moves[BOARD_SIZE_MAX * BOARD_SIZE_MAX][4]; int nr_of_valid_moves; int nr_of_valid_moves_cut; // Variables for measuring time: time_t start; time_t stop; time_t diff_time; // Variables needed for logging: char x[2]; char y[3]; // Setting to root level values: alpha = INT_MIN; beta = INT_MAX; hash_hit = 0; alpha_break = 0; beta_break = 0; search_level_incr = 0; count_quiet_search = 0; //init_brains(); init_search_stats(); //init_hash_table(); best_value = ( color == BLACK ) ? INT_MIN : INT_MAX; node_count = 0; if ( do_log ) { log_file = fopen( LOG_FILE, "w" ); if ( log_file == NULL ) { printf( "# Cannot open log file\n" ); exit(1); } } (void) time(&start); nr_of_valid_moves = get_valid_move_list( color, valid_moves ); nr_of_valid_moves_cut = nr_of_valid_moves; // Loop start: search_level_incr = get_search_depth(); for ( d = 0; d <= search_level_incr; d++ ) { set_search_depth(d); //set_search_level(search_level_incr); //l = search_level_incr; // Go through move list: for ( k = 0; k < nr_of_valid_moves_cut; k++ ) { i = valid_moves[k][0]; j = valid_moves[k][1]; // Make move: node_count++; //printf( "# Level: %d make: %d,%d value: %d\n", l, i, j, best_value ); make_move( color, i, j ); //i_to_x( i, x ); //j_to_y( j, y ); //printf( "## %s%s\n", x, y ); // Start recursion: valid_moves[k][2] = add_node( color * -1, depth, alpha, beta ); if ( color == BLACK ) { // For black: remember highest value if ( valid_moves[k][2] > best_value ) { best_value = valid_moves[k][2]; if ( best_value > alpha ) { alpha = best_value; } } } else { // For white: remember lowest value if ( valid_moves[k][2] < best_value ) { best_value = valid_moves[k][2]; if ( best_value < beta ) { beta = best_value; } } } if ( do_log ) { i_to_x( i, x ); j_to_y( j, y ); fprintf( log_file, "%s%s (%d) (a: %d, b: %d)\n" , x, y, valid_moves[k][2], alpha, beta ); } undo_move(); } // Sort move list by value: if ( color == BLACK ) { qsort( valid_moves, (size_t)nr_of_valid_moves_cut, sizeof(valid_moves[0]), compare_value_black ); } else { qsort( valid_moves, (size_t)nr_of_valid_moves_cut, sizeof(valid_moves[0]), compare_value_white ); } // DEBUG: /* printf( "# Level: %d (%d) - ", l, nr_of_valid_moves_cut ); for ( m = 0; m < nr_of_valid_moves_cut; m++ ) { i_to_x( valid_moves[m][0], x ); j_to_y( valid_moves[m][1], y ); printf( "%s%s (%d,%d), ", x, y, valid_moves[m][2], valid_moves[m][3] ); } printf("\n"); */ if ( nr_of_valid_moves_cut / 2 > 5 ) { nr_of_valid_moves_cut = nr_of_valid_moves_cut / 2; } } // Loop end (void) time(&stop); diff_time = stop - start; if ( diff_time == 0 ) { diff_time = 1; } // Save some stats about this search: search_stats.color[0] = '\0'; if ( color == BLACK ) { my_strcpy( search_stats.color, "Black", 6 ); } else { my_strcpy( search_stats.color, "White", 6 ); } i_to_x( valid_moves[0][0], x ); j_to_y( valid_moves[0][1], y ); search_stats.move[0] = '\0'; strcat( search_stats.move, x ); strcat( search_stats.move, y ); search_stats.level = search_depth; search_stats.duration = stop - start; search_stats.node_count = node_count; search_stats.nodes_per_sec = node_count / diff_time; search_stats.qsearch_count = count_quiet_search; search_stats.hash_hit = hash_hit; search_stats.alpha_cut = alpha_break; search_stats.beta_cut = beta_break; search_stats.value = valid_moves[0][2]; *i_selected = valid_moves[0][0]; *j_selected = valid_moves[0][1]; if ( log_file != NULL ) { fclose(log_file); } return; }
/** * @brief Adds a new node to the move tree. * * A new node is added to the move tree. For every move in the generated move * list, a new node is added recursively. If a certain level is reached, the * recusrion is stopped. * * @param[in] color Color of move to set. * @param[in] depth Counter that shows the level in the move tree. * @param[in] alpha Alpha-Beta pruning * @param[in] beta Alpha-Beta pruning * @return Value of position */ int add_node( int color, int depth, int alpha, int beta ) { int k, l; int i, j; int valid_moves[BOARD_SIZE_MAX * BOARD_SIZE_MAX][4]; int nr_of_valid_moves; int best_value; char x[2]; char y[3]; char indent[10]; int tactic_move = 0; int qsearch = MAX_QSEARCH_DEPTH; //unsigned hash_id; int value_list[COUNT_BRAINS] = { 1, 2, 3, 4, 5, 6, 7, 8 }; best_value = ( color == BLACK ) ? INT_MIN : INT_MAX; if ( ! ( ( search_depth + MAX_QSEARCH_DEPTH ) % 2 ) ) { qsearch++; } depth++; nr_of_valid_moves = get_valid_move_list( color, valid_moves ); // PASS if no valid move is possible: if ( nr_of_valid_moves == 0 ) { make_move( color, INVALID, INVALID ); best_value = evaluate_position( value_list, false ); undo_move(); } // Count tactic moves: for ( l = 0; l < nr_of_valid_moves; l++ ) { if ( valid_moves[l][3] > 0 ) { tactic_move++; } } // Go through move list: for ( k = 0; k < nr_of_valid_moves; k++ ) { i = valid_moves[k][0]; j = valid_moves[k][1]; // Skip non-tactical moves in quiescense search: if ( depth >= search_depth && tactic_move > 0) { if ( valid_moves[k][3] == 0 ) { continue; } } // Make move: node_count++; make_move( color, i, j ); if ( depth < search_depth ) { // Start recursion: valid_moves[k][2] = add_node( color * -1, depth, alpha, beta ); } else { //insert_hash_table( hash_id, best_value ); if ( tactic_move && depth < search_depth + qsearch ) { valid_moves[k][2] = add_node( color * -1, depth, alpha, beta ); count_quiet_search++; } else { valid_moves[k][2] = evaluate_position( value_list, true ); } } if ( color == BLACK ) { // For black: remember highest value if ( valid_moves[k][2] > best_value ) { best_value = valid_moves[k][2]; if ( best_value > alpha ) { alpha = best_value; } } } else { // For white: remember lowest value if ( valid_moves[k][2] < best_value ) { best_value = valid_moves[k][2]; if ( best_value < beta ) { beta = best_value; } } } if ( do_log ) { i_to_x( i, x ); j_to_y( j, y ); indent[0] = '\0'; for ( l = 1; l <= depth; l++ ) { strcat( indent, "\t" ); } fprintf( log_file, "%s%s%s (%d) (T: %d) (%d,%d,%d,%d,%d,%d,%d,%d) (a: %d, b: %d)\n" , indent, x, y , valid_moves[k][2], valid_moves[k][3], value_list[0], value_list[1] , value_list[2], value_list[3], value_list[4], value_list[5] , value_list[6], value_list[7] , alpha, beta ); } undo_move(); if ( color == BLACK ) { if ( valid_moves[k][2] > beta ) { // Maybe only '>' is correct?! beta_break++; break; } } else { if ( valid_moves[k][2] < alpha ) { // Maybe only '<' is correct?! alpha_break++; break; } } } return best_value; }
void bk( tmove *m, int n ) { int moves[80], values[80], idx; int pass; int sumvalues=0; #define SHOWECO #ifdef SHOWECO static int att=1; static int seco=0; if( att != 0 && Eco!=NULL ) { typedef struct teco { unsigned hashboard; unsigned point; } teco; static struct teco * peco = NULL; if( att==1 && Counter==0 && G[Counter].hashboard==0x39512910 /*init*/) { int c; tmove * move; peco = malloc(2048*sizeof(teco)); if( peco == NULL ) { puts(" telluser cannot alloc memory for ECO"); att=0; goto abort; } printf("telluser creating ECO index, please wait\n"); while( (c=fgetc(Eco))!='[' ) if( c==EOF ) goto doneinit; for(;;) { tmove m[128]; char ms[32]; int msi; int n; (peco+seco)->point=ftell(Eco)-1; while( (c=getc(Eco))!=']' ) if( c==EOF ) goto doneinit; if( c==EOF ) goto doneinit; setfen("rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/w"); for(;;) { msi=0; while( (c=getc(Eco))==' ' || c=='\n' ) {} ungetc(c,Eco); while( (c=getc(Eco))!=' ' && c!='\n' && msi<=30 ) { ms[msi]=c; msi++; if( c==EOF || c=='[' ) { ungetc(c,Eco); goto nextgame; } } ms[msi]='\0'; /* printf("%s ",ms); */ generate_legal_moves( m, &n, checktest(Color) ); move=sandex(ms,m,n); if( move==NULL ) goto nextgame; do_move(move); if( c==EOF ) goto doneinit; } nextgame:; peco[seco].hashboard=G[Counter].hashboard; seco++; while( (c=fgetc(Eco))!='[' ) if( c==EOF ) goto doneinit; } doneinit:; printf(" parsed %i ECO records\n",seco); att=2; setfen("rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/w"); } if( Counter>0 && att>1 ) { int counter=Counter; int text=-1; while( Counter > 0 ) { int i; for(i=0;i!=seco;i++) if(peco[i].hashboard==G[Counter].hashboard) { text=peco[i].point; goto foundeco; } undo_move( & G[Counter-1].m ); } foundeco:; while( counter > Counter ) do_move( & G[Counter].m ); if( text==-1 ) printf(" no eco found\n"); else { char t[128], * c; fseek(Eco,text,SEEK_SET); fgets(t,126,Eco); t[127]='\0'; c=strchr(t,'['); if(c!=NULL) *c = ' '; c=strrchr(t,']'); if(c!=NULL) *c = '\0'; puts(t); } } abort:; } #endif for( pass=0; pass!=2; pass++ ) { if( pass==0 ) { int i; idx = bookmoves(moves,values,m,n); if( idx != -1 ) for(i=0;i!=idx;i++) sumvalues += values[i]; printf(" primary book moves\n"); } else { idx = sbookmoves(moves,values,m,n); printf(" secondary book moves\n"); } if( idx > 0 ) { int i; for( i=0; i!=idx; i++ ) if( i==0 || moves[i-1]!=moves[i] ) { printf(" "); printm( m[moves[i]], NULL ); if(pass==0) printf("%3d%%\n",values[i]*100/sumvalues); else printf("\n"); } } else printf(" no move found\n"); } if( Flag.xboard>1 ) puts(""); { char c[128]; postr(c); printf("%s\n",c); } }