Ejemplo n.º 1
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.º 2
0
Archivo: move.c Proyecto: ujh/HouseBot
int
coord_edge_distance(coord_t c, struct board *b)
{
	int x = coord_x(c, b), y = coord_y(c, b);
	int dx = x > board_size(b) / 2 ? board_size(b) - x : x;
	int dy = y > board_size(b) / 2 ? board_size(b) - y : y;
	return (dx < dy ? dx : dy) - 1 /* S_OFFBOARD */;
}
Ejemplo n.º 3
0
void
board_stats_print(struct board *board, struct move_stat *moves, FILE *f)
{
	fprintf(f, "\n       ");
	int x, y;
	char asdf[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ";
	for (x = 1; x < board_size(board) - 1; x++)
		fprintf(f, "%c    ", asdf[x - 1]);
	fprintf(f, "\n   +-");
	for (x = 1; x < board_size(board) - 1; x++)
		fprintf(f, "-----");
	fprintf(f, "+\n");
	for (y = board_size(board) - 2; y >= 1; y--) {
		fprintf(f, "%2d | ", y);
		for (x = 1; x < board_size(board) - 1; x++)
			if (moves[y * board_size(board) + x].games)
				fprintf(f, "%0.2f ", (floating_t) moves[y * board_size(board) + x].wins / moves[y * board_size(board) + x].games);
			else
				fprintf(f, "---- ");
		fprintf(f, "| ");
		for (x = 1; x < board_size(board) - 1; x++)
			fprintf(f, "%4d ", moves[y * board_size(board) + x].games);
		fprintf(f, "|\n");
	}
	fprintf(f, "   +-");
	for (x = 1; x < board_size(board) - 1; x++)
		fprintf(f, "-----");
	fprintf(f, "+\n");
}
Ejemplo n.º 4
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.º 5
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.º 6
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.º 7
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.º 8
0
static coord_t
coord_transform(struct board *b, coord_t coord, int i)
{
#define HASH_VMIRROR     1
#define HASH_HMIRROR     2
#define HASH_XYFLIP      4
	if (i & HASH_VMIRROR) {
		coord = coord_xy(b, coord_x(coord, b), board_size(b) - 1 - coord_y(coord, b));
	}
	if (i & HASH_HMIRROR) {
		coord = coord_xy(b, board_size(b) - 1 - coord_x(coord, b), coord_y(coord, b));
	}
	if (i & HASH_XYFLIP) {
		coord = coord_xy(b, coord_y(coord, b), coord_x(coord, b));
	}
	return coord;
}
Ejemplo n.º 9
0
void
board_resize(struct board *board, int size)
{
#ifdef BOARD_SIZE
	assert(board_size(board) == size + 2);
#endif
	assert(size <= BOARD_MAX_SIZE);
	board->size = size + 2 /* S_OFFBOARD margin */;
	board->size2 = board_size(board) * board_size(board);

	board->bits2 = 1;
	while ((1 << board->bits2) < board->size2) board->bits2++;

	if (board->b)
		free(board->b);

	size_t asize = board_alloc(board);
	memset(board->b, 0, asize);
}
Ejemplo n.º 10
0
int main(int argc, char** argv) {

    int size_of_board; //BOARD'IN BUYUKLUGU
    char cells[21][21]; //CHAR TIPINDE 2D ARRAY
    int check_player_move=1; // PLAYERIN ANLAMLI HAREKETINI KONTROL
    int player_can_move=1;//Playerin hamlesinin olup olmadigi kontrol edilir
    int computer_can_move=1;//Computerin hamlesinin olup olmadigi kontrol edilir
    
    //Gecerli bir size of board degeri girilene kadar,
    //kullanicidan size of board degeri istenir.
    size_of_board=board_size();
    
    //Hucrelerin oyun basi degerleri verilir
    first_view(size_of_board, cells);
    
    //Guncel board ekrana cizilir.
    paint_board(size_of_board, cells);
    
    //Eger player veya computer hamle yapabiliyorsa 
    while(player_can_move==1 || computer_can_move==1)
    {
        computer_can_move=1;
        
        //Player yapacak hamleye sahip mi degil mi
        player_can_move=does_player_have_move(size_of_board, cells);
        
        //Eger Player Hamle yapabiliyorsa
        if(player_can_move)  
        {
            while(check_player_move)
            {
                //Player Hareketi
                //Legal bir hareket girilene kadar donguden cikmaz
                check_player_move=for_player_move(size_of_board, cells);              
            }
            check_player_move=1;
        
            //Guncel board ekrana cizilir.
            paint_board(size_of_board, cells);
        }
        
        //Computer Hareketi
        for_computer_move(size_of_board, cells, &computer_can_move);
    
        //Guncel board ekrana cizilir.
        paint_board(size_of_board, cells);
        
        cout <<"\n";
    }
    
    //Skor Yazilir
    scoreboard(size_of_board, cells);
    
    return 0;
}
Ejemplo n.º 11
0
static floating_t
board_game_portion(struct dynkomi_adaptive *a, struct board *b)
{
	if (!a->adapt_aport) {
		int total_moves = b->moves + 2 * board_estimated_moves_left(b);
		return (floating_t) b->moves / total_moves;
	} else {
		int brsize = board_size(b) - 2;
		return 1.0 - (floating_t) b->flen / (brsize * brsize);
	}
}
Ejemplo n.º 12
0
char* print_score_histogram(Position *pos, int score_count[2*N*N+1]) 
{
    int cmax=0, nc=0, size2=board_size(pos)*board_size(pos);
    for (int i=0; i <= 2*N*N+1 ; i++)
        if (score_count[i] > cmax) cmax = score_count[i];

    if (cmax > 0) {
        for (int s=-size2 ; s <= size2 ; s++) {
            int n = (50*score_count[s+N*N]) / cmax;
            char c;
            if (s < 0)       c = '-';
            else if (s == 0) c = '=';
            else             c = '+';
            nc += sprintf(buf + nc, "%5d %5d ", s, score_count[s+N*N]);
            for (int i=0 ; i < n ; i++)
                nc += sprintf(buf + nc, "%c", c);
            nc += sprintf(buf + nc, "\n");
        }
    }
    return buf;
}
Ejemplo n.º 13
0
bool
board_stone_radar(struct board *b, coord_t coord, int distance)
{
	int bounds[4] = {
		coord_x(coord, b) - distance,
		coord_y(coord, b) - distance,
		coord_x(coord, b) + distance,
		coord_y(coord, b) + distance
	};
	for (int i = 0; i < 4; i++)
		if (bounds[i] < 1)
			bounds[i] = 1;
		else if (bounds[i] > board_size(b) - 2)
			bounds[i] = board_size(b) - 2;
	for (int x = bounds[0]; x <= bounds[2]; x++)
		for (int y = bounds[1]; y <= bounds[3]; y++)
			if (board_atxy(b, x, y) != S_NONE) {
				/* fprintf(stderr, "radar %d,%d,%d: %d,%d (%d)\n",
					coord_x(coord, b), coord_y(coord, b),
					distance, x, y, board_atxy(b, x, y)); */
				return true;
			}
	return false;
}
Ejemplo n.º 14
0
/* Adjust the recommended per-move time based on the current game phase.
 * We expect stop->worst to be total time available, stop->desired the current
 * per-move time allocation, and set stop->desired to adjusted per-move time. */
static void
time_stop_phase_adjust(struct board *b, int fuseki_end, int yose_start, struct time_stop *stop)
{
	int bsize = (board_size(b)-2)*(board_size(b)-2);
	fuseki_end = fuseki_end * bsize / 100; // move nb at fuseki end
	yose_start = yose_start * bsize / 100; // move nb at yose start
	assert(fuseki_end < yose_start);

	/* No adjustments in yose. */
	if (b->moves >= yose_start)
		return;
	int moves_to_yose = (yose_start - b->moves) / 2;
	// ^- /2 because we only consider the moves we have to play ourselves
	int left_at_yose_start = board_estimated_moves_left(b) - moves_to_yose;
	if (left_at_yose_start < MIN_MOVES_LEFT)
		left_at_yose_start = MIN_MOVES_LEFT;

	/* This particular value of middlegame_time will continuously converge
	 * to effective "yose_time" value as we approach yose_start. */
	double middlegame_time = stop->worst.time / left_at_yose_start;
	if (middlegame_time < stop->desired.time)
		return;

	if (b->moves < fuseki_end) {
		assert(fuseki_end > 0);
		/* At the game start, use stop->desired.time (rather
		 * conservative estimate), then gradually prolong it. */
		double beta = b->moves / fuseki_end;
		stop->desired.time = middlegame_time * beta + stop->desired.time * (1 - beta);

	} else { assert(b->moves < yose_start);
		/* Middlegame, start with relatively large value, then
		 * converge to the uniform-timeslice yose value. */
		stop->desired.time = middlegame_time;
	}
}
Ejemplo n.º 15
0
static coord_t *
proof_genmove(struct engine *e, struct board *b, struct time_info *ti, enum stone color, bool pass_all_alive)
{
    coord_t *coord;
    fprintf(stderr, "HELLO WORLD!");
    struct board b2;
    board_copy(&b2, b);
    for (int i=0; i<=19; i++){
        for (int j=0; j<=19; j++){
            coord = coord_init(i,j,board_size(&b2));
            if (board_is_valid_play(&b2, color, *coord))
                return coord;
        }
    }
    *coord = -1;
    return coord;
}
Ejemplo n.º 16
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.º 17
0
int
uct_playout(struct uct *u, struct board *b, enum stone player_color, struct tree *t)
{
	struct board b2;
	board_copy(&b2, b);

	struct playout_amafmap amaf;
	amaf.gamelen = amaf.game_baselen = 0;

	/* Walk the tree until we find a leaf, then expand it and do
	 * a random playout. */
	struct tree_node *n = t->root;
	enum stone node_color = stone_other(player_color);
	assert(node_color == t->root_color);

	/* Make sure the root node is expanded. */
	if (tree_leaf_node(n) && !__sync_lock_test_and_set(&n->is_expanded, 1))
		tree_expand_node(t, n, &b2, player_color, u, 1);

	/* Tree descent history. */
	/* XXX: This is somewhat messy since @n and descent[dlen-1].node are
	 * redundant. */
	struct uct_descent descent[DESCENT_DLEN];
	descent[0].node = n; descent[0].lnode = NULL;
	int dlen = 1;
	/* Total value of the sequence. */
	struct move_stats seq_value = { .playouts = 0 };
	/* The last "significant" node along the descent (i.e. node
	 * with higher than configured number of playouts). For black
	 * and white. */
	struct tree_node *significant[2] = { NULL, NULL };
	if (n->u.playouts >= u->significant_threshold)
		significant[node_color - 1] = n;

	int result;
	int pass_limit = (board_size(&b2) - 2) * (board_size(&b2) - 2) / 2;
	int passes = is_pass(b->last_move.coord) && b->moves > 0;

	/* debug */
	static char spaces[] = "\0                                                      ";
	/* /debug */
	if (UDEBUGL(8))
		fprintf(stderr, "--- UCT walk with color %d\n", player_color);

	while (!tree_leaf_node(n) && passes < 2) {
		spaces[dlen - 1] = ' '; spaces[dlen] = 0;


		/*** Choose a node to descend to: */

		/* Parity is chosen already according to the child color, since
		 * it is applied to children. */
		node_color = stone_other(node_color);
		int parity = (node_color == player_color ? 1 : -1);

		assert(dlen < DESCENT_DLEN);
		descent[dlen] = descent[dlen - 1];
		if (u->local_tree && (!descent[dlen].lnode || descent[dlen].node->d >= u->tenuki_d)) {
			/* Start new local sequence. */
			/* Remember that node_color already holds color of the
			 * to-be-found child. */
			descent[dlen].lnode = node_color == S_BLACK ? t->ltree_black : t->ltree_white;
		}

		if (!u->random_policy_chance || fast_random(u->random_policy_chance))
			u->policy->descend(u->policy, t, &descent[dlen], parity, b2.moves > pass_limit);
		else
			u->random_policy->descend(u->random_policy, t, &descent[dlen], parity, b2.moves > pass_limit);


		/*** Perform the descent: */

		if (descent[dlen].node->u.playouts >= u->significant_threshold) {
			significant[node_color - 1] = descent[dlen].node;
		}

		seq_value.playouts += descent[dlen].value.playouts;
		seq_value.value += descent[dlen].value.value * descent[dlen].value.playouts;
		n = descent[dlen++].node;
		assert(n == t->root || n->parent);
		if (UDEBUGL(7))
			fprintf(stderr, "%s+-- UCT sent us to [%s:%d] %d,%f\n",
			        spaces, coord2sstr(node_coord(n), t->board),
				node_coord(n), n->u.playouts,
				tree_node_get_value(t, parity, n->u.value));

		/* Add virtual loss if we need to; this is used to discourage
		 * other threads from visiting this node in case of multiple
		 * threads doing the tree search. */
		if (u->virtual_loss)
			stats_add_result(&n->u, node_color == S_BLACK ? 0.0 : 1.0, u->virtual_loss);

		assert(node_coord(n) >= -1);
		record_amaf_move(&amaf, node_coord(n));

		struct move m = { node_coord(n), node_color };
		int res = board_play(&b2, &m);

		if (res < 0 || (!is_pass(m.coord) && !group_at(&b2, m.coord)) /* suicide */
		    || b2.superko_violation) {
			if (UDEBUGL(4)) {
				for (struct tree_node *ni = n; ni; ni = ni->parent)
					fprintf(stderr, "%s<%"PRIhash"> ", coord2sstr(node_coord(ni), t->board), ni->hash);
				fprintf(stderr, "marking invalid %s node %d,%d res %d group %d spk %d\n",
				        stone2str(node_color), coord_x(node_coord(n),b), coord_y(node_coord(n),b),
					res, group_at(&b2, m.coord), b2.superko_violation);
			}
			n->hints |= TREE_HINT_INVALID;
			result = 0;
			goto end;
		}

		if (is_pass(node_coord(n)))
			passes++;
		else
			passes = 0;

		enum stone next_color = stone_other(node_color);
		/* We need to make sure only one thread expands the node. If
		 * we are unlucky enough for two threads to meet in the same
		 * node, the latter one will simply do another simulation from
		 * the node itself, no big deal. t->nodes_size may exceed
		 * the maximum in multi-threaded case but not by much so it's ok.
		 * The size test must be before the test&set not after, to allow
		 * expansion of the node later if enough nodes have been freed. */
		if (tree_leaf_node(n)
		    && n->u.playouts - u->virtual_loss >= u->expand_p && t->nodes_size < u->max_tree_size
		    && !__sync_lock_test_and_set(&n->is_expanded, 1))
			tree_expand_node(t, n, &b2, next_color, u, -parity);
	}

	amaf.game_baselen = amaf.gamelen;

	if (t->use_extra_komi && u->dynkomi->persim) {
		b2.komi += round(u->dynkomi->persim(u->dynkomi, &b2, t, n));
	}

	if (passes >= 2) {
		/* XXX: No dead groups support. */
		floating_t score = board_official_score(&b2, NULL);
		/* Result from black's perspective (no matter who
		 * the player; black's perspective is always
		 * what the tree stores. */
		result = - (score * 2);

		if (UDEBUGL(5))
			fprintf(stderr, "[%d..%d] %s p-p scoring playout result %d (W %f)\n",
				player_color, node_color, coord2sstr(node_coord(n), t->board), result, score);
		if (UDEBUGL(6))
			board_print(&b2, stderr);

		board_ownermap_fill(&u->ownermap, &b2);

	} else { // assert(tree_leaf_node(n));
		/* In case of parallel tree search, the assertion might
		 * not hold if two threads chew on the same node. */
		result = uct_leaf_node(u, &b2, player_color, &amaf, descent, &dlen, significant, t, n, node_color, spaces);
	}

	if (u->policy->wants_amaf && u->playout_amaf_cutoff) {
		unsigned int cutoff = amaf.game_baselen;
		cutoff += (amaf.gamelen - amaf.game_baselen) * u->playout_amaf_cutoff / 100;
		amaf.gamelen = cutoff;
	}

	/* Record the result. */

	assert(n == t->root || n->parent);
	floating_t rval = scale_value(u, b, result);
	u->policy->update(u->policy, t, n, node_color, player_color, &amaf, &b2, rval);

	if (t->use_extra_komi) {
		stats_add_result(&u->dynkomi->score, result / 2, 1);
		stats_add_result(&u->dynkomi->value, rval, 1);
	}

	if (u->local_tree && n->parent && !is_pass(node_coord(n)) && dlen > 0) {
		/* Get the local sequences and record them in ltree. */
		/* We will look for sequence starts in our descent
		 * history, then run record_local_sequence() for each
		 * found sequence start; record_local_sequence() may
		 * pick longer sequences from descent history then,
		 * which is expected as it will create new lnodes. */
		enum stone seq_color = player_color;
		/* First move always starts a sequence. */
		record_local_sequence(u, t, &b2, descent, dlen, 1, seq_color);
		seq_color = stone_other(seq_color);
		for (int dseqi = 2; dseqi < dlen; dseqi++, seq_color = stone_other(seq_color)) {
			if (u->local_tree_allseq) {
				/* We are configured to record all subsequences. */
				record_local_sequence(u, t, &b2, descent, dlen, dseqi, seq_color);
				continue;
			}
			if (descent[dseqi].node->d >= u->tenuki_d) {
				/* Tenuki! Record the fresh sequence. */
				record_local_sequence(u, t, &b2, descent, dlen, dseqi, seq_color);
				continue;
			}
			if (descent[dseqi].lnode && !descent[dseqi].lnode) {
				/* Record result for in-descent picked sequence. */
				record_local_sequence(u, t, &b2, descent, dlen, dseqi, seq_color);
				continue;
			}
		}
	}

end:
	/* We need to undo the virtual loss we added during descend. */
	if (u->virtual_loss) {
		floating_t loss = node_color == S_BLACK ? 0.0 : 1.0;
		for (; n->parent; n = n->parent) {
			stats_rm_result(&n->u, loss, u->virtual_loss);
			loss = 1.0 - loss;
		}
	}

	board_done_noalloc(&b2);
	return result;
}

int
uct_playouts(struct uct *u, struct board *b, enum stone color, struct tree *t, struct time_info *ti)
{
	int i;
	if (ti && ti->dim == TD_GAMES) {
		for (i = 0; t->root->u.playouts <= ti->len.games && !uct_halt; i++)
			uct_playout(u, b, color, t);
	} else {
		for (i = 0; !uct_halt; i++)
			uct_playout(u, b, color, t);
	}
	return i;
}
Ejemplo n.º 18
0
static int
uct_leaf_node(struct uct *u, struct board *b, enum stone player_color,
              struct playout_amafmap *amaf,
	      struct uct_descent *descent, int *dlen,
	      struct tree_node *significant[2],
              struct tree *t, struct tree_node *n, enum stone node_color,
	      char *spaces)
{
	enum stone next_color = stone_other(node_color);
	int parity = (next_color == player_color ? 1 : -1);

	if (UDEBUGL(7))
		fprintf(stderr, "%s*-- UCT playout #%d start [%s] %f\n",
			spaces, n->u.playouts, coord2sstr(node_coord(n), t->board),
			tree_node_get_value(t, parity, n->u.value));

	struct uct_playout_callback upc = {
		.uct = u,
		.tree = t,
		/* TODO: Don't necessarily restart the sequence walk when
		 * entering playout. */
		.lnode = NULL,
	};

	struct playout_setup ps = {
		.gamelen = u->gamelen,
		.mercymin = u->mercymin,
		.prepolicy_hook = uct_playout_prepolicy,
		.postpolicy_hook = uct_playout_postpolicy,
		.hook_data = &upc,
	};
	int result = play_random_game(&ps, b, next_color,
	                              u->playout_amaf ? amaf : NULL,
				      &u->ownermap, u->playout);
	if (next_color == S_WHITE) {
		/* We need the result from black's perspective. */
		result = - result;
	}
	if (UDEBUGL(7))
		fprintf(stderr, "%s -- [%d..%d] %s random playout result %d\n",
		        spaces, player_color, next_color, coord2sstr(node_coord(n), t->board), result);

	return result;
}

static floating_t
scale_value(struct uct *u, struct board *b, int result)
{
	floating_t rval = result > 0 ? 1.0 : result < 0 ? 0.0 : 0.5;
	if (u->val_scale && result != 0) {
		int vp = u->val_points;
		if (!vp) {
			vp = board_size(b) - 1; vp *= vp; vp *= 2;
		}

		floating_t sval = (floating_t) abs(result) / vp;
		sval = sval > 1 ? 1 : sval;
		if (result < 0) sval = 1 - sval;
		if (u->val_extra)
			rval += u->val_scale * sval;
		else
			rval = (1 - u->val_scale) * rval + u->val_scale * sval;
		// fprintf(stderr, "score %d => sval %f, rval %f\n", result, sval, rval);
	}
	return rval;
}
Ejemplo n.º 19
0
static coord_t *
montecarlo_genmove(struct engine *e, struct board *b, struct time_info *ti, enum stone color, bool pass_all_alive)
{
	struct montecarlo *mc = e->data;

	if (ti->dim == TD_WALLTIME) {
		fprintf(stderr, "Warning: TD_WALLTIME time mode not supported, resetting to defaults.\n");
		ti->period = TT_NULL;
	}
	if (ti->period == TT_NULL) {
		ti->period = TT_MOVE;
		ti->dim = TD_GAMES;
		ti->len.games = MC_GAMES;
	}
	struct time_stop stop;
	time_stop_conditions(ti, b, 20, 40, 3.0, &stop);

	/* resign when the hope for win vanishes */
	coord_t top_coord = resign;
	floating_t top_ratio = mc->resign_ratio;

	/* We use [0] for pass. Normally, this is an inaccessible corner
	 * of board margin. */
	struct move_stat moves[board_size2(b)];
	memset(moves, 0, sizeof(moves));

	int losses = 0;
	int i, superko = 0, good_games = 0;
	for (i = 0; i < stop.desired.playouts; i++) {
		assert(!b->superko_violation);

		struct board b2;
		board_copy(&b2, b);

		coord_t coord;
		board_play_random(&b2, color, &coord, NULL, NULL);
		if (!is_pass(coord) && !group_at(&b2, coord)) {
			/* Multi-stone suicide. We play chinese rules,
			 * so we can't consider this. (Note that we
			 * unfortunately still consider this in playouts.) */
			if (DEBUGL(4)) {
				fprintf(stderr, "SUICIDE DETECTED at %d,%d:\n", coord_x(coord, b), coord_y(coord, b));
				board_print(b, stderr);
			}
			continue;
		}

		if (DEBUGL(3))
			fprintf(stderr, "[%d,%d color %d] playing random game\n", coord_x(coord, b), coord_y(coord, b), color);

		struct playout_setup ps = { .gamelen = mc->gamelen };
		int result = play_random_game(&ps, &b2, color, NULL, NULL, mc->playout);

		board_done_noalloc(&b2);

		if (result == 0) {
			/* Superko. We just ignore this playout.
			 * And play again. */
			if (unlikely(superko > 2 * stop.desired.playouts)) {
				/* Uhh. Triple ko, or something? */
				if (MCDEBUGL(0))
					fprintf(stderr, "SUPERKO LOOP. I will pass. Did we hit triple ko?\n");
				goto pass_wins;
			}
			/* This playout didn't count; we should not
			 * disadvantage moves that lead to a superko.
			 * And it is supposed to be rare. */
			i--, superko++;
			continue;
		}

		if (MCDEBUGL(3))
			fprintf(stderr, "\tresult for other player: %d\n", result);

		int pos = is_pass(coord) ? 0 : coord;

		good_games++;
		moves[pos].games++;

		losses += result > 0;
		moves[pos].wins += 1 - (result > 0);

		if (unlikely(!losses && i == mc->loss_threshold)) {
			/* We played out many games and didn't lose once yet.
			 * This game is over. */
			break;
		}
	}

	if (!good_games) {
		/* No moves to try??? */
		if (MCDEBUGL(0)) {
			fprintf(stderr, "OUT OF MOVES! I will pass. But how did this happen?\n");
			board_print(b, stderr);
		}
pass_wins:
		top_coord = pass; top_ratio = 0.5;
		goto move_found;
	}

	foreach_point(b) {
		if (b->moves < 3) {
			/* Simple heuristic: avoid opening too low. Do not
			 * play on second or first line as first white or
			 * first two black moves.*/
			if (coord_x(c, b) < 3 || coord_x(c, b) > board_size(b) - 4
			    || coord_y(c, b) < 3 || coord_y(c, b) > board_size(b) - 4)
				continue;
		}

		floating_t ratio = (floating_t) moves[c].wins / moves[c].games;
		/* Since pass is [0,0], we will pass only when we have nothing
		 * better to do. */
		if (ratio >= top_ratio) {
			top_ratio = ratio;
			top_coord = c == 0 ? pass : c;
		}
	} foreach_point_end;

	if (MCDEBUGL(2)) {
		board_stats_print(b, moves, stderr);
	}

move_found:
	if (MCDEBUGL(1))
		fprintf(stderr, "*** WINNER is %d,%d with score %1.4f (%d games, %d superko)\n", coord_x(top_coord, b), coord_y(top_coord, b), top_ratio, i, superko);

	return coord_copy(top_coord);
}

static void
montecarlo_done(struct engine *e)
{
	struct montecarlo *mc = e->data;
	playout_policy_done(mc->playout);
	joseki_done(mc->jdict);
}

struct montecarlo *
montecarlo_state_init(char *arg, struct board *b)
{
	struct montecarlo *mc = calloc2(1, sizeof(struct montecarlo));

	mc->debug_level = 1;
	mc->gamelen = MC_GAMELEN;
	mc->jdict = joseki_load(b->size);

	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, "debug")) {
				if (optval)
					mc->debug_level = atoi(optval);
				else
					mc->debug_level++;
			} else if (!strcasecmp(optname, "gamelen") && optval) {
				mc->gamelen = atoi(optval);
			} else if (!strcasecmp(optname, "playout") && optval) {
				char *playoutarg = strchr(optval, ':');
				if (playoutarg)
					*playoutarg++ = 0;
				if (!strcasecmp(optval, "moggy")) {
					mc->playout = playout_moggy_init(playoutarg, b, mc->jdict);
				} else if (!strcasecmp(optval, "light")) {
					mc->playout = playout_light_init(playoutarg, b);
				} else {
					fprintf(stderr, "MonteCarlo: Invalid playout policy %s\n", optval);
				}
			} else {
				fprintf(stderr, "MonteCarlo: Invalid engine argument %s or missing value\n", optname);
			}
		}
	}

	if (!mc->playout)
		mc->playout = playout_light_init(NULL, b);
	mc->playout->debug_level = mc->debug_level;

	mc->resign_ratio = 0.1; /* Resign when most games are lost. */
	mc->loss_threshold = 5000; /* Stop reading if no loss encountered in first 5000 games. */

	return mc;
}


struct engine *
engine_montecarlo_init(char *arg, struct board *b)
{
	struct montecarlo *mc = montecarlo_state_init(arg, b);
	struct engine *e = calloc2(1, sizeof(struct engine));
	e->name = "MonteCarlo";
	e->comment = "I'm playing in Monte Carlo. When we both pass, I will consider all the stones on the board alive. If you are reading this, write 'yes'. Please bear with me at the game end, I need to fill the whole board; if you help me, we will both be happier. Filling the board will not lose points (NZ rules).";
	e->genmove = montecarlo_genmove;
	e->done = montecarlo_done;
	e->data = mc;

	return e;
}
Ejemplo n.º 20
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.º 21
0
struct fbook *
fbook_init(char *filename, struct board *b)
{
	if (fbcache && fbcache->bsize == board_size(b)
	    && fbcache->handicap == b->handicap)
		return fbcache;

	FILE *f = fopen(filename, "r");
	if (!f) {
		perror(filename);
		return NULL;
	}

	struct fbook *fbook = calloc(1, sizeof(*fbook));
	fbook->bsize = board_size(b);
	fbook->handicap = b->handicap;
	/* We do not set handicap=1 in case of too low komi on purpose;
	 * we want to go with the no-handicap fbook for now. */
	for (int i = 0; i < 1<<fbook_hash_bits; i++)
		fbook->moves[i] = pass;

	if (DEBUGL(1))
		fprintf(stderr, "Loading opening fbook %s...\n", filename);

	/* Scratch board where we lay out the sequence;
	 * one for each transposition. */
	struct board *bs[8];
	for (int i = 0; i < 8; i++) {
		bs[i] = board_init(NULL);
		board_resize(bs[i], fbook->bsize - 2);
	}

	char linebuf[1024];
	while (fgets(linebuf, sizeof(linebuf), f)) {
		char *line = linebuf;
		linebuf[strlen(linebuf) - 1] = 0; // chop

		/* Format of line is:
		 * BSIZE COORD COORD COORD... | COORD
		 * BSIZE/HANDI COORD COORD COORD... | COORD
		 * We descend up to |, then add the new node
		 * with value minimax(1000), forcing UCT to
		 * always pick that node immediately. */
		int bsize = strtol(line, &line, 10);
		if (bsize != fbook->bsize - 2)
			continue;
		int handi = 0;
		if (*line == '/') {
			line++;
			handi = strtol(line, &line, 10);
		}
		if (handi != fbook->handicap)
			continue;
		while (isspace(*line)) line++;

		for (int i = 0; i < 8; i++) {
			board_clear(bs[i]);
			bs[i]->last_move.color = S_WHITE;
		}

		while (*line != '|') {
			coord_t *c = str2coord(line, fbook->bsize);

			for (int i = 0; i < 8; i++) {
				coord_t coord = coord_transform(b, *c, i);
				struct move m = { .coord = coord, .color = stone_other(bs[i]->last_move.color) };
				int ret = board_play(bs[i], &m);
				assert(ret >= 0);
			}

			coord_done(c);
			while (!isspace(*line)) line++;
			while (isspace(*line)) line++;
		}

		line++;
		while (isspace(*line)) line++;

		/* In case of multiple candidates, pick one with
		 * exponentially decreasing likelihood. */
		while (strchr(line, ' ') && fast_random(2)) {
			line = strchr(line, ' ');
			while (isspace(*line)) line++;
			// fprintf(stderr, "<%s> skip to %s\n", linebuf, line);
		}

		coord_t *c = str2coord(line, fbook->bsize);
		for (int i = 0; i < 8; i++) {
			coord_t coord = coord_transform(b, *c, i);
#if 0
			char conflict = is_pass(fbook->moves[bs[i]->hash & fbook_hash_mask]) ? '+' : 'C';
			if (conflict == 'C')
				for (int j = 0; j < i; j++)
					if (bs[i]->hash == bs[j]->hash)
						conflict = '+';
			if (conflict == 'C') {
				hash_t hi = bs[i]->hash;
				while (!is_pass(fbook->moves[hi & fbook_hash_mask]) && fbook->hashes[hi & fbook_hash_mask] != bs[i]->hash)
					hi++;
				if (fbook->hashes[hi & fbook_hash_mask] == bs[i]->hash)
					hi = 'c';
			}
			fprintf(stderr, "%c %"PRIhash":%"PRIhash" (<%d> %s)\n", conflict,
			        bs[i]->hash & fbook_hash_mask, bs[i]->hash, i, linebuf);
#endif
			hash_t hi = bs[i]->hash;
			while (!is_pass(fbook->moves[hi & fbook_hash_mask]) && fbook->hashes[hi & fbook_hash_mask] != bs[i]->hash)
				hi++;
			fbook->moves[hi & fbook_hash_mask] = coord;
			fbook->hashes[hi & fbook_hash_mask] = bs[i]->hash;
			fbook->movecnt++;
		}
		coord_done(c);
	}

	for (int i = 0; i < 8; i++) {
		board_done(bs[i]);
	}

	fclose(f);

	if (!fbook->movecnt) {
		/* Empty book is not worth the hassle. */
		fbook_done(fbook);
		return NULL;
	}

	struct fbook *fbold = fbcache;
	fbcache = fbook;
	if (fbold)
		fbook_done(fbold);

	return fbook;
}

void fbook_done(struct fbook *fbook)
{
	if (fbook != fbcache)
		free(fbook);
}
Ejemplo n.º 22
0
void PropValue(void)
// PropValue = "[" ValueType "]"
{
    yyaccept('['); ValueType();

    // Property Value was read : use it to modify the game
    int size = board_size(game->pos);
    if (board_nmoves(game->pos) < nmoves-1 
        && strcmp(prop_name[prop], "B") == 0) {
        if (yytext[0] != 'B')
            do_play(game, BLACK, parse_sgf_coord(yytext, size));
        else
            do_play(game, BLACK, PASS_MOVE);
    }
    else if (board_nmoves(game->pos) < nmoves-1 
        && strcmp(prop_name[prop], "W") == 0) {
        if (yytext[0] != 'W')
            do_play(game, WHITE, parse_sgf_coord(yytext, size));
        else
            do_play(game, WHITE, PASS_MOVE);
    }
    else if (strcmp(prop_name[prop], "AB") == 0) {
        Point pt = parse_sgf_coord(yytext, size);
        slist_push(game->placed_black_stones, pt);
        board_place_stone(game->pos, pt, BLACK);
    }
    else if (strcmp(prop_name[prop], "AW") == 0) {
        Point pt = parse_sgf_coord(yytext, size);
        slist_push(game->placed_white_stones, pt);
        board_place_stone(game->pos, pt, WHITE);
    }
    else if (strcmp(prop_name[prop], "KM") == 0)
        board_set_komi(game->pos, atof(yytext));
    else if (strcmp(prop_name[prop], "SZ") == 0) {
        if (is_game_board_empty(game)) { 
            board_set_size(game->pos, atoi(yytext));
            game_clear_board(game);
        }
        else {
            // Can happen if SZ occurs after AB or AW
            Point    bstones[BOARDSIZE], wstones[BOARDSIZE];
            Position *pos=game->pos;

            slist_clear(bstones); slist_clear(wstones);
            slist_append(bstones, game->placed_black_stones);
            slist_append(wstones, game->placed_white_stones);

            board_set_size(game->pos, atoi(yytext));
            game_clear_board(game);
            
            FORALL_IN_SLIST(bstones, pt) {
                board_set_color_to_play(pos, BLACK);
                play_move(pos, pt);
                slist_push(game->placed_black_stones, pt);
            }
            FORALL_IN_SLIST(wstones, pt) {
                board_set_color_to_play(pos, WHITE);
                play_move(pos, pt);
                slist_push(game->placed_white_stones, pt);
            }
        }
Ejemplo n.º 23
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 =)
}