pachi_py/pachi/uct/plugin/example.c (73 lines of code) (raw):

/* This is an example Pachi UCT plugin. */ /* This file is released under the same licence conditions as * <uct/plugin.h>. */ /* We will add positive priors (1.0) for moves that play in-between * of two different groups of the same color; that is, moves that connect * two groups or the same color or separate two groups of the same color. * This is not a very good prior actually, since it leads to a lot of * useless moves. (Maybe doing this in simulations would be more interesting?) * But it is a simple enough example. :-) */ /* Compile the plugin like this: * gcc -Wall -O3 -march=native -Ipachi_source_root -shared -fPIC -o example.so example.c * Then, load it in Pachi by passing plugin=example.so as a parameter. * You can also pass it parameters: plugin=example.so:p1=v1:p2=v2. * The module supports these parameters: * eqex Number of prior'd simulations, overrides Pachi default * selfatari If specified (selfatari or selfatari=1), test for selfatari * before giving the prior */ #include <stdio.h> #include <stdlib.h> /* The basic plugin interface. */ #include "uct/plugin.h" /* The tactical reading tools, for selfatari testing. */ #include "tactics/selfatari.h" /* Our context structure. */ struct context { int eqex; bool selfatari; }; void pachi_plugin_prior(void *data, struct tree_node *node, struct prior_map *map, int eqex) { struct context *ctx = data; struct board *b = map->b; if (ctx->eqex >= 0) eqex = ctx->eqex; // override Pachi default /* foreach_free_point defines a variable @c corresponding * to our current coordinate. */ foreach_free_point(map->b) { if (!map->consider[c]) continue; /* We will look at the current point's 4-neighborhood; * we are to set a prior if we spot two different * groups of the same color. */ /* First, a shortcut: We keep track of numbers of neighboring * stones. The | is not a typo. */ if ((neighbor_count_at(b, c, S_BLACK) | neighbor_count_at(b, c, S_WHITE)) <= 1) continue; /* Keep track of seen groups for each color; at each * point, we will look only at groups with the same color. */ int groups[S_MAX] = {0, 0, 0, 0}; /* foreach_neighbor goes through all direct neighbors * of a given coordinate defines also its own variable @c * corresponding to the current coordinate. */ foreach_neighbor(b, c, { enum stone s = board_at(b, c); // color of stone group_t g = group_at(b, c); // id of a group if (!g) continue; // no group at this coord if (!groups[s]) { /* First time we see a group of this color. */ groups[s] = g; continue; } if (groups[s] == g) { /* We have already seen this group. */ continue; } /* We have already seen another group of this color! * We can connect or split. */ goto set_prior; }); /* If we reach this point, we have not seen any two groups * to connect. */ continue; set_prior: /* Check if our move here is not self-atari if the option * is enabled. */ if (ctx->selfatari && is_bad_selfatari(b, map->to_play, c)) continue; /* Finally record the prior; value is 0.0 (avoid) to 1.0 * (strongly favor). eqex is the number of simulations * the value is worth. */ add_prior_value(map, c, 1.0, eqex); } foreach_free_point_end; } void * pachi_plugin_init(char *arg, struct board *b, int seed) { struct context *ctx = calloc(1, sizeof(*ctx)); /* Initialize ctx defaults here. */ ctx->eqex = -1; /* This is the canonical Pachi arguments parser. You do not strictly * need to decypher it, you can just use it as a boilerplate. */ if (arg) { char *optspec, *next = arg; while (*next) { optspec = next; next += strcspn(next, ":"); if (*next) { *next++ = 0; } else { *next = 0; } char *optname = optspec; char *optval = strchr(optspec, '='); if (optval) *optval++ = 0; if (!strcasecmp(optname, "eqex") && optval) { /* eqex takes a required integer argument */ ctx->eqex = atoi(optval); } else if (!strcasecmp(optname, "selfatari")) { /* selfatari takes an optional integer * argument */ ctx->selfatari = !optval || atoi(optval); } else { fprintf(stderr, "example plugin: Invalid argument %s or missing value\n", optname); exit(1); } } } /* Initialize the rest of ctx (depending on arguments) here. */ return ctx; } void pachi_plugin_done(void *data) { struct context *ctx = data; /* No big magic. */ free(ctx); }