From 0f55030479f1abb26088580950ed7b28a7d8e1df Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Sun, 20 Feb 2011 20:48:23 +0100 Subject: [PATCH] Moggy: Play the proper atari in case we can catch a group in ladder --- playout/moggy.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- tactics/ladder.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tactics/ladder.h | 4 ++++ 3 files changed, 109 insertions(+), 3 deletions(-) diff --git a/playout/moggy.c b/playout/moggy.c index ce27cd8..9bfc98c 100644 --- a/playout/moggy.c +++ b/playout/moggy.c @@ -41,6 +41,7 @@ enum mq_tag { MQ_KO = 0, MQ_LATARI, MQ_L2LIB, +#define MQ_LADDER MQ_L2LIB /* XXX: We want to fit in char still! */ MQ_LNLIB, MQ_PAT3, MQ_GATARI, @@ -53,7 +54,7 @@ enum mq_tag { /* Note that the context can be shared by multiple threads! */ struct moggy_policy { - unsigned int lcapturerate, atarirate, nlibrate, capturerate, patternrate, korate, josekirate, nakaderate; + unsigned int lcapturerate, atarirate, nlibrate, ladderrate, capturerate, patternrate, korate, josekirate, nakaderate; unsigned int selfatarirate, alwaysccaprate; unsigned int fillboardtries; int koage; @@ -288,6 +289,26 @@ local_atari_check(struct playout_policy *p, struct board *b, struct move *m, str static void +local_ladder_check(struct playout_policy *p, struct board *b, struct move *m, struct move_queue *q) +{ + group_t group = group_at(b, m->coord); + + if (board_group_info(b, group).libs != 2) + return; + + for (int i = 0; i < 2; i++) { + coord_t chase = board_group_info(b, group).lib[i]; + coord_t escape = board_group_info(b, group).lib[1 - i]; + if (wouldbe_ladder(b, escape, chase, board_at(b, group))) + mq_add(q, chase, 1<moves > 0 && PLDEBUGL(5)) + mq_print(q, b, "Ladder"); +} + + +static void local_2lib_check(struct playout_policy *p, struct board *b, struct move *m, struct move_queue *q) { struct moggy_policy *pp = p->data; @@ -451,6 +472,14 @@ playout_moggy_seqchoose(struct playout_policy *p, struct playout_setup *s, struc return mq_pick(&q); } + /* Local group trying to escape ladder? */ + if (pp->ladderrate > fast_random(100)) { + struct move_queue q; q.moves = 0; + local_ladder_check(p, b, &b->last_move, &q); + if (q.moves > 0) + return mq_pick(&q); + } + /* Local group can be PUT in atari? */ if (pp->atarirate > fast_random(100)) { struct move_queue q; q.moves = 0; @@ -586,6 +615,9 @@ playout_moggy_fullchoose(struct playout_policy *p, struct playout_setup *s, stru /* Local group in atari? */ local_atari_check(p, b, &b->last_move, &q); + /* Local group trying to escape ladder? */ + local_ladder_check(p, b, &b->last_move, &q); + /* Local group can be PUT in atari? */ local_2lib_check(p, b, &b->last_move, &q); @@ -660,6 +692,22 @@ playout_moggy_assess_group(struct playout_policy *p, struct prior_map *map, grou } if (board_group_info(b, g).libs == 2) { + if (pp->ladderrate) { + /* Make sure to play the correct liberty in case + * this is a group that can be caught in a ladder. */ + bool ladderable = false; + for (int i = 0; i < 2; i++) { + coord_t chase = board_group_info(b, g).lib[i]; + coord_t escape = board_group_info(b, g).lib[1 - i]; + if (wouldbe_ladder(b, escape, chase, board_at(b, g))) { + add_prior_value(map, chase, 1, games); + ladderable = true; + } + } + if (ladderable) + return; // do not suggest the other lib at all + } + if (!pp->atarirate) return; group_2lib_check(b, g, map->to_play, &q, 0, pp->atari_miaisafe, pp->atari_def_no_hopeless); @@ -823,8 +871,8 @@ playout_moggy_init(char *arg, struct board *b, struct joseki_dict *jdict) * XXX: no 9x9 tuning has been done recently. */ int rate = board_large(b) ? 80 : 90; - pp->lcapturerate = pp->atarirate = pp->nlibrate = pp->patternrate - = pp->selfatarirate = pp->josekirate = -1U; + pp->lcapturerate = pp->ladderrate = pp->atarirate = pp->nlibrate + = pp->patternrate = pp->selfatarirate = pp->josekirate = -1U; if (board_large(b)) { pp->lcapturerate = 90; pp->patternrate = 100; @@ -866,6 +914,8 @@ playout_moggy_init(char *arg, struct board *b, struct joseki_dict *jdict) p->debug_level = atoi(optval); } else if (!strcasecmp(optname, "lcapturerate") && optval) { pp->lcapturerate = atoi(optval); + } else if (!strcasecmp(optname, "ladderrate") && optval) { + pp->ladderrate = atoi(optval); } else if (!strcasecmp(optname, "atarirate") && optval) { pp->atarirate = atoi(optval); } else if (!strcasecmp(optname, "nlibrate") && optval) { diff --git a/tactics/ladder.c b/tactics/ladder.c index 04b0fe1..48f0a76 100644 --- a/tactics/ladder.c +++ b/tactics/ladder.c @@ -181,3 +181,55 @@ is_middle_ladder(struct board *b, coord_t coord, enum stone lcolor) return middle_ladder_walk(b, lcolor, x, y, xd, yd); } + +bool +wouldbe_ladder(struct board *b, coord_t escapelib, coord_t chaselib, enum stone lcolor) +{ + if (DEBUGL(6)) + fprintf(stderr, "would-be ladder check - does %s %s play out chasing move %s?\n", + stone2str(lcolor), coord2sstr(escapelib, b), coord2sstr(chaselib, b)); + + if (!coord_is_8adjecent(escapelib, chaselib, b)) { + if (DEBUGL(5)) + fprintf(stderr, "cannot determine ladder for remote simulated stone\n"); + return false; + } + + if (neighbor_count_at(b, chaselib, lcolor) != 1 || immediate_liberty_count(b, chaselib) != 2) { + if (DEBUGL(5)) + fprintf(stderr, "overly trivial for a ladder\n"); + return false; + } + + int x = coord_x(escapelib, b), y = coord_y(escapelib, b); + int cx = coord_x(chaselib, b), cy = coord_y(chaselib, b); + + /* Figure out the ladder direction */ + int xd, yd; + xd = board_atxy(b, x + 1, y) == S_NONE ? 1 : board_atxy(b, x - 1, y) == S_NONE ? -1 : 0; + yd = board_atxy(b, x, y + 1) == S_NONE ? 1 : board_atxy(b, x, y - 1) == S_NONE ? -1 : 0; + + if (board_atxy(b, x + 1, y) == board_atxy(b, x - 1, y) + || board_atxy(b, x, y + 1) == board_atxy(b, x, y - 1)) { + if (DEBUGL(5)) + fprintf(stderr, "no ladder, distorted space\n"); + return false; + } + + /* The ladder may be + * . c . . e X + * e O X or c O X + * X X X . X X */ + bool horiz_first = cx + xd == x; + bool vert_first = cy + yd == y; + //fprintf(stderr, "esc %d,%d chase %d,%d xd %d yd %d\n", x,y, cx,cy, xd, yd); + if (horiz_first == vert_first) { + /* TODO: In case of basic non-simple ladder, play out both variants. */ + if (DEBUGL(5)) + fprintf(stderr, "non-simple ladder\n"); + return false; + } + + /* We skip the atari check, obviously. */ + return middle_ladder_walk(b, lcolor, x, y, xd, yd); +} diff --git a/tactics/ladder.h b/tactics/ladder.h index d97a628..fce1205 100644 --- a/tactics/ladder.h +++ b/tactics/ladder.h @@ -12,6 +12,10 @@ * ladders and trivial middle-board ladders. */ static bool is_ladder(struct board *b, coord_t coord, group_t laddered); +/* Check if a 2-lib group of color @lcolor escaping at @escapelib would be + * caught in a ladder given opponent stone at @chaselib. */ +bool wouldbe_ladder(struct board *b, coord_t escapelib, coord_t chaselib, enum stone lcolor); + bool is_border_ladder(struct board *b, coord_t coord, enum stone lcolor); bool is_middle_ladder(struct board *b, coord_t coord, enum stone lcolor); -- 2.11.4.GIT