1lib.c: don't use board clen in tactics
[pachi.git] / replay / replay.c
blob312e37753721994ddb06cca05ceda107144f470f
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
5 #define DEBUG
6 #include "board.h"
7 #include "debug.h"
8 #include "engine.h"
9 #include "move.h"
10 #include "playout.h"
11 #include "joseki/base.h"
12 #include "playout/light.h"
13 #include "playout/moggy.h"
14 #include "replay/replay.h"
16 /* Internal engine state. */
17 struct replay {
18 int debug_level;
19 int runs;
20 int no_suicide;
21 struct joseki_dict *jdict;
22 struct playout_policy *playout;
25 static void
26 suicide_stats(int suicide)
28 static int total = 0;
29 static int suicides = 0;
30 if (suicide) suicides++;
31 if (++total % 100 == 0)
32 fprintf(stderr, "Suicides: %i/%i (%i%%)\n", suicides, total, suicides * 100 / total);
35 coord_t
36 replay_sample_moves(struct engine *e, struct board *b, enum stone color,
37 int *played, int *pmost_played)
39 struct replay *r = e->data;
40 struct playout_setup setup; memset(&setup, 0, sizeof(setup));
41 struct move m = { .coord = pass, .color = color };
42 int most_played = 0;
44 /* Find out what moves policy plays most in this situation */
45 for (int i = 0; i < r->runs; i++) {
46 struct board b2;
47 board_copy(&b2, b);
49 if (DEBUGL(4)) fprintf(stderr, "---------------------------------\n");
50 coord_t c = play_random_move(&setup, &b2, color, r->playout);
51 if (DEBUGL(4)) fprintf(stderr, "-> %s\n", coord2sstr(c, &b2));
53 played[c]++;
54 if (played[c] > most_played) {
55 most_played++; m.coord = c;
58 board_done_noalloc(&b2);
61 *pmost_played = most_played;
62 return m.coord;
65 static coord_t *
66 replay_genmove(struct engine *e, struct board *b, struct time_info *ti, enum stone color, bool pass_all_alive)
68 struct replay *r = e->data;
69 struct move m = { .coord = pass, .color = color };
71 if (DEBUGL(3))
72 printf("genmove: %s to play. Sampling moves (%i runs)\n", stone2str(color), r->runs);
74 int played_[b->size2 + 2]; memset(played_, 0, sizeof(played_));
75 int *played = played_ + 2; // allow storing pass/resign
76 int most_played = 0;
77 m.coord = replay_sample_moves(e, b, color, played, &most_played);
79 if (DEBUGL(3)) { /* Show moves stats */
80 for (int k = most_played; k > 0; k--)
81 for (coord_t c = resign; c < b->size2; c++)
82 if (played[c] == k)
83 fprintf(stderr, "%3s: %.2f%%\n", coord2str(c, b), (float)k * 100 / r->runs);
84 fprintf(stderr, "\n");
87 if (DEBUGL(2))
88 fprintf(stderr, "genmove: %s %s %.2f%% (%i runs)\n\n",
89 (color == S_BLACK ? "B" : "W"),
90 coord2str(m.coord, b), (float)most_played * 100 / r->runs, r->runs);
92 if (r->no_suicide) { /* Check group suicides */
93 struct board b2; board_copy(&b2, b);
94 int res = board_play(&b2, &m); assert(res >= 0);
95 int suicide = !group_at(&b2, m.coord);
96 board_done_noalloc(&b2);
98 suicide_stats(suicide);
99 if (suicide) {
100 if (DEBUGL(2))
101 fprintf(stderr, "EEEK, group suicide, will pass instead !\n");
102 /* XXX: We should check for non-suicide alternatives. */
103 return coord_copy(pass);
107 return coord_copy(m.coord);
110 static void
111 replay_done(struct engine *e)
113 struct replay *r = e->data;
114 playout_policy_done(r->playout);
115 joseki_done(r->jdict);
118 struct replay *
119 replay_state_init(char *arg, struct board *b)
121 struct replay *r = calloc2(1, sizeof(struct replay));
123 r->debug_level = 1;
124 r->runs = 1000;
125 r->no_suicide = 0;
126 r->jdict = joseki_load(b->size);
128 if (arg) {
129 char *optspec, *next = arg;
130 while (*next) {
131 optspec = next;
132 next += strcspn(next, ",");
133 if (*next) { *next++ = 0; } else { *next = 0; }
135 char *optname = optspec;
136 char *optval = strchr(optspec, '=');
137 if (optval) *optval++ = 0;
139 if (!strcasecmp(optname, "debug")) {
140 if (optval)
141 r->debug_level = atoi(optval);
142 else
143 r->debug_level++;
144 } else if (!strcasecmp(optname, "runs") && optval) {
145 /* runs=n set number of playout runs to sample.
146 * use runs=1 for raw playout policy */
147 r->runs = atoi(optval);
148 } else if (!strcasecmp(optname, "no_suicide")) {
149 /* ensure engine doesn't allow group suicides
150 * (off by default) */
151 r->no_suicide = 1;
152 } else if (!strcasecmp(optname, "playout") && optval) {
153 char *playoutarg = strchr(optval, ':');
154 if (playoutarg)
155 *playoutarg++ = 0;
156 if (!strcasecmp(optval, "moggy")) {
157 r->playout = playout_moggy_init(playoutarg, b, r->jdict);
158 } else if (!strcasecmp(optval, "light")) {
159 r->playout = playout_light_init(playoutarg, b);
160 } else {
161 fprintf(stderr, "Replay: Invalid playout policy %s\n", optval);
163 } else {
164 fprintf(stderr, "Replay: Invalid engine argument %s or missing value\n", optname);
165 exit(1);
170 if (!r->playout)
171 r->playout = playout_moggy_init(NULL, b, r->jdict);
172 r->playout->debug_level = r->debug_level;
174 return r;
178 struct engine *
179 engine_replay_init(char *arg, struct board *b)
181 struct replay *r = replay_state_init(arg, b);
182 /* TODO engine_done(), free policy */
184 struct engine *e = calloc2(1, sizeof(struct engine));
185 e->name = "PlayoutReplay";
186 e->comment = "I select the most probable move from moggy playout policy";
187 e->genmove = replay_genmove;
188 e->done = replay_done;
189 e->data = r;
191 return e;