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