Merge branch 'master' of git+ssh://repo.or.cz/srv/git/pachi
[pachi/json.git] / playout / moggy.c
blob1d3ee9be36a87b187b1eb43e43e72dd88813304c
1 #include <assert.h>
2 #include <math.h>
3 #include <stdio.h>
4 #include <stdlib.h>
6 #define DEBUG
7 #include "board.h"
8 #include "debug.h"
9 #include "playout.h"
10 #include "playout/moggy.h"
11 #include "random.h"
13 #define PLDEBUGL(n) DEBUGL_(p->debug_level, n)
16 struct moggy_policy {
17 bool ladders, ladderassess, borderladders;
18 int lcapturerate, capturerate, patternrate;
19 int selfatarirate;
22 #define MQL 64
23 struct move_queue {
24 int moves;
25 coord_t move[MQL];
28 static void
29 mq_nodup(struct move_queue *q)
31 if ((q->moves > 1 && q->move[q->moves - 2] == q->move[q->moves - 1])
32 || (q->moves > 2 && q->move[q->moves - 3] == q->move[q->moves - 1])
33 || (q->moves > 3 && q->move[q->moves - 4] == q->move[q->moves - 1]))
34 q->moves--;
38 /* Pattern encoding:
39 * X: black; O: white; .: empty; #: edge
40 * x: !black; o: !white; ?: any
42 * extra X: pattern valid only for one side;
43 * middle point ignored. */
45 static char moggy_patterns_src[][11] = {
46 /* hane pattern - enclosing hane */
47 "XOX"
48 "..."
49 "???",
50 /* hane pattern - non-cutting hane */
51 "XO."
52 "..."
53 "?.?",
54 /* hane pattern - magari */
55 "XO?"
56 "X.."
57 "x.?",
58 /* hane pattern - thin hane */
59 "XOO"
60 "..."
61 "?.?" "X",
62 /* generic pattern - katatsuke or diagonal attachment; similar to magari */
63 ".O."
64 "X.."
65 "...",
66 /* cut1 pattern (kiri) - unprotected cut */
67 "XO?"
68 "O.o"
69 "?o?",
70 /* cut1 pattern (kiri) - peeped cut */
71 "XO?"
72 "O.X"
73 "???",
74 /* cut2 pattern (de) */
75 "?X?"
76 "O.O"
77 "ooo",
78 /* cut keima (not in Mogo) */
79 "OX?"
80 "o.O"
81 "o??",
82 /* side pattern - chase */
83 "X.?"
84 "O.?"
85 "##?",
86 /* side pattern - weirdness (SUSPICIOUS) */
87 "?X?"
88 "X.O"
89 "###",
90 /* side pattern - sagari (SUSPICIOUS) */
91 "?XO"
92 "x.x" /* Mogo has "x.?" */
93 "###" /* Mogo has "X" */,
94 /* side pattern - weirdcut (SUSPICIOUS) */
95 #if 0
96 "?OX"
97 "?.O"
98 "?##" "X",
99 #endif
100 /* side pattern - cut (SUSPICIOUS) */
101 "?OX"
102 "X.O"
103 "###" /* Mogo has "X" */,
105 #define moggy_patterns_src_n sizeof(moggy_patterns_src) / sizeof(moggy_patterns_src[0])
107 /* Hashtable: 2*8 bits (ignore middle point, 2 bits per intersection) */
108 /* Value: 0: no pattern, 1: black pattern, 2: white pattern, 3: both patterns */
109 static char moggy_patterns[65536];
111 static void
112 _record_pattern(char *table, char *str, int pat, int fixed_color)
114 /* Original color assignment */
115 table[pat] = fixed_color ? fixed_color : 3;
116 //fprintf(stderr, "[%s] %04x %d\n", str, pat, fixed_color);
118 /* Reverse color assignment - achieved by swapping odd and even bits */
119 pat = ((pat >> 1) & 0x5555) | ((pat & 0x5555) << 1);
120 table[pat] = fixed_color ? 2 - (fixed_color == 2) : 3;
121 //fprintf(stderr, "[%s] %04x %d\n", str, pat, fixed_color);
124 static int
125 _pat_vmirror(int pat)
127 /* V mirror pattern; reverse order of 3-2-3 chunks */
128 return ((pat & 0xfc00) >> 10) | (pat & 0x03c0) | ((pat & 0x003f) << 10);
131 static int
132 _pat_hmirror(int pat)
134 /* H mirror pattern; reverse order of 2-bit values within the chunks */
135 #define rev3(p) ((p >> 4) | (p & 0xc) | ((p & 0x3) << 4))
136 #define rev2(p) ((p >> 2) | ((p & 0x3) << 2))
137 return (rev3((pat & 0xfc00) >> 10) << 10)
138 | (rev2((pat & 0x03c0) >> 6) << 6)
139 | rev3((pat & 0x003f));
140 #undef rev3
141 #undef rev2
144 static int
145 _pat_90rot(int pat)
147 /* Rotate by 90 degrees:
148 * 5 6 7 7 4 2
149 * 3 4 -> 6 1
150 * 0 1 2 5 3 0 */
151 /* I'm too lazy to optimize this :) */
152 int vals[8];
153 for (int i = 0; i < 8; i++)
154 vals[i] = (pat >> (i * 2)) & 0x3;
155 int vals2[8];
156 vals2[0] = vals[5]; vals2[1] = vals[3]; vals2[2] = vals[0];
157 vals2[3] = vals[6]; vals2[4] = vals[1];
158 vals2[5] = vals[7]; vals2[6] = vals[4]; vals2[7] = vals[2];
159 int p2 = 0;
160 for (int i = 0; i < 8; i++)
161 p2 |= vals2[i] << (i * 2);
162 return p2;
165 static void
166 _gen_pattern(char *table, int pat, char *src, int srclen, int fixed_color)
168 for (; srclen > 0; src++, srclen--) {
169 if (srclen == 5)
170 continue;
171 int patofs = (srclen > 5 ? srclen - 1 : srclen) - 1;
172 switch (*src) {
173 case '?':
174 *src = '.'; _gen_pattern(table, pat, src, srclen, fixed_color);
175 *src = 'X'; _gen_pattern(table, pat, src, srclen, fixed_color);
176 *src = 'O'; _gen_pattern(table, pat, src, srclen, fixed_color);
177 *src = '#'; _gen_pattern(table, pat, src, srclen, fixed_color);
178 *src = '?'; // for future recursions
179 return;
180 case 'x':
181 *src = '.'; _gen_pattern(table, pat, src, srclen, fixed_color);
182 *src = 'O'; _gen_pattern(table, pat, src, srclen, fixed_color);
183 *src = '#'; _gen_pattern(table, pat, src, srclen, fixed_color);
184 *src = 'x'; // for future recursions
185 return;
186 case 'o':
187 *src = '.'; _gen_pattern(table, pat, src, srclen, fixed_color);
188 *src = 'X'; _gen_pattern(table, pat, src, srclen, fixed_color);
189 *src = '#'; _gen_pattern(table, pat, src, srclen, fixed_color);
190 *src = 'o'; // for future recursions
191 return;
192 case '.': /* 0 */ break;
193 case 'X': pat |= S_BLACK << (patofs * 2); break;
194 case 'O': pat |= S_WHITE << (patofs * 2); break;
195 case '#': pat |= S_OFFBOARD << (patofs * 2); break;
199 /* Original pattern, all transpositions and rotations */
200 _record_pattern(table, src - 9, pat, fixed_color);
201 _record_pattern(table, src - 9, _pat_vmirror(pat), fixed_color);
202 _record_pattern(table, src - 9, _pat_hmirror(pat), fixed_color);
203 _record_pattern(table, src - 9, _pat_vmirror(_pat_hmirror(pat)), fixed_color);
204 _record_pattern(table, src - 9, _pat_90rot(pat), fixed_color);
205 _record_pattern(table, src - 9, _pat_90rot(_pat_vmirror(pat)), fixed_color);
206 _record_pattern(table, src - 9, _pat_90rot(_pat_hmirror(pat)), fixed_color);
207 _record_pattern(table, src - 9, _pat_90rot(_pat_vmirror(_pat_hmirror(pat))), fixed_color);
210 #warning gcc is stupid; ignore following out-of-bounds warnings
212 static void
213 _gen_patterns(char src[][11], int src_n)
215 for (int i = 0; i < src_n; i++) {
216 //printf("<%s>\n", src[i]);
217 int fixed_color = 0;
218 switch (src[i][9]) {
219 case 'X': fixed_color = S_BLACK; break;
220 case 'O': fixed_color = S_WHITE; break;
222 //fprintf(stderr, "** %s **\n", src[i]);
223 _gen_pattern(moggy_patterns, 0, src[i], 9, fixed_color);
227 static bool
228 _load_patterns(char src[][11], int src_n, char *filename)
230 FILE *f = fopen("moggy.patterns", "r");
231 if (!f) return false;
233 int i;
234 for (i = 0; i < moggy_patterns_src_n; i++) {
235 char line[32];
236 if (!fgets(line, sizeof(line), f))
237 goto error;
238 int l = strlen(line);
239 if (l != 10 + (line[l - 1] == '\n'))
240 goto error;
241 memcpy(src[i], line, 10);
243 fprintf(stderr, "moggy.patterns: %d patterns loaded\n", i);
244 fclose(f);
245 return true;
246 error:
247 fprintf(stderr, "Error loading moggy.patterns.\n");
248 fclose(f);
249 return false;
252 static void __attribute__((constructor))
253 _init_patterns(void)
255 /* Replaces default patterns if the file is found, no-op otherwise. */
256 _load_patterns(moggy_patterns_src, moggy_patterns_src_n, "moggy.patterns");
258 _gen_patterns(moggy_patterns_src, moggy_patterns_src_n);
262 /* Check if we match any pattern centered on given move. */
263 static bool
264 test_pattern_here(struct playout_policy *p, char *hashtable,
265 struct board *b, struct move *m)
267 int pat = 0;
268 int x = coord_x(m->coord, b), y = coord_y(m->coord, b);
269 pat |= (board_atxy(b, x - 1, y - 1) << 14)
270 | (board_atxy(b, x, y - 1) << 12)
271 | (board_atxy(b, x + 1, y - 1) << 10);
272 pat |= (board_atxy(b, x - 1, y) << 8)
273 | (board_atxy(b, x + 1, y) << 6);
274 pat |= (board_atxy(b, x - 1, y + 1) << 4)
275 | (board_atxy(b, x, y + 1) << 2)
276 | (board_atxy(b, x + 1, y + 1));
277 //fprintf(stderr, "(%d,%d) hashtable[%04x] = %d\n", x, y, pat, hashtable[pat]);
278 return (hashtable[pat] & m->color) && !is_selfatari(b, m->color, m->coord);
281 static void
282 apply_pattern_here(struct playout_policy *p, char *hashtable,
283 struct board *b, struct move *m, struct move_queue *q)
285 if (test_pattern_here(p, hashtable, b, m))
286 q->move[q->moves++] = m->coord;
289 /* Check if we match any pattern around given move (with the other color to play). */
290 static coord_t
291 apply_pattern(struct playout_policy *p, struct board *b, struct move *m)
293 //struct moggy_policy *pp = p->data;
294 struct move_queue q;
295 q.moves = 0;
297 /* Suicides do not make any patterns and confuse us. */
298 if (board_at(b, m->coord) == S_NONE || board_at(b, m->coord) == S_OFFBOARD)
299 return pass;
301 foreach_neighbor(b, m->coord, {
302 struct move m2; m2.coord = c; m2.color = stone_other(m->color);
303 if (board_at(b, c) == S_NONE)
304 apply_pattern_here(p, moggy_patterns, b, &m2, &q);
306 foreach_diag_neighbor(b, m->coord) {
307 struct move m2; m2.coord = c; m2.color = stone_other(m->color);
308 if (board_at(b, c) == S_NONE)
309 apply_pattern_here(p, moggy_patterns, b, &m2, &q);
310 } foreach_diag_neighbor_end;
312 if (PLDEBUGL(5)) {
313 fprintf(stderr, "Pattern candidate moves: ");
314 for (int i = 0; i < q.moves; i++) {
315 fprintf(stderr, "%s ", coord2sstr(q.move[i], b));
317 fprintf(stderr, "\n");
320 int i = fast_random(q.moves);
321 return q.moves ? q.move[i] : pass;
326 /* Is this ladder breaker friendly for the one who catches ladder. */
327 static bool
328 ladder_catcher(struct board *b, int x, int y, enum stone laddered)
330 enum stone breaker = board_atxy(b, x, y);
331 return breaker == stone_other(laddered) || breaker == S_OFFBOARD;
334 static bool
335 ladder_catches(struct playout_policy *p, struct board *b, coord_t coord, group_t laddered)
337 struct moggy_policy *pp = p->data;
339 /* This is very trivial and gets a lot of corner cases wrong.
340 * We need this to be just very fast. One important point is
341 * that we sometimes might not notice a ladder but if we do,
342 * it should always work; thus we can use this for strong
343 * negative hinting safely. */
344 //fprintf(stderr, "ladder check\n");
346 enum stone lcolor = board_at(b, group_base(laddered));
347 int x = coord_x(coord, b), y = coord_y(coord, b);
349 /* First, special-case first-line "ladders". This is a huge chunk
350 * of ladders we actually meet and want to play. */
351 if (pp->borderladders
352 && neighbor_count_at(b, coord, S_OFFBOARD) == 1
353 && neighbor_count_at(b, coord, lcolor) == 1) {
354 if (PLDEBUGL(5))
355 fprintf(stderr, "border ladder\n");
356 /* Direction along border; xd is horiz. border, yd vertical. */
357 int xd = 0, yd = 0;
358 if (board_atxy(b, x + 1, y) == S_OFFBOARD || board_atxy(b, x - 1, y) == S_OFFBOARD)
359 yd = 1;
360 else
361 xd = 1;
362 /* Direction from the border; -1 is above/left, 1 is below/right. */
363 int dd = (board_atxy(b, x + yd, y + xd) == S_OFFBOARD) ? 1 : -1;
364 if (PLDEBUGL(6))
365 fprintf(stderr, "xd %d yd %d dd %d\n", xd, yd, dd);
366 /* | ? ?
367 * | . O #
368 * | c X #
369 * | . O #
370 * | ? ? */
371 /* This is normally caught, unless we have friends both above
372 * and below... */
373 if (board_atxy(b, x + xd * 2, y + yd * 2) == lcolor
374 && board_atxy(b, x - xd * 2, y - yd * 2) == lcolor)
375 return false;
376 /* ...or can't block where we need because of shortage
377 * of liberties. */
378 int libs1 = board_group_info(b, group_atxy(b, x + xd - yd * dd, y + yd - xd * dd)).libs;
379 int libs2 = board_group_info(b, group_atxy(b, x - xd - yd * dd, y - yd - xd * dd)).libs;
380 if (PLDEBUGL(6))
381 fprintf(stderr, "libs1 %d libs2 %d\n", libs1, libs2);
382 if (libs1 < 2 && libs2 < 2)
383 return false;
384 if (board_atxy(b, x + xd * 2, y + yd * 2) == lcolor && libs1 < 3)
385 return false;
386 if (board_atxy(b, x - xd * 2, y - yd * 2) == lcolor && libs2 < 3)
387 return false;
388 return true;
391 /* Figure out the ladder direction */
392 int xd, yd;
393 xd = board_atxy(b, x + 1, y) == S_NONE ? 1 : board_atxy(b, x - 1, y) == S_NONE ? -1 : 0;
394 yd = board_atxy(b, x, y + 1) == S_NONE ? 1 : board_atxy(b, x, y - 1) == S_NONE ? -1 : 0;
396 /* We do only tight ladders, not loose ladders. Furthermore,
397 * the ladders need to be simple:
398 * . X . . . X
399 * c O X supported . c O unsupported
400 * X # # X O #
403 /* For given (xd,yd), we have two possibilities where to move
404 * next. Consider (-1,1):
405 * n X . n c X
406 * c O X X O #
407 * X # # . X #
409 if (!xd || !yd || !(ladder_catcher(b, x - xd, y, lcolor) ^ ladder_catcher(b, x, y - yd, lcolor))) {
410 /* Silly situation, probably non-simple ladder or suicide. */
411 /* TODO: In case of basic non-simple ladder, play out both variants. */
412 if (PLDEBUGL(5))
413 fprintf(stderr, "non-simple ladder\n");
414 return false;
417 #define ladder_check(xd1_, yd1_, xd2_, yd2_) \
418 if (board_atxy(b, x, y) != S_NONE) { \
419 /* Did we hit a stone when playing out ladder? */ \
420 if (ladder_catcher(b, x, y, lcolor)) \
421 return true; /* ladder works */ \
422 if (board_group_info(b, group_atxy(b, x, y)).lib[0] > 0) \
423 return false; /* friend that's not in atari himself */ \
424 } else { \
425 /* No. So we are at new position. \
426 * We need to check indirect ladder breakers. */ \
427 /* . 2 x . . \
428 * . x o O 1 <- only at O we can check for o at 2 \
429 * x o o x . otherwise x at O would be still deadly \
430 * o o x . . \
431 * We check for o and x at 1, these are vital. \
432 * We check only for o at 2; x at 2 would mean we \
433 * need to fork (one step earlier). */ \
434 enum stone s1 = board_atxy(b, x + (xd1_), y + (yd1_)); \
435 if (s1 == lcolor) return false; \
436 if (s1 == stone_other(lcolor)) return true; \
437 enum stone s2 = board_atxy(b, x + (xd2_), y + (yd2_)); \
438 if (s2 == lcolor) return false; \
440 #define ladder_horiz do { if (PLDEBUGL(6)) fprintf(stderr, "%d,%d horiz step %d\n", x, y, xd); x += xd; ladder_check(xd, 0, -2 * xd, yd); } while (0)
441 #define ladder_vert do { if (PLDEBUGL(6)) fprintf(stderr, "%d,%d vert step %d\n", x, y, yd); y += yd; ladder_check(0, yd, xd, -2 * yd); } while (0)
443 if (ladder_catcher(b, x - xd, y, lcolor))
444 ladder_horiz;
445 do {
446 ladder_vert;
447 ladder_horiz;
448 } while (1);
452 static void
453 group_atari_check(struct playout_policy *p, struct board *b, group_t group, struct move_queue *q)
455 struct moggy_policy *pp = p->data;
457 /* Do not bother with kos. */
458 if (group_is_onestone(b, group))
459 return;
461 enum stone color = board_at(b, group_base(group));
462 coord_t lib = board_group_info(b, group).lib[0];
464 assert(color != S_OFFBOARD && color != S_NONE);
465 if (PLDEBUGL(5))
466 fprintf(stderr, "atariiiiiiiii %s of color %d\n", coord2sstr(lib, b), color);
467 assert(board_at(b, lib) == S_NONE);
469 /* Can we capture some neighbor? */
470 foreach_in_group(b, group) {
471 foreach_neighbor(b, c, {
472 if (board_at(b, c) != stone_other(color)
473 || board_group_info(b, group_at(b, c)).libs > 1)
474 continue;
475 if (PLDEBUGL(6))
476 fprintf(stderr, "can capture group %d\n", group_at(b, c));
477 /* If we are saving our group, capture! */
478 if (b->last_move.color == stone_other(color))
479 q->move[q->moves++] = board_group_info(b, group_at(b, c)).lib[0];
480 else /* If we chase the group, capture it now! */
481 q->move[q->moves++] = lib;
482 /* Make sure capturing the group will actually
483 * expand our liberties if we are filling our
484 * last liberty. */
485 if (q->move[q->moves - 1] == lib && is_selfatari(b, color, lib))
486 q->moves--;
487 else
488 mq_nodup(q);
490 } foreach_in_group_end;
492 /* Do not suicide... */
493 if (is_selfatari(b, color, lib))
494 return;
495 if (PLDEBUGL(6))
496 fprintf(stderr, "...escape route valid\n");
498 /* ...or play out ladders. */
499 if (pp->ladders && ladder_catches(p, b, lib, group)) {
500 return;
502 if (PLDEBUGL(6))
503 fprintf(stderr, "...no ladder\n");
505 q->move[q->moves++] = lib;
506 mq_nodup(q);
509 static coord_t
510 global_atari_check(struct playout_policy *p, struct board *b)
512 struct move_queue q;
513 q.moves = 0;
515 if (b->clen == 0)
516 return pass;
518 int g_base = fast_random(b->clen);
519 for (int g = g_base; g < b->clen; g++) {
520 group_atari_check(p, b, group_at(b, group_base(b->c[g])), &q);
521 if (q.moves > 0)
522 return q.move[fast_random(q.moves)];
524 for (int g = 0; g < g_base; g++) {
525 group_atari_check(p, b, group_at(b, group_base(b->c[g])), &q);
526 if (q.moves > 0)
527 return q.move[fast_random(q.moves)];
529 return pass;
532 static coord_t
533 local_atari_check(struct playout_policy *p, struct board *b, struct move *m)
535 struct move_queue q;
536 q.moves = 0;
538 /* Did the opponent play a self-atari? */
539 if (board_group_info(b, group_at(b, m->coord)).libs == 1) {
540 group_atari_check(p, b, group_at(b, m->coord), &q);
543 foreach_neighbor(b, m->coord, {
544 group_t g = group_at(b, c);
545 if (!g || board_group_info(b, g).libs != 1)
546 continue;
547 group_atari_check(p, b, g, &q);
550 if (PLDEBUGL(5)) {
551 fprintf(stderr, "Local atari candidate moves: ");
552 for (int i = 0; i < q.moves; i++) {
553 fprintf(stderr, "%s ", coord2sstr(q.move[i], b));
555 fprintf(stderr, "\n");
558 int i = fast_random(q.moves);
559 return q.moves ? q.move[i] : pass;
562 coord_t
563 playout_moggy_choose(struct playout_policy *p, struct board *b, enum stone to_play)
565 struct moggy_policy *pp = p->data;
566 coord_t c;
568 if (PLDEBUGL(5))
569 board_print(b, stderr);
571 /* Local checks */
572 if (!is_pass(b->last_move.coord)) {
573 /* Local group in atari? */
574 if (pp->lcapturerate > fast_random(100)) {
575 c = local_atari_check(p, b, &b->last_move);
576 if (!is_pass(c))
577 return c;
580 /* Check for patterns we know */
581 if (pp->patternrate > fast_random(100)) {
582 c = apply_pattern(p, b, &b->last_move);
583 if (!is_pass(c))
584 return c;
588 /* Global checks */
590 /* Any groups in atari? */
591 if (pp->capturerate > fast_random(100)) {
592 c = global_atari_check(p, b);
593 if (!is_pass(c))
594 return c;
597 return pass;
600 float
601 playout_moggy_assess(struct playout_policy *p, struct board *b, struct move *m)
603 struct moggy_policy *pp = p->data;
605 if (is_pass(m->coord))
606 return NAN;
608 if (PLDEBUGL(5)) {
609 fprintf(stderr, "ASSESS of %s:\n", coord2sstr(m->coord, b));
610 board_print(b, stderr);
613 /* Are we dealing with atari? */
614 if (pp->lcapturerate || pp->capturerate) {
615 bool ladder = false;
617 foreach_neighbor(b, m->coord, {
618 group_t g = group_at(b, c);
619 if (!g || board_group_info(b, g).libs != 1)
620 continue;
622 /* _Never_ play here if this move plays out
623 * a caught ladder. (Unless it captures another
624 * group. :-) */
625 if (pp->ladderassess && ladder_catches(p, b, m->coord, g)) {
626 /* Note that the opposite is not guarded against;
627 * we do not advise against capturing a laddered
628 * group (but we don't encourage it either). Such
629 * a move can simplify tactical situations if we
630 * can afford it. */
631 if (m->color == board_at(b, c))
632 ladder = true;
633 continue;
636 struct move_queue q; q.moves = 0;
637 group_atari_check(p, b, g, &q);
638 while (q.moves--)
639 if (q.move[q.moves] == m->coord) {
640 if (PLDEBUGL(5))
641 fprintf(stderr, "1.0: atari\n");
642 return 1.0;
646 if (ladder) {
647 if (PLDEBUGL(5))
648 fprintf(stderr, "0.0: ladder\n");
649 return 0.0;
653 /* Pattern check */
654 if (pp->patternrate) {
655 if (test_pattern_here(p, moggy_patterns, b, m)) {
656 if (PLDEBUGL(5))
657 fprintf(stderr, "1.0: pattern\n");
658 return 1.0;
662 return NAN;
665 bool
666 playout_moggy_permit(struct playout_policy *p, struct board *b, struct move *m)
668 struct moggy_policy *pp = p->data;
670 /* The idea is simple for now - never allow self-atari moves.
671 * They suck in general, but this also permits us to actually
672 * handle seki in the playout stage. */
673 /* FIXME: We must allow self-atari in some basic nakade shapes. */
674 #if 0
675 if (is_selfatari(b, m->color, m->coord))
676 fprintf(stderr, "__ Prohibiting self-atari %s %s\n", stone2str(m->color), coord2sstr(m->coord, b));
677 #endif
678 return fast_random(100) >= pp->selfatarirate || !is_selfatari(b, m->color, m->coord);
682 struct playout_policy *
683 playout_moggy_init(char *arg)
685 struct playout_policy *p = calloc(1, sizeof(*p));
686 struct moggy_policy *pp = calloc(1, sizeof(*pp));
687 p->data = pp;
688 p->choose = playout_moggy_choose;
689 p->assess = playout_moggy_assess;
690 p->permit = playout_moggy_permit;
692 pp->lcapturerate = 90;
693 pp->capturerate = 90;
694 pp->patternrate = 90;
695 pp->selfatarirate = 90;
696 pp->ladders = pp->borderladders = true;
697 pp->ladderassess = true;
699 if (arg) {
700 char *optspec, *next = arg;
701 while (*next) {
702 optspec = next;
703 next += strcspn(next, ":");
704 if (*next) { *next++ = 0; } else { *next = 0; }
706 char *optname = optspec;
707 char *optval = strchr(optspec, '=');
708 if (optval) *optval++ = 0;
710 if (!strcasecmp(optname, "lcapturerate") && optval) {
711 pp->lcapturerate = atoi(optval);
712 } else if (!strcasecmp(optname, "capturerate") && optval) {
713 pp->capturerate = atoi(optval);
714 } else if (!strcasecmp(optname, "patternrate") && optval) {
715 pp->patternrate = atoi(optval);
716 } else if (!strcasecmp(optname, "selfatarirate") && optval) {
717 pp->selfatarirate = atoi(optval);
718 } else if (!strcasecmp(optname, "ladders")) {
719 pp->ladders = optval && *optval == '0' ? false : true;
720 } else if (!strcasecmp(optname, "borderladders")) {
721 pp->borderladders = optval && *optval == '0' ? false : true;
722 } else if (!strcasecmp(optname, "ladderassess")) {
723 pp->ladderassess = optval && *optval == '0' ? false : true;
724 } else {
725 fprintf(stderr, "playout-moggy: Invalid policy argument %s or missing value\n", optname);
730 return p;