Example #1
0
int main(int argc, char * argv[]){
    Board * board;
    int x, y;
    Pos pos;
    UCTNode * uct_tree = 0;
    UCTNode * ptr;

    board_initialize();
    uct_initialize();

    board = board_new();

    while(1) {
        board_print(board, stdout);
        printf("\nBlack: ");
        if(scanf("%d %d", &x, &y) == -1)
            break;
        board_play(board, to_pos(x, y), BLACK);

        board_print(board, stdout);
        pos = uct_search(board, WHITE);
        board_play(board, pos, WHITE);
    }

    //for(ptr = uct_tree->child; ptr; ptr = ptr->next)
    //    printf("%d ", ptr->move);

    puts("");

    board_destroy();
    uct_destroy();
    return 0;
}
Example #2
0
File: main.c Project: iruel01/2048
int main(int argc, char* argv[]) {
	struct board board;
	char input[1024];
	int status; // Game status.
	int valid;

	// Print legal shenanigains.
	printf("\t2048 (implemented in C)  Copyright (C) 2014  Wade T. Cline\n"
	       "\tThis program comes with ABSOLUTELY NO WARRANTY. This is\n"
	       "\tfree software, and you are welcome to redistribute it\n"
	       "\tunder certain conditions. See the file 'COPYING' in the\n"
	       "\tsource code for details.\n\n");

	// Set up board.
	board_init(&board);
	
	// Play the game.
	while (!(status = board_done(&board))) {
		// Print the board.
		board_print(&board);

		// Get the player's move.
		valid = 0;
		memset((void*)input, 0, sizeof(input));
		write(STDOUT_FILENO, (void*)"> ", 3);
		if (read(STDIN_FILENO, (void*)input, sizeof(input) - 1)
		    == -1) {
			perror("Error reading input");
			break;
		}
		input[strlen(input) - 1] = 0;
		if (!strcmp(input, "u") || !strcmp(input, "up")) {
			valid = board_move_up(&board);
		} else if (!strcmp(input, "d") || !strcmp(input, "down")) {
			valid = board_move_down(&board);
		} else if (!strcmp(input, "l") || !strcmp(input, "left")) {
			valid = board_move_left(&board);
		} else if (!strcmp(input, "r") || !strcmp(input, "right")) {
			valid = board_move_right(&board);
		} else {
			printf("Don't understand input: %s.\n", input);
			continue;
		}

		// Prepare for user's next move.
		if (valid) {
			board_plop(&board);
		} else {
			printf("Invalid move.\n");
		}
	}
	
	// Print the final board.
	printf("Game over, you %s!", (status < 0) ? "LOSE" : "WIN");
	board_print(&board);

	// Return success.
	return EXIT_SUCCESS;
}
Example #3
0
static int ascii_recorder (recorder_t* rec, position_t pos, bool passed, bool end)
{
    assert (rec != NULL);

    const board_t* board = rec->board;

    if (end)
    {
        fprintf (rec->file, "end of game\n");
        // TODO: print score
    }
    else
    {
        if (passed)
        {
            fprintf (rec->file, "%s: passed\n",
                     board->turn == c_white ? "black" : "white");
        }
        else
        {
            fprintf (rec->file, "%s: %zu-%zu:\n",
                     board->turn == c_white ? "black" : "white", pos.x, pos.y);
            board_print (board, rec->file);
        }

        fprintf (rec->file, "\n");
    }

    return 0;
}
Example #4
0
int main()
{
    Board b;
    GroupInfo gi;
    /* FILE *fp; */

    /* TODO: test with more boards */
    board_decode_short(&b, board_desc);
    board_print(&b, stdout);
    analysis_initialize();
    analysis_identify_groups(&b, &gi);
    analysis_nim_values(&b, &gi);
    printf("%.3fs\n", (double)clock()/CLOCKS_PER_SEC);
    /*
    fp = fopen("memo55.dat", "wb");
    if (fp != NULL)
    {
        int n;
        for (n = 0; n < (1<<25); ++n) fputc(memo[n^((1<<25)-1)], fp);
        fclose(fp);
        printf("memo dumped to memo55.dat\n");
    }
    */
    if (gi.nval[0] != nval)
    {
        printf("Expected nim-value %d, computed %d!\n", nval, gi.nval[0]);
    }
    debug_cache_info();
    return 0;
}
Example #5
0
static coord_t *
replay_genmove(struct engine *e, struct board *b, struct time_info *ti, enum stone color, bool pass_all_alive)
{
	struct replay *r = e->data;
	struct playout_setup s; memset(&s, 0, sizeof(s));

	coord_t coord = r->playout->choose(r->playout, &s, b, color);

	if (!is_pass(coord)) {
		struct move m;
		m.coord = coord; m.color = color;
		if (board_play(b, &m) >= 0)
			goto have_move;

		if (DEBUGL(2)) {
			fprintf(stderr, "Pre-picked move %d,%d is ILLEGAL:\n",
				coord_x(coord, b), coord_y(coord, b));
			board_print(b, stderr);
		}
	}

	/* Defer to uniformly random move choice. */
	board_play_random(b, color, &coord, (ppr_permit) r->playout->permit, r->playout);

have_move:
	if (!group_at(b, coord)) {
		/* This was suicide. Just pass. */
		/* XXX: We should check for non-suicide alternatives. */
		return coord_pass();
	}

	return coord_copy(coord);
}
Example #6
0
File: test.c Project: mkghub/pachi
static void
board_print_test(int level, struct board *b)
{
	if (!DEBUGL(level) || board_printed)
		return;
	board_print(b, stderr);
	board_printed = true;
}
Example #7
0
File: main.c Project: fenglyu/c2048
int main(int argc, char **argv) {
    int seed = time(NULL);
    //seed = 1394569404;
    //printf("Random seed: %d\n", seed);
    srand(seed);

    printf("%d %d %d\n", LSB(0x11), MSB(0x11), PopCnt(0xFFFF));

    precalc_init();

    if (argc == 2) {
        if (0 == strcmp(argv[1], "--human")) {
            board_t board = board_init();

            while (1) {
                board_print(board);

                printf("[hjkl] ");
                char key = getchar();
                getchar(); // eat newline

                if (key == 'k') {
                    board_move(&board, MOVE_UP);
                }
                else if (key == 'l') {
                    board_move(&board, MOVE_RIGHT);
                }
                else if (key == 'j') {
                    board_move(&board, MOVE_DOWN);
                }
                else if (key == 'h') {
                    board_move(&board, MOVE_LEFT);
                }
            }
        }
        else if (0 == strcmp(argv[1], "--test")) {
            test_status = DOING_TESTS; // disable board_fill_random_cell
            test_run_testcases();
            test_status = NOT_DOING_TESTS;
        }
        else if (0 == strcmp(argv[1], "--ai")) {
            ai_loop();
        }
        else {
            interface_main(argv[1]);
        }
    }
    else {
        printf("c2048, compiled with AI_DEPTH=%d AI_NUM_TRIES=%d\n\n", AI_DEPTH, AI_NUM_TRIES);
        puts("--human  Play on the console, using hjkl to move around");
        puts("--test   Runs some testcases");
        puts("--ai     Runs infinitly many games in a row, while tracking stats (avg, max, nps, etc.)");
        return 1;
    }

    return 0;
}
Example #8
0
File: flip.c Project: CPonty/Flip
void play (gameType * game) {
    /*
        Gameplay loop
    */
    
    board_print(&game->board);
    while (1) {
        turn_decision(game);
    }
}
Example #9
0
bool test_generator(const unsigned long long flipped, const unsigned long long P, const unsigned long long O, const int x0)
{
	if (flipped != flip_slow(P, O, x0)) {
		Board b[1];
		char s[3] = "--";
		b->player = P; b->opponent = O;
		board_print(b, BLACK, stderr);
		fprintf(stderr, "move wrong : %s\n", move_to_string(x0, BLACK, s));
		bitboard_write(flipped, stderr);
		return true;
	}
	return false;
}
Example #10
0
static void
cmd_printboard(void)
{
    char str[BOARD_BUFFER_LENGTH];

    mtx_lock(&game_mutex);

    (void) board_print(str, current_position(), turn());

    mtx_unlock(&game_mutex);

    (void) fputs(str, stdout);
}
Example #11
0
File: chess.c Project: ia0/lbmgs
static int
chess_join(int cid, void *data)
{
	struct chess *chess = data;
	int pid;

	assert(valid_cid(cid));
	assert(chess != NULL);

	chess->ids[1] = cid;
	pid = chess->ids[0];

	cprintf(pid, "\n");
	board_print(pid, data);
	cprintf(pid, "This is your turn to play.\n");
	cprompt(pid);

	board_print(cid, data);
	cprintf(cid, "You play black.\n");
	cprintf(cid, "Wait for white to play.\n");

	return 1;
}
Example #12
0
/**
 * @brief ui_ggs_join
 *
 * Join a new game.
 * This is a new game from Edax point of view.
 * This may be a saved game from GGS side.
 *
 * @param ui User Interface.
 */
static void ui_ggs_join(UI *ui) {
	char buffer[256];
	char s_move[4];
	Play *play;
	int edax_turn, i;
	
	printf("[received GGS_BOARD_JOIN]\n");

	// set correct played game
	if (strcmp(ui->ggs->board->player[0].name, ui->ggs->me) == 0) {
		play = ui->play;
		edax_turn = BLACK;
	} else if (strcmp(ui->ggs->board->player[1].name, ui->ggs->me) == 0) {
		play = ui->play + 1;
		edax_turn = WHITE;
	} else {
		warn("Edax is not concerned by this game\n");
		return ;
	}

	// non synchro games => play a single match
	if (!ui->ggs->board->match_type->is_synchro) play = ui->play;

	// set board
	sprintf(buffer, "%s %c", ui->ggs->board->board_init, ui->ggs->board->turn_init);
	play_set_board(play, buffer);

	for (i = 0; i < ui->ggs->board->move_list_n; i++) {
		if (!play_move(play, ui->ggs->board->move_list[i])) {
			error("cannot play GGS move %s ?", move_to_string(ui->ggs->board->move_list[i], play->player, s_move));
			break;
		}
	}
	printf("[%s's turn in game %s]\n", ui->ggs->board->player[play->player].name, ui->ggs->board->id);
	board_print(play->board, play->player, stdout);

	ui->is_same_play = (ui->ggs->board->move_list_n == 0 || board_equal(ui->play[0].board, ui->play[1].board) || !ui->ggs->board->match_type->is_synchro);
	if (ui->is_same_play) printf("[Playing same game]\n");

	// set time & start thinking
	if (play->player == edax_turn) {
		printf("<My turn>\n");
		ggs_client_send(ui->ggs, "tell .%s =====================================\n", ui->ggs->me);
		ui_ggs_play(ui, edax_turn);
		ui_ggs_ponder(ui, edax_turn);
	} else {
		printf("[Waiting opponent move]\n");
//		ui_ggs_ponder(ui, edax_turn);
	}
}
Example #13
0
void perft_test(char *fen, unsigned long long *expected, int count) {
    Board board;
    board_load_fen(&board, fen);
    board_print(&board);
    double start = now();
    for (int depth = 0; depth < count; depth++) {
        hits = 0;
        unsigned long long actual = perft(&board, depth);
        char *result = actual == expected[depth] ? "PASS" : "FAIL";
        double elapsed = now() - start;
        printf("%s: depth = %2d, time = %.3f, expected = %12llu, actual = %12llu, hits = %g%%\n",
            result, depth, elapsed, expected[depth], actual, 100.0 * hits / actual);
    }
    printf("\n");
}
Example #14
0
File: main.c Project: clinew/2048
/**
 * Print the game screen to 'stdout'.
 */
void screen_print(struct board* board, char* message, int format) {
	if (format) {
		// Clear display and put cursor at 0,0.
		printf("\33[2J\33[H");

		// Print legal shenanigans.
		fputs(legal, stdout);
	}
	printf("\n");
	board_print(board);
	if (message) {
		printf("%s", message);
	}
	printf("> ");
	fflush(stdout);
}
Example #15
0
File: flip.c Project: CPonty/Flip
void ai_turn (int playerType, gameType * game) {
    /*
        Parse through the valid moves using one of the AI types
     */
    int x, y, dy, size;
    size = (game->validMove).n;
    
    /* Choose an AI search pattern */
    if (playerType == 1) {
        x = 0;
        y = 0;
        dy = 1;
    } else {
        x = size-1;
        y = size-1;
        dy = -1;
    }
    
    /* Find an available position */
    while (1) {
        /* is this position a valid move? */
        if ((game->validMove).s[x][y] == game->whoseTurn) {
            break;
        }
        y += dy;
        /* walked off ends of board - wrap around */
        if ((y < 0)) {
            y = size-1;
            x--;
        } else if (y >= size) {
            y = 0;
            x++;
        }
        /* walked off top/bottom of board - suspend; debug problem */
        if ((x < 0) || (x >= size)) {
            sysMessage(0, game);
        }
    }
    /* Place tile, display & prepare for the next player */
    game_put_tile(x, y, game);
    printf("Player %c moves at %d %d.\n", game->whoseTurn, x, y);
    board_print(&game->board);
    game_next_player(game);
    game->passes = 0;
}
Example #16
0
File: game.c Project: Egomeh/BA2015
/**
 * @brief Prints a human-readable view of the current state in a file.
 *
 * The current piece, a view of the board and the game score are printed.
 *
 * @param out file to write, e.g. stdout
 * @param game the game
 */
void game_print(FILE *out, Game *game) {
  /* print the game pieces 
     int i;
     fprintf(out, "Game pieces:\n");
     for (i = 0; i < game->nb_pieces; i++) {
     fprintf(out, "  Piece %d\n", i);
     print_piece_orientations(out, &game->pieces[i]);
     fprintf(out, "\n");
     }
  */

  fprintf(out, "Current piece:\n");
  piece_print(out, game->current_piece); 
  board_print(out, game->board);
   
/*   print_last_move_info(out, &game->last_move_info); */
  fprintf(out, "Game score: %d\n", game->score);
}
Example #17
0
void board_hash_table_print(board_hash_table_t *table)
{
    uint32_t i;

    if(table == NULL)
        return;

    for(i = 0; i < table->size; i++) {
        board_list_t *cur;

        for(cur = table->data[i];
            cur != NULL;
            cur = cur->next)
        {
            board_print(cur->item);
        }
    }

}
Example #18
0
int main(int argc, char *argv[])
{
    Board board;
    Rect moves1[MAX_MOVES], moves2[MAX_MOVES];
    int values1[MAX_MOVES], values2[MAX_MOVES];
    int num_moves1, num_moves2;
    int n;
    char buf[5];

    analysis_initialize();
    time_initialize(60.0);

    if (argc != 2)
    {
        printf("Usage: analyze-board <board>\n");
        exit(1);
    }

    if ( !board_decode_full(&board, argv[1]) &&
        !board_decode_short(&board, argv[1]) )
    {
        printf("Could not decode board description\n");
        exit(1);
    }

    printf("Board:\n");
    board_print(&board, stdout);

    num_moves1 = analysis_value_moves_normal(&board, moves1, values1);
    num_moves2 = analysis_value_moves_misere(&board, moves2, values2);
    assert(num_moves2 == -1 || num_moves1 == num_moves2);

    printf("Winning moves:\n");
    for (n = 0; n < num_moves1; ++n)
    {
        rect_encode(&moves1[n], buf);
        if (values1[n] <= 0 && values2[n] <= 0) continue;
        printf("%2d. %s %3d %3d\n", n + 1, buf, values1[n], values2[n]);
    }

    return 0;
}
Example #19
0
File: flip.c Project: CPonty/Flip
void player_try_move (int x, int y, gameType * game) {
    /*
        Check if a player's choice is available and execute
    */
    
    /* Check position is within board */
    if ( (x > (game->board).n-1) || (y > (game->board).n-1) ) {
        return;
    }
    
    /* Check position is a valid move */
    if ( (game->validMove).s[x][y] != game->whoseTurn ) {
        return;
    }
        
    /* Place tile, display & prepare for the next player */
    game_put_tile(x, y, game);
    board_print(&game->board);
    game_next_player(game);
    game->passes = 0;
}
Example #20
0
File: test.c Project: 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 =)
}
Example #21
0
int play_game( KalahPlayer top, KalahPlayer bottom, PlayerPosition first_player )
{
	Board b_data;
	Board *b = &b_data;  // as shorthand

	board_initialize( b, first_player );

	if ( first_player == TOP )
		printf( "Player %s begins.\n", top.get_name() );
	else
		printf( "Player %s begins.\n", bottom.get_name() );

	while ( !board_game_over( b ) )
	{
		int move;

		board_print( b );		
		printf( "\n" );

		if ( b->player_to_move == TOP )
		{			
			move = top.make_move( b );
			printf( "TOP (%s) chooses move %d.\n", top.get_name(), move );
		}
		else
		{
			move = bottom.make_move( b );
			printf( "BOTTOM (%s) chooses move %d.\n", bottom.get_name(), move );
		}

		board_make_move( b, move );

		if ( board_game_over( b ) )
		{
			if ( board_winner( b ) == TOP )
			{
				printf( "TOP (%s) wins, %d to %d.\n", 
						top.get_name(),
						board_top_score( b ),
						board_bottom_score( b ) );
			}
			else if ( board_winner( b ) == BOTTOM )
			{
				printf( "BOTTOM (%s) wins, %d to %d.\n", 
						bottom.get_name(),
						board_bottom_score( b ),
						board_top_score( b ) );
			}
			else
			{
				printf( "TIE!\n" );
			}
		}
		else
		{
			if ( b->player_to_move == TOP )
				printf( "TOP (%s) to move.\n", top.get_name() );
			else
				printf( "BOTTOM (%s) to move.\n", bottom.get_name() );
		}
	}

	return board_top_score( b );
}
Example #22
0
File: test.c Project: 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);
}
Example #23
0
File: test.c Project: 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 =)
}
Example #24
0
static void
record_local_sequence(struct uct *u, struct tree *t, struct board *endb,
                      struct uct_descent *descent, int dlen, int di,
		      enum stone seq_color)
{
#define LTREE_DEBUG if (UDEBUGL(6))

	/* Ignore pass sequences. */
	if (is_pass(node_coord(descent[di].node)))
		return;

	LTREE_DEBUG board_print(endb, stderr);
	LTREE_DEBUG fprintf(stderr, "recording local %s sequence: ",
		stone2str(seq_color));

	/* Sequences starting deeper are less relevant in general. */
	int pval = LTREE_PLAYOUTS_MULTIPLIER;
	if (u->local_tree && u->local_tree_depth_decay > 0)
		pval = ((floating_t) pval) / pow(u->local_tree_depth_decay, di - 1);
	if (!pval) {
		LTREE_DEBUG fprintf(stderr, "too deep @%d\n", di);
		return;
	}

	/* Pick the right local tree root... */
	struct tree_node *lnode = seq_color == S_BLACK ? t->ltree_black : t->ltree_white;
	lnode->u.playouts++;

	double sval = 0.5;
	if (u->local_tree_rootgoal) {
		sval = local_value(u, endb, node_coord(descent[di].node), seq_color);
		LTREE_DEBUG fprintf(stderr, "(goal %s[%s %1.3f][%d]) ",
			coord2sstr(node_coord(descent[di].node), t->board),
			stone2str(seq_color), sval, descent[di].node->d);
	}

	/* ...and record the sequence. */
	int di0 = di;
	while (di < dlen && (di == di0 || descent[di].node->d < u->tenuki_d)) {
		enum stone color = (di - di0) % 2 ? stone_other(seq_color) : seq_color;
		double rval;
		if (u->local_tree_rootgoal)
			rval = sval;
		else
			rval = local_value(u, endb, node_coord(descent[di].node), color);
		LTREE_DEBUG fprintf(stderr, "%s[%s %1.3f][%d] ",
			coord2sstr(node_coord(descent[di].node), t->board),
			stone2str(color), rval, descent[di].node->d);
		lnode = tree_get_node(t, lnode, node_coord(descent[di++].node), true);
		assert(lnode);
		stats_add_result(&lnode->u, rval, pval);
	}

	/* Add lnode for tenuki (pass) if we descended further. */
	if (di < dlen) {
		double rval = u->local_tree_rootgoal ? sval : 0.5;
		LTREE_DEBUG fprintf(stderr, "pass ");
		lnode = tree_get_node(t, lnode, pass, true);
		assert(lnode);
		stats_add_result(&lnode->u, rval, pval);
	}
	
	LTREE_DEBUG fprintf(stderr, "\n");
}
Example #25
0
File: main.c Project: Octoate/2048
main() {
	struct board board;
	unsigned char input;
	int status; // Game status.
	int valid;
	unsigned char idx;
	
	initGraphics();
	
	//PutSpriteMode0((void*)boardnumber[2], 0, 0, BOARDNUMBER_WIDTH, BOARDNUMBER_HEIGHT);
	
	//for (idx = 0; idx < 10; idx++)
	//{
		//PutSpriteMode0((void*)number[idx], idx * NUMBER_WIDTH, BOARDNUMBER_HEIGHT + 1, NUMBER_WIDTH, NUMBER_HEIGHT);
	//}
	//GetChar_CPC();
	
	// Print legal shenanigains.
	//printf("\t2048 (implemented in C)  Copyright (C) 2014  Wade T. Cline\r\n"
	//       "\tThis program comes with ABSOLUTELY NO WARRANTY. This is\r\n"
	//       "\tfree software, and you are welcome to redistribute it\r\n"
	//       "\tunder certain conditions. See the file 'COPYING' in the\r\n"
	//       "\tsource code for details.\r\n\r\n");

	// Set up board.
	board_init(&board);
	
	
	// Play the game.
	while (!(status = board_done(&board))) {
		// Print the board.
		//printf("Score: %u \r\n", score);
		board_print(&board);

		// Get the player's move.
		valid = 0;
		input = GetChar_CPC();
		
		switch (input)
		{
			case 0x0B:	//Joystick up
			case 0x51:	//Q
			case 0x71:	//q
			case 0xF0:	//Up
				valid = board_move_up(&board);
				break;
			
			case 0x0A:	//Joystick down
			case 0x41:	//A
			case 0x61:	//a
			case 0xF1:	//Down
				valid = board_move_down(&board);
				break;
				
			case 0x08:	//Joystick left
			case 0x4F:	//O
			case 0x6F:	//o
			case 0xF2:	//Left
				valid = board_move_left(&board);
				break;
				
			case 0xFD:	//Joystick right
			case 0x50:	//P
			case 0x70:	//p
			case 0xF3:	//Right
				valid = board_move_right(&board);
				break;
			default:
				//printf("Don't understand input: 0x%x.\r\n", input);
				continue;
		}

		// Prepare for user's next move.
		if (valid) {
			board_plop(&board);
		} else {
			//printf("Invalid move.\r\n");
		}
	}
	
	// Print the final board.
	//printf("Game over, you %s!\r\n", (status < 0) ? "LOSE" : "WIN");
	board_print(&board);

	// Return success.
	return 0;
}
Example #26
0
int __cdecl main(int argc, char **argv) 
{
	gs_ip = "127.0.0.1";
	gs_port = "27017";


    WSADATA wsaData;
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    char sendbuf[500];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;
    
    // Validate the parameters
   /* if (argc != 2) {
        printf("usage: %s server-name\n", argv[0]);
        return 1;
    }*/

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address until one succeeds
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }
 	
	// Send an settings request
    iResult = send( ConnectSocket, "\0", 1, 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

	iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);

	HANDLE thread_gs_listener = CreateThread(NULL, 0, gs_listener, (void *)ConnectSocket, 0, NULL);

	M = recvbuf[0];
	N = recvbuf[1];
	gamerooms[0].board = malloc(sizeof(char)*M*M);
	gamerooms[0].board_lifespan = malloc(sizeof(char)*M*M);
	gamerooms[0].players = malloc(sizeof(PLAYER)*512);
	gamerooms[0].canmove = 0;
	gamerooms[0].playersnum = 1;
	gamerooms[0].players[0].mark = 'A';
	printf("settings:\nM=%d\nN=%d\n\n",M,N);
	//M=3,N=3;

	unsigned char Y, X;

	//first come, fist served
	u_long iMode = 0; //change to 1 to turn on non-blocking mode
	//scanf("%hhu%hhu",&Y,&X);
	//check if opponent moved faster
	ioctlsocket(ConnectSocket, FIONBIO, &iMode);

	char input[256];
//Sleep(2000);
    while(gs_alive){
		gets(input);
		switch(input[0]){
			case 'm': //change gameroom
				sscanf(input, "%*s %hhu", &Y);
				sprintf(sendbuf, "\2%c", Y);
				send(ConnectSocket, sendbuf, 2, 0);
				break;
			default: //move
				sscanf(input, "%hhu%hhu", &Y, &X);
				if(Y<M && X<M && gamerooms[0].canmove==client_id && gamerooms[0].board[Y*M+X]==0){
					sprintf(sendbuf,"%c%c%c",'\1',Y,X);
					send( ConnectSocket, sendbuf, 3, 0 );
					gamerooms[0].board[Y*M+X] = gamerooms[0].players[client_id].mark;
					board_print();
				}else printf("Couldnt move to %d %d, try once again\n", Y, X);
				break;
		}
    }

   

    //printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }
 // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}
Example #27
0
int main(void)
{
	Color computer_player = -1; // not WHITE or BLACK if we don't play either (e.g. -1)
	int game_on = 0;
	Bitboard *board = malloc(sizeof(Bitboard));
	Undo *u = NULL;
	char* input = malloc(sizeof(char) * max_input_length);
	Move last_move = 0;
	int got_move = 0;

	freopen("/dev/tty", "w", stderr);
	setbuf(stderr, NULL);
	setbuf(stdout, NULL);

	srandom(time(NULL));

	while (1)
	{
		if (game_on && got_move)
		{
			u = malloc(sizeof(Undo));
			board_do_move(board, last_move, u);
			got_move = 0;
		}

		if (game_on && computer_player == board->to_move)
		{
			last_move = search_find_move(board);
			move_srcdest_form(last_move, input);
			printf("move %s\n", input);
			u = malloc(sizeof(Undo));
			board_do_move(board, last_move, u);
		}

		fgets(input, max_input_length, stdin);
		fprintf(stderr, "%s", input);

		if (!strcmp("xboard\n", input))
			printf("feature colors=0 setboard=1 time=0 sigint=0 sigterm=0 variants=\"normal\" done=1\n");
		else if (!strcmp("new\n", input))
		{
			board_free_undos(u);
			board_init(board);
			computer_player = BLACK;
			game_on = 1;
		}
		else if (!strcmp("quit\n", input))
			break;
		else if (!strcmp("force\n", input))
			computer_player = -1;
		else if (!strcmp("go\n", input))
			computer_player = board->to_move;
		else if (!strncmp("setboard ", input, 9))
			board_init_with_fen(board, input + 9);
		else if (!strncmp("result", input, 6))
		{
			computer_player = -1;
			game_on = 0;
		}
		else if (!strncmp("level ", input, 6))
			timer_init(input);
		else if (!strcmp("_print\n", input))
		{
			board_print(board);
			printf("Evaluation: %i\n", evaluate_board(board));
			puts("Pseudolegal moves: ");

			Movelist all_moves;
			move_generate_movelist(board, &all_moves);

			Moveiter it;
			moveiter_init(&it, &all_moves, MOVEITER_SORT_NONE, MOVE_NULL);

			char srcdest_form[6];
			while (moveiter_has_next(&it))
			{
				Move m = moveiter_next(&it);
				move_srcdest_form(m, srcdest_form);
				printf("%s ", srcdest_form);
			}
			puts("\n");
		}
		else if (input[0] >= 'a' && input[0] <= 'h'
				&& input[1] >= '1' && input[1] <= '8'
				&& input[2] >= 'a' && input[2] <= 'h'
				&& input[3] >= '1' && input[3] <= '8')
		{
			last_move = parse_move(board, input);
			if (!last_move)
				printf("Illegal move: %s", input);
			else
				got_move = 1;
		}
		else
			printf("Error (unknown command): %s", input);
	}

	free(board);
	free(input);
	return 0;
}
Example #28
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;
}
Example #29
0
/*thread responsible for receiving data*/
DWORD WINAPI gs_listener(void *data){
	int iResult;
	int iSendResult;
	int recvbuflen;

	SOCKET ConnectSocket2 = (SOCKET)data; //////////////////////////////////////doesnt work?!!!

	/*receive until connection closure*/
	while(1){
		//if(ConnectSocket2==ConnectSocket) printf("yes"); //!!!!!!!!!!!!prints "yes"
		//else printf("no");
		//Sleep(500);
		//to solve this:
		//1. move this swtich to main()
		//2. use non-blocking mode
		//3. use this thread to pass input to global buffor
		//4. read in main() from global buffor and send it from there
		//5. now both sending and receiving works
		//OR SIMPLY
		//somehow make this thread to be able to use this socket
		iResult = recv(ConnectSocket2, recvbuf, recvbuflen, 0);
		if(iResult>0){
			switch(recvbuf[0]){
				case 0x00:
					printf("Couldnt move to %d %d, try once again.\n", recvbuf[1], recvbuf[2]);
					break;
				case 0x01:
					printf("Player %d has made a move.\n", gamerooms[0].canmove);
					gamerooms[0].board[recvbuf[1]*M+recvbuf[2]] = gamerooms[0].players[gamerooms[0].canmove].mark;
					gamerooms[0].canmove = (gamerooms[0].canmove+1)%gamerooms[0].playersnum;
					board_print();
					dead_marks_delete(recvbuf);
					board_print();
					break;
				case 0x02:
					printf("Player %d got a point.\n", gamerooms[0].canmove);
					gamerooms[0].board[recvbuf[1]*M+recvbuf[2]] = gamerooms[0].players[gamerooms[0].canmove].mark;
					++gamerooms[0].players[gamerooms[0].canmove].points;
					gamerooms[0].canmove = (gamerooms[0].canmove+1)%gamerooms[0].playersnum;
					board_print();
					dead_marks_delete(recvbuf);
					board_print();
					break;
				case 0x06:
					printf("A new player has connected to the gameroom.\n");
					newplayer_get(recvbuf);
					break;
				case 0x07:
					printf("Connected to a new gameroom!\n");
					gameroom_get(recvbuf);
					break;
				case 0x08:
					printf("Player %d has disconnected.\n", recvbuf[1]);
					player_remove(0, recvbuf[1]);
					break;
				case 0x09:
					printf("Couldn't move to %d gameroom.\n", recvbuf[1]);
					break;
				default: break;
			}
		}else{
			printf("\n\nconnection error\n");
			break;
		}//else printf("socket failed with error: %ld\n", WSAGetLastError());
	}

	gs_alive = 0;
	/* cleanup will be handled by main() */
	return 0;
}
Example #30
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;
}