/* Full board matching in database for fuseki moves. Return 1 if any * pattern found. */ static int search_fuseki_database(int color) { struct fullboard_pattern *database; int q; int k; int best_fuseki_value; /* Disable matching after a certain number of stones are placed on * the board. */ if (stones_on_board(BLACK | WHITE) > MAX_FUSEKI_DATABASE_STONES) return 0; /* We only have databases for 9x9, 13x13 and 19x19. */ if (board_size == 9) database = fuseki9; else if (board_size == 13) database = fuseki13; else if (board_size == 19) database = fuseki19; else return 0; /* Do the matching. */ num_fuseki_moves = 0; fuseki_total_value = 0; fullboard_matchpat(fuseki_callback, color, database); /* No match. */ if (num_fuseki_moves == 0) return 0; /* Choose randomly with respect to relative weights for matched moves. */ /* Do not choose moves with less value than 20% of the best move */ best_fuseki_value = fuseki_value[0]; q = gg_rand() % fuseki_total_value; for (k = 0; k < num_fuseki_moves; k++) { if (fuseki_value[k] < (best_fuseki_value / 5)) break; q -= fuseki_value[k]; if (q < 0) break; } gg_assert(k < num_fuseki_moves); /* Give this move an arbitrary value of 75. The actual value doesn't * matter much since the intention is that we should play this move * whatever the rest of the analysis thinks. */ announce_move(fuseki_moves[k], 75, color); /* Also make sure the other considered moves can be seen in the * traces and in the output file. */ for (k = 0; k < num_fuseki_moves; k++) set_minimum_move_value(fuseki_moves[k], 74); return 1; }
static int uniform_rand_10(void) { uint8_t rval; do { if (gg_rand(&rval, sizeof(rval)) != 0) exit(-1); } while (rval >= 250); return (rval % 10); }
static void choose_corner_move(struct board_lib_state_struct *internal_state, int corner, int *m, int *n) { int *table = 0; int sum_of_weights = 0; int i; int q; if (internal_state->board_size <= 11) table = small_board; else if (internal_state->board_size <= 15) table = medium_board; else table = large_board; for (i = 0; i < 8; i++) sum_of_weights += table[i]; q = gg_rand() % sum_of_weights; for (i = 0; i < 8; i++) { q -= table[i]; if (q < 0) break; } *m = corners[i][0]; *n = corners[i][1]; switch (corner) { case UPPER_LEFT: *m = *m - 1; *n = *n - 1; break; case UPPER_RIGHT: *m = *m - 1; *n = internal_state->board_size - *n; break; case LOWER_LEFT: *m = internal_state->board_size - *m; *n = *n - 1; break; case LOWER_RIGHT: *m = internal_state->board_size - *m; *n = internal_state->board_size - *n; break; } }
static int find_free_handicap_pattern() { int k; int highest_value = -1; int sum_values = 0; int r; int anchor; struct pattern *pattern; int ll; int move; number_of_matches = 0; matchpat(free_handicap_callback, BLACK, &handipat_db, NULL, NULL); if (number_of_matches == 0) return 0; /* Find the highest value among the matched patterns. */ for (k = 0; k < number_of_matches; k++) if (highest_value < handicap_matches[k].value) highest_value = handicap_matches[k].value; /* Replace the values by 2^(value - highest_value + 10) and compute * the sum of these values. Fractional values are discarded. */ for (k = 0; k < number_of_matches; k++) { if (handicap_matches[k].value < highest_value - 10) handicap_matches[k].value = 0; else handicap_matches[k].value = 1 << (handicap_matches[k].value - highest_value + 10); sum_values += handicap_matches[k].value; } /* Pick a random number between 0 and sum_values. Don't bother with * the fact that lower numbers will tend to be very slightly * overrepresented. */ r = gg_rand() % sum_values; /* Find the chosen pattern. */ for (k = 0; k < number_of_matches; k++) { r -= handicap_matches[k].value; if (r < 0) break; } /* Place handicap stones according to pattern k. */ anchor = handicap_matches[k].anchor; pattern = handicap_matches[k].pattern; ll = handicap_matches[k].ll; /* Pick up the location of the move */ move = AFFINE_TRANSFORM(pattern->move_offset, ll, anchor); add_stone(move, BLACK); remaining_handicap_stones--; /* Add stones at all '!' in the pattern. */ for (k = 0; k < pattern->patlen; k++) { if (pattern->patn[k].att == ATT_not) { int pos = AFFINE_TRANSFORM(pattern->patn[k].offset, ll, anchor); add_stone(pos, BLACK); remaining_handicap_stones--; } } return 1; }
void play_solo(Gameinfo *gameinfo, int moves) { SGFTree sgftree; int passes = 0; /* num. consecutive passes */ int move_val; double t1, t2; int save_moves = moves; int boardsize = gnugo_get_boardsize(); struct stats_data totalstats; int total_owl_count = 0; /* It tends not to be very imaginative in the opening, * so we scatter a few stones randomly to start with. * We add two random numbers to reduce the probability * of playing stones near the edge. */ int n = 6 + 2*gg_rand()%5; int i, j; gnugo_set_komi(5.5); sgftree_clear(&sgftree); sgftreeCreateHeaderNode(&sgftree, gnugo_get_boardsize(), gnugo_get_komi()); sgf_write_header(sgftree.root, 1, random_seed, 5.5, level, chinese_rules); /* Generate some random moves. */ if (boardsize > 6) { do { do { i = (gg_rand() % 4) + (gg_rand() % (boardsize - 4)); j = (gg_rand() % 4) + (gg_rand() % (boardsize - 4)); } while (!gnugo_is_legal(i, j, gameinfo->to_move)); gnugo_play_move(i, j, gameinfo->to_move); sgftreeAddPlay(&sgftree, gameinfo->to_move, i, j); sgftreeAddComment(&sgftree, "random move"); gameinfo->to_move = OTHER_COLOR(gameinfo->to_move); } while (--n > 0); } t1 = gg_cputime(); memset(&totalstats, '\0', sizeof(totalstats)); while (passes < 2 && --moves >= 0) { reset_owl_node_counter(); move_val = gnugo_genmove(&i, &j, gameinfo->to_move); gnugo_play_move(i, j, gameinfo->to_move); sgffile_add_debuginfo(sgftree.lastnode, move_val); sgftreeAddPlay(&sgftree, gameinfo->to_move, i, j); sgffile_output(&sgftree); gameinfo->to_move = OTHER_COLOR(gameinfo->to_move); if (move_val < 0) { ++passes; printf("%s(%d): Pass\n", gameinfo->to_move == BLACK ? "Black" : "White", movenum); } else { passes = 0; gprintf("%s(%d): %m\n", gameinfo->to_move == BLACK ? "Black" : "White", movenum, i, j); } totalstats.nodes += stats.nodes; totalstats.position_entered += stats.position_entered; totalstats.position_hits += stats.position_hits; totalstats.read_result_entered += stats.read_result_entered; totalstats.hash_collisions += stats.hash_collisions; total_owl_count += get_owl_node_counter(); } t2 = gg_cputime(); /* Two passes and it's over. (EMPTY == BOTH) */ gnugo_who_wins(EMPTY, stdout); score = gnugo_estimate_score(&lower_bound, &upper_bound); sgfWriteResult(sgftree.root, score, 1); sgffile_output(&sgftree); #if 0 if (t2 == t1) printf("%.3f moves played\n", (double) (save_moves-moves)); else printf("%.3f moves/sec\n", (save_moves-moves)/(t2-t1)); #else printf("%10d moves played in %0.3f seconds\n", save_moves-moves, t2-t1); if (save_moves != moves) printf("%10.3f seconds/move\n", (t2-t1)/(save_moves-moves)); printf("%10d nodes\n", totalstats.nodes); printf("%10d positions entered\n", totalstats.position_entered); printf("%10d position hits\n", totalstats.position_hits); printf("%10d read results entered\n", totalstats.read_result_entered); printf("%10d hash collisions\n", totalstats.hash_collisions); printf("%10d owl nodes\n", total_owl_count); #endif }
/* dfa_patterns_optimize_variations() tries to reduce the size of DFA by * altering pattern variations (in fact, transformations). The algorithm * is to change several patterns' variations and if this happens to give * size reduction, to keep the change, otherwise, revert. * * This function contains many heuristically chosen values for variation * changing probability etc. They have been chosen by observing algorithm * effectiveness and seem to be very good. * * Note that we subtract 1 from the number of nodes to be consistent with * the standard builder, which doesn't count error state. */ int * dfa_patterns_optimize_variations(dfa_patterns *patterns, int iterations) { int k = 0; int failed_iterations = 0; int min_nodes_so_far; int num_nodes_original; int *best_variations; double lower_limit = 2.0 / patterns->num_patterns; double upper_limit = 6.0 / patterns->num_patterns; double change_probability = 4.0 / patterns->num_patterns; dfa_pattern *pattern; best_variations = malloc(patterns->num_patterns * sizeof(*best_variations)); assert(best_variations); for (pattern = patterns->patterns; pattern; pattern = pattern->next, k++) best_variations[k] = pattern->current_variation; dfa_patterns_build_graph(patterns); num_nodes_original = patterns->graph.num_nodes; min_nodes_so_far = num_nodes_original; fprintf(stderr, "Original number of DFA states: %d\n", min_nodes_so_far - 1); fprintf(stderr, "Trying to optimize in %d iterations\n", iterations); gg_srand(num_nodes_original + patterns->num_patterns); while (iterations--) { int changed_variations = 0; int k = 0; /* Randomly change some variations. */ for (pattern = patterns->patterns; pattern; pattern = pattern->next, k++) { if (gg_drand() < change_probability && pattern->num_variations > 1) { int new_variation = gg_rand() % (pattern->num_variations - 1); if (new_variation >= pattern->current_variation) new_variation++; pattern->current_variation = new_variation; changed_variations++; } else pattern->current_variation = best_variations[k]; } if (changed_variations == 0) { iterations++; continue; } fprintf(stderr, "."); dfa_patterns_build_graph(patterns); if (patterns->graph.num_nodes < min_nodes_so_far) { /* If the new set of variations produces smaller dfa, save it. */ int k = 0; for (pattern = patterns->patterns; pattern; pattern = pattern->next, k++) best_variations[k] = pattern->current_variation; fprintf(stderr, "\nOptimized: %d => %d states (%d iterations left)\n", min_nodes_so_far - 1, patterns->graph.num_nodes - 1, iterations); min_nodes_so_far = patterns->graph.num_nodes; failed_iterations = 0; } else failed_iterations++; if (failed_iterations >= 30) { /* If haven't succeded in 30 last iterations, try to alter variation * change probability. */ double delta = gg_drand() / patterns->num_patterns; if (change_probability > upper_limit || (change_probability >= lower_limit && gg_rand() % 2 == 0)) delta = -delta; change_probability += delta; failed_iterations = 0; } } fprintf(stderr, "\nTotal optimization result: %d => %d states\n", num_nodes_original - 1, min_nodes_so_far - 1); dfa_graph_clear(&(patterns->graph)); return best_variations; }
void play_solo(Gameinfo *gameinfo, int moves) { SGFTree sgftree; int passes = 0; /* num. consecutive passes */ float move_value; double t1, t2; int save_moves = moves; struct stats_data totalstats; int total_owl_count = 0; /* It tends not to be very imaginative in the opening, * so we scatter a few stones randomly to start with. * We add two random numbers to reduce the probability * of playing stones near the edge. */ int n = 6 + 2*gg_rand()%5; int i, j; komi = 5.5; sgftree_clear(&sgftree); sgftreeCreateHeaderNode(&sgftree, board_size, komi, handicap); sgf_write_header(sgftree.root, 1, get_random_seed(), 5.5, handicap, get_level(), chinese_rules); /* Generate some random moves. */ if (board_size > 6) { do { do { i = (gg_rand() % 4) + (gg_rand() % (board_size - 4)); j = (gg_rand() % 4) + (gg_rand() % (board_size - 4)); } while (!is_allowed_move(POS(i, j), gameinfo->to_move)); gnugo_play_move(POS(i, j), gameinfo->to_move); sgftreeAddPlay(&sgftree, gameinfo->to_move, i, j); sgftreeAddComment(&sgftree, "random move"); gameinfo->to_move = OTHER_COLOR(gameinfo->to_move); } while (--n > 0); } t1 = gg_cputime(); memset(&totalstats, '\0', sizeof(totalstats)); while (passes < 2 && --moves >= 0) { int move; reset_owl_node_counter(); move = genmove(gameinfo->to_move, &move_value, NULL); gnugo_play_move(move, gameinfo->to_move); sgffile_add_debuginfo(sgftree.lastnode, move_value); sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move)); sgffile_output(&sgftree); gameinfo->to_move = OTHER_COLOR(gameinfo->to_move); if (move == PASS_MOVE) { passes++; printf("%s(%d): Pass\n", gameinfo->to_move == BLACK ? "Black" : "White", movenum); } else { passes = 0; gprintf("%s(%d): %1m\n", gameinfo->to_move == BLACK ? "Black" : "White", movenum, move); } totalstats.nodes += stats.nodes; totalstats.read_result_entered += stats.read_result_entered; totalstats.read_result_hits += stats.read_result_hits; totalstats.trusted_read_result_hits += stats.trusted_read_result_hits; total_owl_count += get_owl_node_counter(); } t2 = gg_cputime(); /* Two passes and it's over. (EMPTY == BOTH) */ who_wins(EMPTY, stdout); { float score = gnugo_estimate_score(NULL, NULL); sgfWriteResult(sgftree.root, score, 1); } sgffile_output(&sgftree); printf("%10d moves played in %0.3f seconds\n", save_moves-moves, t2-t1); if (save_moves != moves) printf("%10.3f seconds/move\n", (t2-t1)/(save_moves-moves)); printf("%10d nodes\n", totalstats.nodes); printf("%10d read results entered\n", totalstats.read_result_entered); printf("%10d read result hits\n", totalstats.read_result_hits); printf("%10d trusted read result hits\n", totalstats.trusted_read_result_hits); printf("%10d owl nodes\n", total_owl_count); }