Next: Autohelpers and Constraints, Previous: Pattern Values, Up: Patterns
Helper functions can be provided to assist the matcher in deciding whether to accept a pattern, register move reasons, and setting various move values. The helper is supplied with the compiled pattern entry in the table, and the (absolute) position on the board of the `*' point.
One difficulty is that the helper must be able to cope with all the possible transformations of the pattern. To help with this, the OFFSET macro is used to transform relative pattern coordinates to absolute board locations.
The actual helper functions are in helpers.c. They are declared in patterns.h.
As an example to show how to write a helper function, we consider
a hypothetical helper called wedge_helper
. Such a helper
used to exist, but has been replaced by a constraint. Due to
its simplicity it's still a good example. The helper begins with a
comment:
/* ?O. ?Ob .X* aX* ?O. ?Oc :8,C,wedge_helper */
The image on the left is the actual pattern. On the right we've taken
this image and added letters to label apos
, bpos
, and
cpos
. The position of *, the point where GNU Go will move if the
pattern is adopted, is passed through the parameter move
.
int wedge_helper(ARGS) { int apos, bpos, cpos; int other = OTHER_COLOR(color); int success = 0; apos = OFFSET(0, -2); bpos = OFFSET(-1, 0); cpos = OFFSET(1, 0); if (TRYMOVE(move, color)) { if (TRYMOVE(apos, other)) { if (board[apos] == EMPTY || attack(apos, NULL)) success = 1; else if (TRYMOVE(bpos, color)) { if (!safe_move(cpos, other)) success = 1; popgo(); } popgo(); } popgo(); } return success; }
The OFFSET
lines tell GNU Go the positions of the three stones at
`a', `b', and `c'. To decide whether the pattern
guarantees a connection, we do some reading. First we use the
TRYMOVE
macro to place an `O' at `move' and let
`X' draw back to `a'. Then we ask whether `O' can capture
these stones by calling attack()
. The test if there is a stone at
`a' before calling attack()
is in this position not really
necessary but it's good practice to do so, because if the attacked stone
should happen to already have been captured while placing stones, GNU Go
would crash with an assertion failure.
If this attack fails we let `O' connect at `b' and use the
safe_move()
function to examine whether a cut by `X' at
`c' could be immediately captured. Before we return the result we
need to remove the stones we placed from the reading stack. This is done
with the function popgo()
.