1 //-----------------------------------------------------------------------------
2 /** @file pentobi_gtp/Main.cpp
3     @author Markus Enzenberger
4     @copyright GNU General Public License version 3 or later */
5 //-----------------------------------------------------------------------------
6 
7 #include <fstream>
8 #include "GtpEngine.h"
9 #include "libboardgame_base/Log.h"
10 #include "libboardgame_base/Options.h"
11 #include "libboardgame_base/RandomGenerator.h"
12 
13 using namespace std;
14 using libboardgame_base::Options;
15 using libboardgame_base::RandomGenerator;
16 using libboardgame_gtp::Failure;
17 using libpentobi_base::parse_variant_id;
18 using libpentobi_base::Board;
19 using libpentobi_base::Variant;
20 using libpentobi_mcts::Player;
21 
22 //-----------------------------------------------------------------------------
23 
24 namespace {
25 
get_application_dir_path(int argc,char ** argv)26 string get_application_dir_path(int argc, char** argv)
27 {
28     if (argc == 0 || argv == nullptr || argv[0] == nullptr)
29         return "";
30     string application_path(argv[0]);
31 #ifdef _WIN32
32     auto pos = application_path.find_last_of("/\\");
33 #else
34     auto pos = application_path.find_last_of('/');
35 #endif
36     if (pos == string::npos)
37         return "";
38     return application_path.substr(0, pos);
39 }
40 
41 } // namespace
42 
43 //-----------------------------------------------------------------------------
44 
main(int argc,char ** argv)45 int main(int argc, char** argv)
46 {
47     libboardgame_base::LogInitializer log_initializer;
48     string application_dir_path = get_application_dir_path(argc, argv);
49     try
50     {
51         vector<string> specs = {
52             "book:",
53             "config|c:",
54             "color",
55             "cputime",
56             "game|g:",
57             "help|h",
58             "level|l:",
59             "nobook",
60             "noresign",
61             "quiet|q",
62             "seed|r:",
63             "showboard",
64             "threads:",
65             "version|v"
66         };
67         Options opt(argc, argv, specs);
68         if (opt.contains("help"))
69         {
70             cout <<
71                 "Usage: pentobi_gtp [options] [input files]\n"
72                 "--book       load an external book file\n"
73                 "--config,-c  set GTP config file\n"
74                 "--color      colorize text output of boards\n"
75                 "--cputime    use CPU time\n"
76                 "--game,-g    game variant (classic, classic_2, classic_3,\n"
77                 "             duo, trigon, trigon_2, trigon_3, junior)\n"
78                 "--help,-h    print help message and exit\n"
79                 "--level,-l   set playing strength level\n"
80                 "--seed,-r    set random seed\n"
81                 "--showboard  automatically write board to stderr after\n"
82                 "             changes\n"
83                 "--nobook     disable opening book\n"
84                 "--noresign   disable resign\n"
85                 "--quiet,-q   do not print logging messages\n"
86                 "--threads    number of threads in the search\n"
87                 "--version,-v print version and exit\n";
88             return 0;
89         }
90         if (opt.contains("version"))
91         {
92 #ifdef VERSION
93             cout << "Pentobi " << VERSION << '\n';
94 #else
95             cout << "Pentobi unknown version";
96 #endif
97             return 0;
98         }
99         unsigned threads = 1;
100         if (opt.contains("threads"))
101         {
102             threads = opt.get<unsigned>("threads");
103             if (threads == 0)
104                 throw runtime_error("Number of threads must be greater zero.");
105         }
106         Board::color_output = opt.contains("color");
107         if (opt.contains("quiet"))
108             libboardgame_base::disable_logging();
109         if (opt.contains("seed"))
110             RandomGenerator::set_global_seed(
111                         opt.get<RandomGenerator::ResultType>("seed"));
112         string variant_string = opt.get("game", "classic");
113         Variant variant;
114         if (! parse_variant_id(variant_string, variant))
115             throw runtime_error("invalid game variant " + variant_string);
116         auto level = opt.get<unsigned>("level", 4);
117         if (level < 1 || level > Player::max_supported_level)
118             throw runtime_error("invalid level");
119         auto use_book = (! opt.contains("nobook"));
120         const string& books_dir = application_dir_path;
121         GtpEngine engine(variant, level, use_book, books_dir, threads);
122         engine.set_resign(! opt.contains("noresign"));
123         if (opt.contains("showboard"))
124             engine.set_show_board(true);
125         if (opt.contains("cputime"))
126             engine.use_cpu_time(true);
127         string book_file = opt.get("book", "");
128         if (! book_file.empty())
129         {
130             ifstream in(book_file);
131             engine.get_mcts_player().load_book(in);
132         }
133         string config_file = opt.get("config", "");
134         if (! config_file.empty())
135         {
136             ifstream in(config_file);
137             if (! in)
138                 throw runtime_error("Error opening " + config_file);
139             engine.exec(in, true, libboardgame_base::get_log_stream());
140         }
141         auto& args = opt.get_args();
142         if (! args.empty())
143             for (auto& file : args)
144             {
145                 ifstream in(file);
146                 if (! in)
147                     throw runtime_error("Error opening " + file);
148                 engine.exec_main_loop(in, cout);
149             }
150         else
151             engine.exec_main_loop(cin, cout);
152         return 0;
153     }
154     catch (const Failure& e)
155     {
156         LIBBOARDGAME_LOG("Error: command in config file failed: ", e.what());
157         return 1;
158     }
159     catch (const exception& e)
160     {
161         LIBBOARDGAME_LOG("Error: ", e.what());
162         return 1;
163     }
164 }
165 
166 //-----------------------------------------------------------------------------
167