Ejemplo n.º 1
0
static inline int
nakade_area(struct board *b, coord_t around, enum stone color, coord_t *area)
{
	/* First, examine the nakade area. For sure, it must be at most
	 * six points. And it must be within color group(s). */
#define NAKADE_MAX 6
	int area_n = 0;

	area[area_n++] = around;

	for (int i = 0; i < area_n; i++) {
		foreach_neighbor(b, area[i], {
			if (board_at(b, c) == stone_other(color))
				return -1;
			if (board_at(b, c) == S_NONE) {
				bool dup = false;
				for (int j = 0; j < area_n; j++)
					if (c == area[j]) {
						dup = true;
						break;
					}
				if (dup) continue;

				if (area_n >= NAKADE_MAX) {
					/* Too large nakade area. */
					return -1;
				}
				area[area_n++] = c;
			}
		});
	}
Ejemplo n.º 2
0
void
pattern_get(struct pattern_config *pc, struct pattern *p, struct board *b, struct move *m)
{
	p->n = 0;
	struct feature *f = &p->f[0];

	/* TODO: We should match pretty much all of these features
	 * incrementally. */

	/* FEAT_SPATIAL */
	/* TODO */
	assert(!pc->spat_max);

	/* FEAT_PASS */
	if (is_pass(m->coord)) {
		f->id = FEAT_PASS; f->payload = 0;
		f->payload |= (b->moves > 0 && is_pass(b->last_move.coord)) << PF_PASS_LASTPASS;
		p->n++;
		return;
	}

	/* FEAT_CAPTURE */
	{
		foreach_neighbor(b, m->coord, {
			if (board_at(b, c) != stone_other(m->color))
				continue;
			group_t g = group_at(b, c);
			if (!g || board_group_info(b, g).libs != 1)
				continue;

			/* Capture! */
			f->id = FEAT_CAPTURE; f->payload = 0;

			f->payload |= is_ladder(b, m->coord, g, true, true) << PF_CAPTURE_LADDER;
			/* TODO: is_ladder() is too conservative in some
			 * very obvious situations, look at complete.gtp. */

			/* TODO: PF_CAPTURE_RECAPTURE */

			foreach_in_group(b, g) {
				foreach_neighbor(b, c, {
					assert(board_at(b, c) != S_NONE || c == m->coord);
					if (board_at(b, c) != m->color)
						continue;
					group_t g = group_at(b, c);
					if (!g || board_group_info(b, g).libs != 1)
						continue;
					/* A neighboring group of ours is in atari. */
					f->payload |= 1 << PF_CAPTURE_ATARIDEF;
				});
			} foreach_in_group_end;

			if (group_is_onestone(b, g)
			    && neighbor_count_at(b, m->coord, stone_other(m->color))
			       + neighbor_count_at(b, m->coord, S_OFFBOARD) == 4)
				f->payload |= 1 << PF_CAPTURE_KO;

			(f++, p->n++);
		});
Ejemplo n.º 3
0
static void
board_init_data(struct board *board)
{
	int size = board_size(board);

	board_setup(board);
	board_resize(board, size - 2 /* S_OFFBOARD margin */);

	/* Setup neighborhood iterators */
	board->nei8[0] = -size - 1; // (-1,-1)
	board->nei8[1] = 1;
	board->nei8[2] = 1;
	board->nei8[3] = size - 2; // (-1,0)
	board->nei8[4] = 2;
	board->nei8[5] = size - 2; // (-1,1)
	board->nei8[6] = 1;
	board->nei8[7] = 1;
	board->dnei[0] = -size - 1;
	board->dnei[1] = 2;
	board->dnei[2] = size*2 - 2;
	board->dnei[3] = 2;

	/* Setup initial symmetry */
	if (size % 2) {
		board->symmetry.d = 1;
		board->symmetry.x1 = board->symmetry.y1 = board_size(board) / 2;
		board->symmetry.x2 = board->symmetry.y2 = board_size(board) - 1;
		board->symmetry.type = SYM_FULL;
	} else {
		/* TODO: We do not handle board symmetry on boards
		 * with no tengen yet. */
		board->symmetry.d = 0;
		board->symmetry.x1 = board->symmetry.y1 = 1;
		board->symmetry.x2 = board->symmetry.y2 = board_size(board) - 1;
		board->symmetry.type = SYM_NONE;
	}

	/* Set up coordinate cache */
	foreach_point(board) {
		board->coord[c][0] = c % board_size(board);
		board->coord[c][1] = c / board_size(board);
	} foreach_point_end;

	/* Draw the offboard margin */
	int top_row = board_size2(board) - board_size(board);
	int i;
	for (i = 0; i < board_size(board); i++)
		board->b[i] = board->b[top_row + i] = S_OFFBOARD;
	for (i = 0; i <= top_row; i += board_size(board))
		board->b[i] = board->b[board_size(board) - 1 + i] = S_OFFBOARD;

	foreach_point(board) {
		coord_t coord = c;
		if (board_at(board, coord) == S_OFFBOARD)
			continue;
		foreach_neighbor(board, c, {
			inc_neighbor_count_at(board, coord, board_at(board, c));
		} );
	} foreach_point_end;
Ejemplo n.º 4
0
Archivo: test.c Proyecto: mkghub/pachi
static void
pick_random_last_move(struct board *b, enum stone to_play)
{
	if (board_empty(b))
		return;
	
	int base = fast_random(board_size2(b));
	for (int i = base; i < base + board_size2(b); i++) {
		coord_t c = i % board_size2(b);
		if (board_at(b, c) == stone_other(to_play)) {
			b->last_move.coord = c;
			b->last_move.color = board_at(b, c);
			break;
		}
	}	
}
Ejemplo n.º 5
0
Archivo: test.c Proyecto: mkghub/pachi
static bool
test_sar(struct board *b, char *arg)
{
	enum stone color = str2stone(arg);
	arg += 2;
	coord_t *cc = str2coord(arg, board_size(b));
	coord_t c = *cc; coord_done(cc);
	arg += strcspn(arg, " ") + 1;
	int eres = atoi(arg);

	board_print_test(2, b);
	if (DEBUGL(1))
		printf("sar %s %s %d...\t", stone2str(color), coord2sstr(c, b), eres);

	assert(board_at(b, c) == S_NONE);
	int rres = is_bad_selfatari(b, color, c);

	if (rres == eres) {
		if (DEBUGL(1))
			printf("OK\n");
	} else {
		if (debug_level <= 2) {
			board_print_test(0, b);
			printf("sar %s %s %d...\t", stone2str(color), coord2sstr(c, b), eres);
		}
		printf("FAILED (%d)\n", rres);
	}
	return rres == eres;
}
Ejemplo n.º 6
0
Archivo: test.c Proyecto: mkghub/pachi
static bool
test_two_eyes(struct board *b, char *arg)
{
	coord_t c = str2scoord(arg, board_size(b));
	arg += strcspn(arg, " ") + 1;
	int eres = atoi(arg);

	board_print_test(2, b);
	if (DEBUGL(1))
		printf("two_eyes %s %d...\t", coord2sstr(c, b), eres);

	enum stone color = board_at(b, c);
	assert(color == S_BLACK || color == S_WHITE);
	int rres = dragon_is_safe(b, group_at(b, c), color);

	if (rres == eres) {
		if (DEBUGL(1))
			printf("OK\n");
	} else {
		if (debug_level <= 2) {
			board_print_test(0, b);
			printf("two_eyes %s %d...\t", coord2sstr(c, b), eres);
		}
		printf("FAILED (%d)\n", rres);
	}
	return rres == eres;
}
Ejemplo n.º 7
0
Archivo: test.c Proyecto: mkghub/pachi
static bool
test_can_countercapture(struct board *b, char *arg)
{
	coord_t c = str2scoord(arg, board_size(b));
	arg += strcspn(arg, " ") + 1;
	int eres = atoi(arg);

	board_print_test(2, b);
	if (DEBUGL(1))
		printf("can_countercap %s %d...\t", coord2sstr(c, b), eres);

	enum stone color = board_at(b, c);
	group_t g = group_at(b, c);
	assert(color == S_BLACK || color == S_WHITE);
	int rres = can_countercapture(b, g, NULL, 0);

	if (rres == eres) {
		if (DEBUGL(1))
			printf("OK\n");
	} else {
		if (debug_level <= 2) {
			board_print_test(0, b);
			printf("can_countercap %s %d...\t", coord2sstr(c, b), eres);
		}
		printf("FAILED (%d)\n", rres);
	}
	return rres == eres;
}
Ejemplo n.º 8
0
Archivo: test.c Proyecto: mkghub/pachi
static bool
test_useful_ladder(struct board *b, char *arg)
{
	enum stone color = str2stone(arg);
	arg += 2;
	coord_t *cc = str2coord(arg, board_size(b));
	coord_t c = *cc; coord_done(cc);
	arg += strcspn(arg, " ") + 1;
	int eres = atoi(arg);

	board_print_test(2, b);
	if (DEBUGL(1))
		printf("useful_ladder %s %s %d...\t", stone2str(color), coord2sstr(c, b), eres);
	
	assert(board_at(b, c) == S_NONE);
	group_t atari_neighbor = board_get_atari_neighbor(b, c, color);
	assert(atari_neighbor);
	int ladder = is_ladder(b, c, atari_neighbor, true);  assert(ladder);
	int rres = useful_ladder(b, atari_neighbor);
	
	if (rres == eres) {
		if (DEBUGL(1))
			printf("OK\n");
	} else {
		if (debug_level <= 2) {
			board_print_test(0, b);
			printf("useful_ladder %s %s %d...\t", stone2str(color), coord2sstr(c, b), eres);
		}
		printf("FAILED (%d)\n", rres);
	}

	return (rres == eres);
}
Ejemplo n.º 9
0
void
cfg_distances(struct board *b, coord_t start, int *distances, int maxdist)
{
	/* Queue for d+1 spots; no two spots of the same group
	 * should appear in the queue. */
#define qinc(x) (x = ((x + 1) >= board_size2(b) ? ((x) + 1 - board_size2(b)) : (x) + 1))
	coord_t queue[board_size2(b)]; int qstart = 0, qstop = 0;

	foreach_point(b) {
		distances[c] = board_at(b, c) == S_OFFBOARD ? maxdist + 1 : -1;
	} foreach_point_end;

	queue[qstop++] = start;
	for (int d = 0; d <= maxdist; d++) {
		/* Process queued moves, while setting the queue
		 * for new wave. */
		int qa = qstart, qb = qstop;
		qstart = qstop;
		for (int q = qa; q < qb; qinc(q)) {
#define cfg_one(coord, grp) do {\
	distances[coord] = d; \
	foreach_neighbor (b, coord, { \
		if (distances[c] < 0 && (!grp || group_at(b, coord) != grp)) { \
			queue[qstop] = c; \
			qinc(qstop); \
		} \
	}); \
} while (0)
			coord_t cq = queue[q];
			if (distances[cq] >= 0)
				continue; /* We already looked here. */
			if (board_at(b, cq) == S_NONE) {
				cfg_one(cq, 0);
			} else {
				group_t g = group_at(b, cq);
				foreach_in_group(b, g) {
					cfg_one(c, g);
				} foreach_in_group_end;
			}
#undef cfg_one
		}
	}
Ejemplo n.º 10
0
/* Note that @to_play is important; e.g. consider snapback, it's good
 * to play at the last liberty by attacker, but not defender. */
static __attribute__((always_inline)) bool
capturable_group(struct board *b, enum stone capturer, coord_t c,
                 enum stone to_play)
{
    group_t g = group_at(b, c);
    if (likely(board_at(b, c) != stone_other(capturer)
               || board_group_info(b, g).libs > 1))
        return false;

    return can_play_on_lib(b, g, to_play);
}
Ejemplo n.º 11
0
Archivo: test.c Proyecto: mkghub/pachi
static bool
test_moggy_moves(struct board *b, char *arg)
{
	int runs = 1000;	
	
	coord_t *cc = str2coord(arg, board_size(b));
	struct move last;
	last.coord = *cc; coord_done(cc);
	last.color = board_at(b, last.coord);
	assert(last.color == S_BLACK || last.color == S_WHITE);
	enum stone color = stone_other(last.color);
	arg += strcspn(arg, " ") + 1;

	b->last_move = last;
	board_print(b, stderr);  // Always print board so we see last move

	char e_arg[128];  sprintf(e_arg, "runs=%i", runs);
	struct engine *e = engine_replay_init(e_arg, b);
	
	if (DEBUGL(1))
		printf("moggy moves %s, %s to play. Sampling moves (%i runs)...\n\n", 
		       coord2sstr(last.coord, b), stone2str(color), runs);

        int played_[b->size2 + 2];		memset(played_, 0, sizeof(played_));
	int *played = played_ + 2;		// allow storing pass/resign
	int most_played = 0;
	replay_sample_moves(e, b, color, played, &most_played);

	/* Show moves stats */	
	for (int k = most_played; k > 0; k--)
		for (coord_t c = resign; c < b->size2; c++)
			if (played[c] == k)
				printf("%3s: %.2f%%\n", coord2str(c, b), (float)k * 100 / runs);
	
	engine_done(e);
	return true;   // Not much of a unit test right now =)
}
Ejemplo n.º 12
0
Archivo: test.c Proyecto: mkghub/pachi
/* Syntax:
 *   moggy status (last_move) coord [coord...]
 *         Play number of random games starting from last_move
 * 
 *   moggy status     coord [coord...]
 *   moggy status (b) coord [coord...]
 *         Black to play, pick random white last move
 *
 *   moggy status (w) coord [coord...]  
 *         White to play, pick random black last move
 */
static bool
test_moggy_status(struct board *board, char *arg)
{
	int games = 4000;
	coord_t status_at[10];
	int n = 0;
	enum stone color = S_BLACK;
	int pick_random = true;  // Pick random last move for each game

	while (*arg && *arg != '#') {
		if (*arg == ' ' || *arg == '\t') {  arg++; continue;  }		
		if (!strncmp(arg, "(b)", 3))
			color = S_BLACK;
		else if (!strncmp(arg, "(w)", 3))
			color = S_WHITE;
		else if (*arg == '(') {  /* Optional "(last_move)" argument */
			arg++;	assert(isalpha(*arg));
			pick_random = false;
			struct move last;
			last.coord = str2scoord(arg, board_size(board));
			last.color = board_at(board, last.coord);
			assert(last.color == S_BLACK || last.color == S_WHITE);
			color = stone_other(last.color);
			board->last_move = last;
		}
		else {
			assert(isalpha(*arg));
			status_at[n++] = str2scoord(arg, board_size(board));
		}
		arg += strcspn(arg, " \t");
	}
	
	board_print(board, stderr);
	if (DEBUGL(1)) {
		printf("moggy status ");
		for (int i = 0; i < n; i++)
			printf("%s%s", coord2sstr(status_at[i], board), (i != n-1 ? " " : ""));
		printf(", %s to play. Playing %i games %s...\n", 
		       stone2str(color), games, (pick_random ? "(random last move) " : ""));
	}
	
	struct playout_policy *policy = playout_moggy_init(NULL, board, NULL);
	struct playout_setup setup = { .gamelen = MAX_GAMELEN };
	struct board_ownermap ownermap;

	ownermap.playouts = 0;
	ownermap.map = malloc2(board_size2(board) * sizeof(ownermap.map[0]));
	memset(ownermap.map, 0, board_size2(board) * sizeof(ownermap.map[0]));	


	/* Get final status estimate after a number of moggy games */
	int wr = 0;
	double time_start = time_now();
	for (int i = 0; i < games; i++)  {
		struct board b;
		board_copy(&b, board);
		if (pick_random)
			pick_random_last_move(&b, color);
		
		int score = play_random_game(&setup, &b, color, NULL, &ownermap, policy);
		if (color == S_WHITE)
			score = -score;
		wr += (score > 0);
		board_done_noalloc(&b);
	}
	double elapsed = time_now() - time_start;
	printf("moggy status in %.1fs, %i games/s\n\n", elapsed, (int)((float)games / elapsed));
	
	int wr_black = wr * 100 / games;
	int wr_white = (games - wr) * 100 / games;
	if (wr_black > wr_white)
		printf("Winrate: [ black %i%% ]  white %i%%\n\n", wr_black, wr_white);
	else
		printf("Winrate: black %i%%  [ white %i%% ]\n\n", wr_black, wr_white);

	board_print_ownermap(board, stderr, &ownermap);

	for (int i = 0; i < n; i++) {
		coord_t c = status_at[i];
		enum stone color = (ownermap.map[c][S_BLACK] > ownermap.map[c][S_WHITE] ? S_BLACK : S_WHITE);
		fprintf(stderr, "%3s owned by %s: %i%%\n", 
			coord2sstr(c, board), stone2str(color), 
			ownermap.map[c][color] * 100 / ownermap.playouts);
	}
	
	free(ownermap.map);
	playout_policy_done(policy);
	return true;   // Not much of a unit test right now =)
}
Ejemplo n.º 13
0
Archivo: test.c Proyecto: mkghub/pachi
static void
board_load(struct board *b, FILE *f, unsigned int size)
{
	board_printed = false;
	board_resize(b, size);
	board_clear(b);
	for (int y = size - 1; y >= 0; y--) {
		char line[256];
		if (!fgets(line, sizeof(line), f)) {
			fprintf(stderr, "Premature EOF.\n");
			exit(EXIT_FAILURE);
		}
		line[strlen(line) - 1] = 0; // chomp
		if (strlen(line) != size * 2 - 1) {
			fprintf(stderr, "Line not %d char long: %s\n", size * 2 - 1, line);
			exit(EXIT_FAILURE);
		}
		for (unsigned int i = 0; i < size * 2; i++) {
			enum stone s;
			switch (line[i]) {
				case '.': s = S_NONE; break;
				case 'X': s = S_BLACK; break;
				case 'O': s = S_WHITE; break;
				default: fprintf(stderr, "Invalid stone '%c'\n", line[i]);
					 exit(EXIT_FAILURE);
			}
			i++;
			if (line[i] != ' ' && i/2 < size - 1) {
				fprintf(stderr, "No space after stone %i: '%c'\n", i/2 + 1, line[i]);
				exit(EXIT_FAILURE);
			}
			if (s == S_NONE) continue;
			struct move m = { .color = s, .coord = coord_xy(b, i/2 + 1, y + 1) };
			if (board_play(b, &m) < 0) {
				fprintf(stderr, "Failed to play %s %s\n",
					stone2str(s), coord2sstr(m.coord, b));
				board_print(b, stderr);
				exit(EXIT_FAILURE);
			}
		}
	}
	int suicides = b->captures[S_BLACK] || b->captures[S_WHITE];
	assert(!suicides);
}

static void
set_ko(struct board *b, char *arg)
{
	assert(isalpha(*arg));
	struct move last;
	last.coord = str2scoord(arg, board_size(b));
	last.color = board_at(b, last.coord);
	assert(last.color == S_BLACK || last.color == S_WHITE);
	b->last_move = last;

	/* Sanity checks */
	group_t g = group_at(b, last.coord);
	assert(board_group_info(b, g).libs == 1);
	assert(group_stone_count(b, g, 2) == 1);
	coord_t lib = board_group_info(b, g).lib[0];
	assert(board_is_eyelike(b, lib, last.color));

	b->ko.coord = lib;
	b->ko.color = stone_other(last.color);
}
Ejemplo n.º 14
0
static bool
middle_ladder_walk(Board *b, Board *bset, group_t laddered, Coord nextmove, Stone lcolor)
{
	assert(group_at(b, laddered)->liberties == 1);

	/* First, escape. */
  /*
	if (DEBUGL(6))
		fprintf(stderr, "  ladder escape %s\n", coord2sstr(nextmove, b));
  */
  GroupId4 ids;
  if (!TryPlay2(b, nextmove, &ids)) error("The play should never be wrong!");
  Play(b, &ids);

	// laddered = group_at(b, laddered);
  /*
	if (DEBUGL(8)) {
		board_print(b, stderr);
		fprintf(stderr, "%s c %d\n", coord2sstr(laddered, b), board_group_info(b, laddered).libs);
	}
  */

  int laddered_libs = b->_groups[laddered].liberties;

	if (laddered_libs == 1) {
    /*
		if (DEBUGL(6))
			fprintf(stderr, "* we can capture now\n");
    */
		return true;
	}
	if (laddered_libs > 2) {
    /*
		if (DEBUGL(6))
			fprintf(stderr, "* we are free now\n");
    */
		return false;
	}

  FOR4(nextmove, _, c) {
		if (board_at(b, c) == OPPONENT(lcolor) && group_at(b, c)->liberties == 1) {
			/* We can capture one of the ladder stones
			 * anytime later. */
			/* XXX: If we were very lucky, capturing
			 * this stone will not help us escape.
			 * That should be pretty rate. */
      /*
			if (DEBUGL(6))
				fprintf(stderr, "* can capture chaser\n");
      */
			return false;
		}
	} ENDFOR4

	/* Now, consider alternatives. */
	int liblist[2], libs = 0;
  Coord tmp_libs[2];
  get_nlibs_of_group(b, laddered, 2, tmp_libs);
	for (int i = 0; i < 2; i++) {
		Coord ataristone = tmp_libs[i];
		Coord escape = tmp_libs[1 - i];
		if (immediate_liberty_count(b, escape) > 2 + NEIGHBOR4(ataristone, escape)) {
			/* Too much free space, ignore. */
			continue;
		}
		liblist[libs++] = i;
	}

	/* Try out the alternatives. */
	bool is_ladder = false;
	for (int i = 0; !is_ladder && i < libs; i++) {
		Board *b2 = b;
		if (i != libs - 1) {
			b2 = bset++;
      CopyBoard(b2, b);
		}

    Coord libs_b2[2];
    get_nlibs_of_group(b2, laddered, 2, libs_b2);

		Coord ataristone = libs_b2[liblist[i]];
		// Coord escape = board_group_info(b2, laddered).lib[1 - liblist[i]];
		struct move m = { ataristone, OPPONENT(lcolor) };
    bool play_successful = TryPlay2(b2, ataristone, &ids);
    if (play_successful) Play(b2, &ids);
		/* If we just played self-atari, abandon ship. */
		/* XXX: If we were very lucky, capturing this stone will
		 * not help us escape. That should be pretty rate. */
    /*
		if (DEBUGL(6))
			fprintf(stderr, "(%d=%d) ladder atari %s (%d libs)\n", i, res, coord2sstr(ataristone, b2), board_group_info(b2, group_at(b2, ataristone)).libs);
    */
		if (play_successful && group_at(b2, ataristone)->liberties > 1) {
      Coord last_lib = get_nlibs_of_group(b2, laddered, 1, NULL);
			is_ladder = middle_ladder_walk(b2, bset, laddered, last_lib, lcolor);
    }

    /* Why we need to do deallocation?
		if (i != libs - 1) {
			board_done_noalloc(b2);
		}
    */
	}
  /*
	if (DEBUGL(6))
		fprintf(stderr, "propagating %d\n", is_ladder);
  */
	return is_ladder;
}