1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
//-----------------------------------------------------------------------------
/** @file twogtp/Output.cpp
@author Markus Enzenberger
@copyright GNU General Public License version 3 or later */
//-----------------------------------------------------------------------------
#include "Output.h"
#include <cstdio>
#include <fstream>
#include <iomanip>
#include <fcntl.h>
#include <unistd.h>
#include <sys/file.h>
#include "libboardgame_base/StringUtil.h"
using libboardgame_base::from_string;
using libboardgame_base::split;
using libboardgame_base::trim;
//-----------------------------------------------------------------------------
Output::Output(Variant variant, const string& prefix, bool create_tree)
: m_create_tree(create_tree),
m_prefix(prefix),
m_output_tree(variant)
{
m_lock_fd = creat((prefix + ".lock").c_str(), 0644);
if (m_lock_fd == -1)
throw runtime_error("Output: could not create lock file");
if (flock(m_lock_fd, LOCK_EX | LOCK_NB) == -1)
throw runtime_error("Output: twogtp already running");
m_timer.reset(m_time_source);
ifstream in(prefix + ".dat");
if (! in)
return;
string line;
while (getline(in, line))
{
line = trim(line);
if (! line.empty() && line[0] == '#')
continue;
auto columns = split(line, '\t');
if (columns.empty())
continue;
unsigned game_number;
if (! from_string(columns[0], game_number))
throw runtime_error("Output: expected game number");
m_games.insert({game_number, line});
}
while (m_games.count(m_next) != 0)
++m_next;
if (check_sentinel())
remove((prefix + ".stop").c_str());
if (m_create_tree && m_next > 0)
m_output_tree.load(prefix + "-tree.blksgf");
}
Output::~Output()
{
save();
flock(m_lock_fd, LOCK_UN);
close(m_lock_fd);
remove((m_prefix + ".lock").c_str());
}
void Output::add_result(unsigned n, float result, const Board& bd,
unsigned player_black, double cpu_black,
double cpu_white, const string& sgf,
const array<bool, Board::max_moves>& is_real_move)
{
{
lock_guard lock(m_mutex);
unsigned nu_fast_open = 0;
for (unsigned i = 0; i < bd.get_nu_moves(); ++i)
if (! is_real_move[i])
++nu_fast_open;
ostringstream line;
line << n << '\t'
<< setprecision(4) << result << '\t'
<< bd.get_nu_moves() << '\t'
<< player_black << '\t'
<< setprecision(5) << cpu_black << '\t'
<< cpu_white << '\t'
<< nu_fast_open;
m_games.insert({n, line.str()});
m_sgf_buffer << sgf;
if (m_create_tree)
m_output_tree.add_game(bd, player_black, result, is_real_move);
}
if (m_timer() > m_save_interval)
{
save();
m_timer.reset();
}
}
bool Output::check_sentinel()
{
return ! ifstream(m_prefix + ".stop").fail();
}
bool Output::generate_fast_open_move(bool is_player_black, const Board& bd,
Color to_play, Move& mv)
{
lock_guard lock(m_mutex);
m_output_tree.generate_move(is_player_black, bd, to_play, mv);
return ! mv.is_null();
}
unsigned Output::get_next()
{
lock_guard lock(m_mutex);
unsigned n = m_next;
do
++m_next;
while (m_games.count(m_next) != 0);
return n;
}
void Output::save()
{
lock_guard lock(m_mutex);
{
ofstream out(m_prefix + ".dat");
out << "# Game\tResult\tLength\tPlayerB\tCpuB\tCpuW\tFast\n";
for (auto& i : m_games)
out << i.second << '\n';
}
{
ofstream out(m_prefix + ".blksgf", ios::app);
out << m_sgf_buffer.str();
m_sgf_buffer.str("");
}
if (m_create_tree)
m_output_tree.save(m_prefix + "-tree.blksgf");
}
//-----------------------------------------------------------------------------
|