Add pruning_threshold option to allow forced tree pruning when
[pachi/peepo.git] / playout.c
blob8edfec58360327d60d3c61f30b12be42416b3da1
1 #define DEBUG
2 #include <assert.h>
3 #include <math.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
8 #include "board.h"
9 #include "debug.h"
10 #include "engine.h"
11 #include "move.h"
12 #include "ownermap.h"
13 #include "playout.h"
15 /* Whether to set global debug level to the same as the playout
16 * has, in case it is different. This can make sure e.g. tactical
17 * reading produces proper level of debug prints during simulations.
18 * But it is safe to enable this only in single-threaded instances! */
19 //#define DEBUGL_BY_PLAYOUT
21 #define PLDEBUGL(n) DEBUGL_(policy->debug_level, n)
24 int
25 play_random_game(struct playout_setup *setup,
26 struct board *b, enum stone starting_color,
27 struct playout_amafmap *amafmap,
28 struct board_ownermap *ownermap,
29 struct playout_policy *policy)
31 assert(setup && policy);
33 int gamelen = setup->gamelen - b->moves;
34 if (gamelen < 10)
35 gamelen = 10;
37 if (policy->setboard)
38 policy->setboard(policy, b);
39 #ifdef DEBUGL_BY_PLAYOUT
40 int debug_level_orig = debug_level;
41 debug_level = policy->debug_level;
42 #endif
44 enum stone color = starting_color;
46 int passes = is_pass(b->last_move.coord) && b->moves > 0;
48 while (gamelen-- && passes < 2) {
49 coord_t coord;
50 coord = policy->choose(policy, b, color);
52 if (is_pass(coord)) {
53 play_random:
54 /* Defer to uniformly random move choice. */
55 /* This must never happen if the policy is tracking
56 * internal board state, obviously. */
57 assert(!policy->setboard);
58 board_play_random(b, color, &coord, (ppr_permit) policy->permit, policy);
60 } else {
61 struct move m;
62 m.coord = coord; m.color = color;
63 if (board_play(b, &m) < 0) {
64 if (PLDEBUGL(4)) {
65 fprintf(stderr, "Pre-picked move %d,%d is ILLEGAL:\n",
66 coord_x(coord, b), coord_y(coord, b));
67 board_print(b, stderr);
69 goto play_random;
73 #if 0
74 /* For UCT, superko test here is downright harmful since
75 * in superko-likely situation we throw away literally
76 * 95% of our playouts; UCT will deal with this fine by
77 * itself. */
78 if (unlikely(b->superko_violation)) {
79 /* We ignore superko violations that are suicides. These
80 * are common only at the end of the game and are
81 * rather harmless. (They will not go through as a root
82 * move anyway.) */
83 if (group_at(b, coord)) {
84 if (DEBUGL(3)) {
85 fprintf(stderr, "Superko fun at %d,%d in\n", coord_x(coord, b), coord_y(coord, b));
86 if (DEBUGL(4))
87 board_print(b, stderr);
89 return 0;
90 } else {
91 if (DEBUGL(6)) {
92 fprintf(stderr, "Ignoring superko at %d,%d in\n", coord_x(coord, b), coord_y(coord, b));
93 board_print(b, stderr);
95 b->superko_violation = false;
98 #endif
100 if (PLDEBUGL(7)) {
101 fprintf(stderr, "%s %s\n", stone2str(color), coord2sstr(coord, b));
102 if (PLDEBUGL(8))
103 board_print(b, stderr);
106 if (unlikely(is_pass(coord))) {
107 passes++;
108 } else {
109 /* We don't care about nakade counters, since we want
110 * to avoid taking pre-nakade moves into account only
111 * if they happenned in the tree before nakade nodes;
112 * but this is always out of the tree. */
113 if (amafmap) {
114 if (amafmap->map[coord] == S_NONE || amafmap->map[coord] == color)
115 amafmap->map[coord] = color;
116 else if (amafmap->record_nakade)
117 amaf_op(amafmap->map[coord], +);
118 amafmap->game[amafmap->gamelen].coord = coord;
119 amafmap->game[amafmap->gamelen].color = color;
120 amafmap->gamelen++;
121 assert(amafmap->gamelen < sizeof(amafmap->game) / sizeof(amafmap->game[0]));
124 passes = 0;
127 if (setup->mercymin && abs(b->captures[S_BLACK] - b->captures[S_WHITE]) > setup->mercymin)
128 break;
130 color = stone_other(color);
133 float score = board_fast_score(b);
134 int result = (starting_color == S_WHITE ? score * 2 : - (score * 2));
136 if (DEBUGL(6)) {
137 fprintf(stderr, "Random playout result: %d (W %f)\n", result, score);
138 if (DEBUGL(7))
139 board_print(b, stderr);
142 if (ownermap)
143 board_ownermap_fill(ownermap, b);
145 if (b->ps)
146 free(b->ps);
148 #ifdef DEBUGL_BY_PLAYOUT
149 debug_level = debug_level_orig;
150 #endif
152 return result;