Patternplay: New engine playing and evaluating according to pattern database
[pachi.git] / patternplay / patternplay.c
blobb4dfeff109b4beae2ea2da2b6ef6069470882186
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
5 #include "board.h"
6 #include "debug.h"
7 #include "engine.h"
8 #include "move.h"
9 #include "patternplay/patternplay.h"
10 #include "pattern.h"
11 #include "patternsp.h"
12 #include "patternprob.h"
13 #include "random.h"
16 /* Internal engine state. */
17 struct patternplay {
18 int debug_level;
20 struct pattern_config pc;
21 pattern_spec ps;
22 struct pattern_pdict *pd;
26 /* Evaluate patterns for all available moves. Stores found patterns
27 * to pats[b->flen] and normalized probability of each pattern (or NaN
28 * in case of no match) to probs[b->flen]. */
29 static void
30 rate_moves(struct pattern_config *pc, pattern_spec *ps, struct pattern_pdict *pd,
31 struct board *b, enum stone color,
32 struct pattern *pats, floating_t *probs)
34 /* First pass: Gather probabilities. */
35 floating_t total = 0;
36 for (int f = 0; f < b->flen; f++) {
37 probs[f] = NAN;
39 struct move mo = { .coord = b->f[f], .color = color };
40 if (is_pass(mo.coord))
41 continue;
42 if (!board_is_valid_move(b, &mo))
43 continue;
45 pattern_match(pc, *ps, &pats[f], b, &mo);
46 floating_t prob = pattern_prob(pd, &pats[f]);
47 if (!isnan(prob)) {
48 probs[f] = prob;
49 total += prob;
53 /* Second pass: Rescale. */
54 for (int f = 0; f < b->flen; f++) {
55 probs[f] /= total;
59 static coord_t *
60 patternplay_genmove(struct engine *e, struct board *b, struct time_info *ti, enum stone color, bool pass_all_alive)
62 struct patternplay *pp = e->data;
64 struct pattern pats[b->flen];
65 floating_t probs[b->flen];
66 rate_moves(&pp->pc, &pp->ps, pp->pd, b, color, pats, probs);
68 int best = 0;
69 for (int f = 0; f < b->flen; f++) {
70 if (pp->debug_level >= 5 && probs[f] > 0) {
71 char s[256]; pattern2str(s, &pats[f]);
72 fprintf(stderr, "\t%s: %.3f %s\n", coord2sstr(b->f[f], b), probs[f], s);
74 if (probs[f] > probs[best])
75 best = f;
78 return coord_copy(b->f[best]);
81 void
82 patternplay_evaluate(struct engine *e, struct board *b, struct time_info *ti, floating_t *vals, enum stone color)
84 struct patternplay *pp = e->data;
86 struct pattern pats[b->flen];
87 rate_moves(&pp->pc, &pp->ps, pp->pd, b, color, pats, vals);
89 if (pp->debug_level >= 4) {
90 for (int f = 0; f < b->flen; f++) {
91 if (vals[f] > 0) {
92 char s[256]; pattern2str(s, &pats[f]);
93 fprintf(stderr, "\t%s: %.3f %s\n", coord2sstr(b->f[f], b), vals[f], s);
100 struct patternplay *
101 patternplay_state_init(char *arg)
103 struct patternplay *pp = calloc2(1, sizeof(struct patternplay));
105 pp->debug_level = debug_level;
106 pp->pc = DEFAULT_PATTERN_CONFIG;
107 pp->pc.spat_dict = spatial_dict_init(false);
108 memcpy(&pp->ps, PATTERN_SPEC_MATCH_DEFAULT, sizeof(pattern_spec));
110 if (arg) {
111 char *optspec, *next = arg;
112 while (*next) {
113 optspec = next;
114 next += strcspn(next, ",");
115 if (*next) { *next++ = 0; } else { *next = 0; }
117 char *optname = optspec;
118 char *optval = strchr(optspec, '=');
119 if (optval) *optval++ = 0;
121 if (!strcasecmp(optname, "debug")) {
122 if (optval)
123 pp->debug_level = atoi(optval);
124 else
125 pp->debug_level++;
127 /* See pattern.h:pattern_config for description and
128 * pattern.c:DEFAULT_PATTERN_CONFIG for default values
129 * of the following options. */
130 } else if (!strcasecmp(optname, "bdist_max") && optval) {
131 pp->pc.bdist_max = atoi(optval);
132 } else if (!strcasecmp(optname, "spat_min") && optval) {
133 pp->pc.spat_min = atoi(optval);
134 } else if (!strcasecmp(optname, "spat_max") && optval) {
135 pp->pc.spat_max = atoi(optval);
136 } else if (!strcasecmp(optname, "spat_largest")) {
137 pp->pc.spat_largest = !optval || atoi(optval);
139 } else {
140 fprintf(stderr, "patternplay: Invalid engine argument %s or missing value\n", optname);
141 exit(EXIT_FAILURE);
146 pp->pd = pattern_pdict_init(NULL, &pp->pc);
148 return pp;
151 struct engine *
152 engine_patternplay_init(char *arg, struct board *b)
154 struct patternplay *pp = patternplay_state_init(arg);
155 struct engine *e = calloc2(1, sizeof(struct engine));
156 e->name = "PatternPlay Engine";
157 e->comment = "I select moves blindly according to learned patterns. I won't pass as long as there is a place on the board where I can play. When we both pass, I will consider all the stones on the board alive.";
158 e->genmove = patternplay_genmove;
159 e->evaluate = patternplay_evaluate;
160 e->data = pp;
162 return e;