1 /* This is an example Pachi UCT plugin. */
2 /* This file is released under the same licence conditions as
5 /* We will add positive priors (1.0) for moves that play in-between
6 * of two different groups of the same color; that is, moves that connect
7 * two groups or the same color or separate two groups of the same color.
8 * This is not a very good prior actually, since it leads to a lot of
9 * useless moves. (Maybe doing this in simulations would be more interesting?)
10 * But it is a simple enough example. :-) */
12 /* Compile the plugin like this:
13 * gcc -Wall -O3 -march=native -Ipachi_source_root -shared -fPIC -o example.so example.c
14 * Then, load it in Pachi by passing plugin=example.so as a parameter.
15 * You can also pass it parameters: plugin=example.so:p1=v1:p2=v2.
16 * The module supports these parameters:
17 * eqex Number of prior'd simulations, overrides Pachi default
18 * selfatari If specified (selfatari or selfatari=1), test for selfatari
19 * before giving the prior
25 /* The basic plugin interface. */
26 #include "uct/plugin.h"
27 /* The tactical reading tools, for selfatari testing. */
28 #include "tactics/selfatari.h"
30 /* Our context structure. */
38 pachi_plugin_prior(void *data
, struct tree_node
*node
, struct prior_map
*map
, int eqex
)
40 struct context
*ctx
= data
;
41 struct board
*b
= map
->b
;
43 eqex
= ctx
->eqex
; // override Pachi default
45 /* foreach_free_point defines a variable @c corresponding
46 * to our current coordinate. */
47 foreach_free_point(map
->b
) {
48 if (!map
->consider
[c
])
51 /* We will look at the current point's 4-neighborhood;
52 * we are to set a prior if we spot two different
53 * groups of the same color. */
55 /* First, a shortcut: We keep track of numbers of neighboring
56 * stones. The | is not a typo. */
57 if ((neighbor_count_at(b
, c
, S_BLACK
) | neighbor_count_at(b
, c
, S_WHITE
)) <= 1)
60 /* Keep track of seen groups for each color; at each
61 * point, we will look only at groups with the same color. */
62 int groups
[S_MAX
] = {0, 0, 0, 0};
64 /* foreach_neighbor goes through all direct neighbors
65 * of a given coordinate defines also its own variable @c
66 * corresponding to the current coordinate. */
67 foreach_neighbor(b
, c
, {
68 enum stone s
= board_at(b
, c
); // color of stone
69 group_t g
= group_at(b
, c
); // id of a group
70 if (!g
) continue; // no group at this coord
73 /* First time we see a group of this color. */
78 /* We have already seen this group. */
81 /* We have already seen another group of this color!
82 * We can connect or split. */
85 /* If we reach this point, we have not seen any two groups
90 /* Check if our move here is not self-atari if the option
92 if (ctx
->selfatari
&& is_bad_selfatari(b
, map
->to_play
, c
))
95 /* Finally record the prior; value is 0.0 (avoid) to 1.0
96 * (strongly favor). eqex is the number of simulations
97 * the value is worth. */
98 add_prior_value(map
, c
, 1.0, eqex
);
99 } foreach_free_point_end
;
103 pachi_plugin_init(char *arg
, struct board
*b
, int seed
)
105 struct context
*ctx
= calloc(1, sizeof(*ctx
));
107 /* Initialize ctx defaults here. */
110 /* This is the canonical Pachi arguments parser. You do not strictly
111 * need to decypher it, you can just use it as a boilerplate. */
113 char *optspec
, *next
= arg
;
116 next
+= strcspn(next
, ":");
117 if (*next
) { *next
++ = 0; } else { *next
= 0; }
119 char *optname
= optspec
;
120 char *optval
= strchr(optspec
, '=');
121 if (optval
) *optval
++ = 0;
123 if (!strcasecmp(optname
, "eqex") && optval
) {
124 /* eqex takes a required integer argument */
125 ctx
->eqex
= atoi(optval
);
127 } else if (!strcasecmp(optname
, "selfatari")) {
128 /* selfatari takes an optional integer
130 ctx
->selfatari
= !optval
|| atoi(optval
);
133 fprintf(stderr
, "example plugin: Invalid argument %s or missing value\n", optname
);
139 /* Initialize the rest of ctx (depending on arguments) here. */
145 pachi_plugin_done(void *data
)
147 struct context
*ctx
= data
;