Exemple #1
0
extern "C" uint8_t* fastgo_extract_features(uint8_t* raw_board, int* output_length, int perspective_player) {
	assert(perspective_player == 1 or perspective_player == 2);
	// Copy all of the moves into a board.
	GoBoard board;
	for (int y = 0; y < BOARD_SIZE; y++) {
		for (int x = 0; x < BOARD_SIZE; x++) {
//			uint8_t piece = piece_at(*reinterpret_cast<std::array<Cell, BOARD_SIZE * BOARD_SIZE>*>(raw_board), {x, y});
			uint8_t piece = raw_board[x + y * BOARD_SIZE];
			assert(piece == 0 or piece == 1 or piece == 2);
			if (piece == 1 or piece == 2)
				board.place_stone((Player)piece, {x, y});
		}
	}
	// Get features out.
	string main_feature_block;
	filtering_ostream features_out(std::back_inserter(main_feature_block));
	write_features(features_out, board, (Player)perspective_player);
	features_out.flush();
	// Copy into a C-style array for returning.
	uint8_t* result = new uint8_t[main_feature_block.size()];
	std::copy(main_feature_block.begin(), main_feature_block.end(), result);
	*output_length = main_feature_block.size();
	return result;
}
Exemple #2
0
void write_all_samples(
	filtering_ostream& features_out,
	filtering_ostream& targets_out,
	filtering_ostream& winners_out,
	filtering_ostream& territory_out,
	string path
) {
#else
void write_all_samples(filtering_ostream& features_out, filtering_ostream& targets_out, filtering_ostream& winners_out, string path) {
#endif
	// Read in the SGF file.
	Game game;
	if (not parse_sgf(path, game))
		return;

	// If both players are too low rank then skip.
	if (game.white_rank < RANK_THRESHOLD and game.black_rank < RANK_THRESHOLD) {
//		cerr << "Both players too low rank: " << game.white_rank << " " << game.black_rank << endl;
		return;
	}

	// If just one player is too low rank then print a warning.
//	if (game.white_rank < RANK_THRESHOLD)
//		cerr << "White too low rank: " << game.white_rank << " " << game.black_rank << endl;
//	if (game.black_rank < RANK_THRESHOLD)
//		cerr << "Black too low rank: " << game.white_rank << " " << game.black_rank << endl;

#ifdef SCORING
	string final_territory_black = slurp_file(path + "-FINAL");
	assert(final_territory_black.size() == 361);

	string final_territory_white = final_territory_black;
	std::replace(final_territory_white.begin(), final_territory_white.end(), '\1', 'x');
	std::replace(final_territory_white.begin(), final_territory_white.end(), '\xff', '\1');
	std::replace(final_territory_white.begin(), final_territory_white.end(), 'x', '\xff');
#endif

	// Keep move histories in a pair of circular buffers.
	vector<vector<std::array<uint8_t, BOARD_SIZE * BOARD_SIZE>>> histories{{}, {}};
	vector<int> history_rotations{0, 0};
	std::array<uint8_t, BOARD_SIZE * BOARD_SIZE> blank_board{};
	for (int which_history = 0; which_history < 2; which_history++) {
		for (int i = 0; i < HISTORY_LENGTH; i++) {
			histories[which_history].push_back(blank_board);
			histories[which_history].push_back(blank_board);
		}
	}

	GoBoard board;
	std::array<uint8_t, BOARD_SIZE * BOARD_SIZE> one_hot_winning_move = {};

	std::uniform_int_distribution<int> uni(0, game.moves.size() - 1);
	int random_integer1 = uni(rng);
	int random_integer2 = uni(rng);

	for (int move_index = 0; move_index < game.moves.size(); move_index++) {
		Move& m = game.moves[move_index];

		bool do_write_this_move = true;
#ifdef SELECT_JUST_ONE_MOVE
		do_write_this_move = (move_index == random_integer1) or (move_index == random_integer2);
#endif
#ifdef SELF_PLAY
		do_write_this_move = (move_index > 0) and game.moves[move_index - 1].is_random_self_play_move;
#endif

		// Disable writing this move if the player is too low rank.
		if (m.who_moved == Player::BLACK and game.black_rank < RANK_THRESHOLD)
			do_write_this_move = false;
		if (m.who_moved == Player::WHITE and game.white_rank < RANK_THRESHOLD)
			do_write_this_move = false;

		// Currently we generate no samples on a pass.
		if (m.pass)
			continue;

		// Get out features for the board right BEFORE the move.
		if (do_write_this_move)
			write_features(features_out, board, m.who_moved);

		// If the current perspective player is WHITE then we grab the histories swapped.
		int who_moved_as_index = m.who_moved == Player::BLACK ? 0 : 1;

		// Order the histories to have the perspective player first.
		for (int which_history = 0; which_history < 2; which_history++) {
			auto& history = histories[(which_history + who_moved_as_index) % 2];
			int history_rotation = history_rotations[(which_history + who_moved_as_index) % 2];
			for (int i = 0; i < HISTORY_LENGTH; i++) {
				std::array<uint8_t, BOARD_SIZE * BOARD_SIZE>& entry = history[(i + history_rotation) % HISTORY_LENGTH];
				if (do_write_this_move)
					features_out.write(reinterpret_cast<const char*>(&entry[0]), BOARD_SIZE * BOARD_SIZE);
			}
		}

		// Write the winning move out.
		Cell& winning_move_cell = piece_at(one_hot_winning_move, m.xy);
		winning_move_cell = 1;
		if (do_write_this_move)
			targets_out.write(reinterpret_cast<const char*>(&one_hot_winning_move[0]), BOARD_SIZE * BOARD_SIZE);
		winning_move_cell = 0;

		// Write the winner of the game out.
		int our_komi = std::round(game.komi * 2);
		if (m.who_moved == Player::BLACK)
			our_komi = -our_komi;
		char game_winner[] = {0, 0, our_komi};
		if (game.who_won == m.who_moved) //Player::BLACK)
			game_winner[0] = 1;
		if (game.who_won == opponent_of(m.who_moved))//Player::WHITE)
			game_winner[1] = 1;
		if (do_write_this_move)
			winners_out.write(game_winner, 2);

#ifdef SCORING
		// Write a copy of this game's final territory out.
//		territory_out.write(final_territory, final_territory.size());
		if (m.who_moved == Player::BLACK) {
			territory_out << final_territory_black;
		} else if (m.who_moved == Player::WHITE) {
			territory_out << final_territory_white;
		} else {
			assert(false);
		}
#endif

		// Update the board.
		board.place_stone(m.who_moved, m.xy);

		// Insert into the history.
		int& history_rotation = history_rotations[who_moved_as_index];
		std::array<uint8_t, 361>& this_history_entry = histories[who_moved_as_index][history_rotation];
		this_history_entry = blank_board;
		piece_at(this_history_entry, m.xy) = 1;
		// Increment the rotation of the appropriate history entry.
		history_rotation = (history_rotation + 1) % HISTORY_LENGTH;
	}
}