Pattern: Tune for minimal collisions
[pachi.git] / playout.c
blobda62933b35519b799a3c5c5da52b5e8c7c2aaccb
1 #include <assert.h>
2 #include <math.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include "board.h"
8 #include "debug.h"
9 #include "engine.h"
10 #include "move.h"
11 #include "ownermap.h"
12 #include "playout.h"
13 #include "probdist.h"
16 static coord_t
17 try_probdist_move(struct board *b, enum stone color, struct playout_setup *setup)
19 /* First try probability distribution provided by
20 * the engine for this move. */
21 struct probdist pd;
22 probdist_init(&pd, board_size2(b));
24 setup->probdist(setup, &pd, b);
25 if (pd.moves[0] >= pd.total - __FLT_EPSILON__) {
26 probdist_done(&pd);
27 return pass;
30 coord_t coord = probdist_pick(&pd);
31 probdist_done(&pd);
33 /* If the pick is invalid, defer to policy. */
34 if (!coord || is_pass(coord))
35 return pass;
36 struct move m = { .coord = coord, .color = color };
37 if (!board_is_valid_move(b, &m))
38 return pass;
40 return coord;
43 int
44 play_random_game(struct playout_setup *setup,
45 struct board *b, enum stone starting_color,
46 struct playout_amafmap *amafmap,
47 struct board_ownermap *ownermap,
48 struct playout_policy *policy)
50 assert(setup && policy);
52 int gamelen = setup->gamelen - b->moves;
53 if (gamelen < 10)
54 gamelen = 10;
56 enum stone color = starting_color;
58 int passes = is_pass(b->last_move.coord) && b->moves > 0;
60 while (gamelen-- && passes < 2) {
61 coord_t coord = pass;
63 if (setup->probdist) {
64 coord = try_probdist_move(b, color, setup);
67 if (is_pass(coord)) {
68 /* Defer to policy move choice. */
69 coord = policy->choose(policy, b, color);
72 if (is_pass(coord)) {
73 play_random:
74 /* Defer to uniformly random move choice. */
75 board_play_random(b, color, &coord, (ppr_permit) policy->permit, policy);
77 } else {
78 struct move m;
79 m.coord = coord; m.color = color;
80 if (board_play(b, &m) < 0) {
81 if (DEBUGL(8)) {
82 fprintf(stderr, "Pre-picked move %d,%d is ILLEGAL:\n",
83 coord_x(coord, b), coord_y(coord, b));
84 board_print(b, stderr);
86 goto play_random;
90 #if 0
91 /* For UCT, superko test here is downright harmful since
92 * in superko-likely situation we throw away literally
93 * 95% of our playouts; UCT will deal with this fine by
94 * itself. */
95 if (unlikely(b->superko_violation)) {
96 /* We ignore superko violations that are suicides. These
97 * are common only at the end of the game and are
98 * rather harmless. (They will not go through as a root
99 * move anyway.) */
100 if (group_at(b, coord)) {
101 if (DEBUGL(3)) {
102 fprintf(stderr, "Superko fun at %d,%d in\n", coord_x(coord, b), coord_y(coord, b));
103 if (DEBUGL(4))
104 board_print(b, stderr);
106 return 0;
107 } else {
108 if (DEBUGL(6)) {
109 fprintf(stderr, "Ignoring superko at %d,%d in\n", coord_x(coord, b), coord_y(coord, b));
110 board_print(b, stderr);
112 b->superko_violation = false;
115 #endif
117 if (DEBUGL(7)) {
118 fprintf(stderr, "%s %s\n", stone2str(color), coord2sstr(coord, b));
119 if (DEBUGL(8))
120 board_print(b, stderr);
123 if (unlikely(is_pass(coord))) {
124 passes++;
125 } else {
126 /* We don't care about nakade counters, since we want
127 * to avoid taking pre-nakade moves into account only
128 * if they happenned in the tree before nakade nodes;
129 * but this is always out of the tree. */
130 if (amafmap) {
131 if (amafmap->map[coord] == S_NONE || amafmap->map[coord] == color)
132 amafmap->map[coord] = color;
133 else if (amafmap->record_nakade)
134 amaf_op(amafmap->map[coord], +);
135 amafmap->game[amafmap->gamelen].coord = coord;
136 amafmap->game[amafmap->gamelen].color = color;
137 amafmap->gamelen++;
138 assert(amafmap->gamelen < sizeof(amafmap->game) / sizeof(amafmap->game[0]));
141 passes = 0;
144 color = stone_other(color);
147 float score = board_fast_score(b);
148 int result = (starting_color == S_WHITE ? score * 2 : - (score * 2));
150 if (DEBUGL(6)) {
151 fprintf(stderr, "Random playout result: %d (W %f)\n", result, score);
152 if (DEBUGL(7))
153 board_print(b, stderr);
156 if (ownermap)
157 board_ownermap_fill(ownermap, b);
159 return result;