2
gtp-rhino.cc GRhino GTP Frontend
3
Copyright (c) 2005, 2006 Kriang Lerdsuwanakij
4
email: lerdsuwa@users.sourceforge.net
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
#include <sys/types.h>
42
#include "alphabeta.h"
48
#include "randboard.h"
56
// Grab version number in VERSION variable
59
#include "scripts/version"
71
#define _(x) gettext(x)
74
const char *prog_name = "gtp-rhino";
75
const char *prog_ver = VERSION;
82
unsigned main_time = 0;
83
unsigned byo_yomi_time = 1;
84
unsigned byo_yomi_stones = 0;
86
bool use_byo_yomi = false;
87
unsigned time_left_black;
88
unsigned stone_left_black;
89
unsigned time_left_white;
90
unsigned stone_left_white;
92
// Implementation status (GTP version 2 draft 2)
93
// 2.1 done 2.2 done 2.3 done 2.4 done
94
// 2.5 done 2.6 done 2.7 done 2.8 done
95
// 2.9 done 2.10 done 2.11 N/A 2.12 done
96
// 2.13 done 2.14 done
97
// 3.1 done 3.2 done 3.3 done 3.4 done
99
// 4.1 N/A 4.2 4.3 done
100
// 5.1 5.2 done 5.3 done
103
void gtp_new_game(const byte_board_info *b = 0, int color = BLACK)
107
new_game(cur_game_info);
109
new_game(cur_game_info, *b, color);
113
use_byo_yomi = false;
114
time_left_black = main_time;
115
time_left_white = main_time;
118
void gtp_maybe_log_game()
120
if (!cur_game_info.is_game_play() && !game_logged) {
122
log_history("grhino.log", "player", "player");
126
typedef void (*gtp_func)(const std::string &, size_t i, bool has_id, unsigned id);
133
extern gtp_command gtp_commands[];
135
void gtpfunc_protocol_version(const std::string &/*str*/, size_t /*i*/,
136
bool has_id, unsigned id)
138
output_response("2", has_id, id);
141
void gtpfunc_name(const std::string &/*str*/, size_t /*i*/,
142
bool has_id, unsigned id)
144
output_response("GTP GRhino", has_id, id);
147
void gtpfunc_version(const std::string &/*str*/, size_t /*i*/,
148
bool has_id, unsigned id)
150
output_response(VERSION, has_id, id);
153
void gtpfunc_known_command(const std::string &str, size_t i,
154
bool has_id, unsigned id)
156
i = skip_space(str, i);
158
output_response("false", has_id, id);
160
size_t j = skip_non_space(str, i);
162
for (k = 0 ; gtp_commands[k].command; ++k) {
163
if (!str.compare(i, j-i, gtp_commands[k].command))
166
if (gtp_commands[k].command)
167
output_response("true", has_id, id);
169
output_response("false", has_id, id);
173
void gtpfunc_list_commands(const std::string &/*str*/, size_t /*i*/,
174
bool has_id, unsigned id)
177
for (int k = 0 ; gtp_commands[k].command; ++k) {
180
output += gtp_commands[k].command;
182
output_response(output, has_id, id);
185
void gtpfunc_quit(const std::string &/*str*/, size_t /*i*/,
186
bool has_id, unsigned id)
188
output_response("", has_id, id);
189
throw command_quit();
192
void gtpfunc_boardsize(const std::string &str, size_t i,
193
bool has_id, unsigned id)
195
i = skip_space(str, i);
196
throw_syntax_error_if_end_of_line(str, i);
199
i = read_unsigned(str, i, num);
200
throw_if_extra_argument(str, i);
203
output_error("unacceptable size", has_id, id);
205
output_response("", has_id, id);
208
void gtpfunc_clear_board(const std::string &/*str*/, size_t /*i*/,
209
bool has_id, unsigned id)
212
output_response("", has_id, id);
215
void gtpfunc_komi(const std::string &str, size_t i,
216
bool has_id, unsigned id)
218
i = skip_space(str, i);
219
throw_syntax_error_if_end_of_line(str, i);
220
i = read_float(str, i, komi);
221
throw_if_extra_argument(str, i);
222
output_response("", has_id, id);
225
void gtpfunc_play(const std::string &str, size_t i,
226
bool has_id, unsigned id)
228
i = skip_space(str, i);
229
throw_syntax_error_if_end_of_line(str, i);
232
i = read_color(str, i, color);
234
i = skip_space(str, i);
235
throw_syntax_error_if_end_of_line(str, i);
238
size_t j = skip_non_space(str, i);
240
throw syntax_error();
241
if (str[i] >= 'A' && str[i] <= 'H')
243
else if (str[i] >= 'a' && str[i] <= 'h')
246
throw syntax_error();
248
if (str[i+1] >= '1' && str[i+1] <= '8')
249
row = str[i+1] - '1';
251
throw syntax_error();
253
throw_if_extra_argument(str, j);
255
pos = xy_to_pos(col, row);
257
if (color == cur_game_info.get_player()
258
&& cur_game_info.board_ptr->can_play(color, pos)) {
259
// FIXME: Handle time
260
cur_game_info.place_piece(pos, time_player);
262
gtp_maybe_log_game();
263
output_response("", has_id, id);
266
output_error("illegal move", has_id, id);
269
void gtpfunc_genmove(const std::string &str, size_t i,
270
bool has_id, unsigned id)
272
i = skip_space(str, i);
273
throw_syntax_error_if_end_of_line(str, i);
276
i = read_color(str, i, color);
278
if (cur_game_info.is_game_play()
279
&& color == cur_game_info.get_player()) {
280
int pos = get_computer_move (komi);
281
// FIXME: Handle time
282
cur_game_info.place_piece(pos, time_player);
284
gtp_maybe_log_game();
287
output += pos_to_x(pos) + 'A';
288
output += pos_to_y(pos) + '1';
289
output_response(output, has_id, id);
292
output_response("pass", has_id, id);
295
void gtpfunc_reg_genmove(const std::string &str, size_t i,
296
bool has_id, unsigned id)
298
i = skip_space(str, i);
299
throw_syntax_error_if_end_of_line(str, i);
302
i = read_color(str, i, color);
304
if (cur_game_info.is_game_play()
305
&& color == cur_game_info.get_player()) {
307
int pos = get_computer_move (komi);
311
output += pos_to_x(pos) + 'A';
312
output += pos_to_y(pos) + '1';
313
output_response(output, has_id, id);
316
output_response("pass", has_id, id);
319
void gtpfunc_auto_play(const std::string &/*str*/, size_t /*i*/,
320
bool has_id, unsigned id)
322
while (cur_game_info.is_game_play()) {
323
int pos = get_computer_move (komi);
324
// FIXME: Handle time
325
cur_game_info.place_piece(pos, time_player);
327
gtp_maybe_log_game();
328
output_response("", has_id, id);
331
void gtpfunc_time_settings(const std::string &str, size_t i,
332
bool has_id, unsigned id)
334
i = skip_space(str, i);
335
throw_syntax_error_if_end_of_line(str, i);
339
i = read_unsigned(str, i, m);
340
i = skip_space(str, i);
341
throw_syntax_error_if_end_of_line(str, i);
343
i = read_unsigned(str, i, b);
344
i = skip_space(str, i);
345
throw_syntax_error_if_end_of_line(str, i);
347
i = read_unsigned(str, i, s);
348
throw_if_extra_argument(str, i);
354
use_byo_yomi = false;
355
time_left_black = main_time;
356
time_left_white = main_time;
359
output_response("", has_id, id);
362
void gtpfunc_time_left(const std::string &str, size_t i,
363
bool has_id, unsigned id)
365
i = skip_space(str, i);
366
throw_syntax_error_if_end_of_line(str, i);
369
i = read_color(str, i, color);
371
i = skip_space(str, i);
372
throw_syntax_error_if_end_of_line(str, i);
376
i = read_unsigned(str, i, t);
377
i = skip_space(str, i);
378
throw_syntax_error_if_end_of_line(str, i);
380
i = read_unsigned(str, i, s);
381
throw_if_extra_argument(str, i);
383
if (color == BLACK) {
385
stone_left_black = s;
389
stone_left_white = s;
393
output_response("", has_id, id);
396
void gtpfunc_final_score(const std::string &/*str*/, size_t /*i*/,
397
bool has_id, unsigned id)
399
if (cur_game_info.is_game_play())
400
output_error("cannot score", has_id, id);
402
int black_score = cur_game_info.board_ptr->board_black_score();
403
int white_score = cur_game_info.board_ptr->board_white_score();
405
switch (cur_game_info.get_game_result()) {
406
case game_info::game_result_end:
407
adjust_score(black_score, white_score);
409
case game_info::game_result_timeout_black:
413
case game_info::game_result_timeout_white:
417
case game_info::game_result_resign_black:
421
case game_info::game_result_resign_white:
427
std::ostringstream os;
428
double diff_score = black_score - white_score - komi;
430
os << "B+" << diff_score;
431
else if (diff_score < 0)
432
os << "W+" << (-diff_score);
435
output_response(os.str(), has_id, id);
439
void gtpfunc_showboard(const std::string &/*str*/, size_t /*i*/,
440
bool has_id, unsigned id)
442
std::ostringstream os;
444
if (cur_game_info.is_game_play()) {
446
if (cur_game_info.get_player() == BLACK)
452
switch (cur_game_info.get_game_result()) {
453
case game_info::game_result_end:
456
case game_info::game_result_timeout_black:
457
os << "Black ran out of time";
459
case game_info::game_result_timeout_white:
460
os << "White ran out of time";
462
case game_info::game_result_resign_black:
463
os << "Black resigned";
465
case game_info::game_result_resign_white:
466
os << "White resigned";
471
print_board(os, cur_game_info.board_ptr, 2);
473
output_response(os.str(), has_id, id);
476
void gtpfunc_undo(const std::string &/*str*/, size_t /*i*/,
477
bool has_id, unsigned id)
479
if (cur_game_info.is_undoable()) {
480
cur_game_info.undo();
482
output_response("", has_id, id);
485
output_error("cannot undo", has_id, id);
488
void gtpfunc_set_game(const std::string &str, size_t i,
489
bool has_id, unsigned id)
491
i = skip_space(str, i);
492
throw_syntax_error_if_end_of_line(str, i);
494
size_t j = skip_non_space(str, i);
495
if (!str.compare(i, j-i, "Othello"))
496
output_response("", has_id, id);
498
output_error("unsupported game", has_id, id);
501
void gtpfunc_list_games(const std::string &/*str*/, size_t /*i*/,
502
bool has_id, unsigned id)
504
output_response("Othello", has_id, id);
507
void gtpfunc_setup_board(const std::string &str, size_t i,
508
bool has_id, unsigned id)
510
i = skip_space(str, i);
511
throw_syntax_error_if_end_of_line(str, i);
513
size_t j = skip_non_space(str, i);
515
throw syntax_error();
516
j = skip_space(str, j);
518
if (j != str.size()) {
519
// Optional player with first move
520
size_t jj = skip_non_space(str, j);
521
throw_if_extra_argument(str, jj);
537
// Default is already black
540
throw syntax_error();
544
read_color(str, j, color);
549
for (int k = 0; k < 64; ++k) {
571
throw syntax_error();
576
throw syntax_error();
578
byte_board_info b(&t);
579
gtp_new_game(&b, color);
580
output_response("", has_id, id);
583
void gtpfunc_show_history(const std::string &/*str*/, size_t /*i*/,
584
bool has_id, unsigned id)
587
for (int i = 0; i < cur_game_info.num_history-1; ++i) {
588
int pos = cur_game_info.move_history[i];
591
if (cur_game_info.player_history[i-1]
592
== cur_game_info.player_history[i])
596
if (cur_game_info.first_play_is_pass)
600
output += pos_to_x(pos) + 'A';
601
output += pos_to_y(pos) + '1';
603
output_response(output, has_id, id);
606
gtp_command gtp_commands[] = {
607
{ "protocol_version", gtpfunc_protocol_version },
608
{ "name", gtpfunc_name },
609
{ "version", gtpfunc_version },
610
{ "known_command", gtpfunc_known_command },
611
{ "list_commands", gtpfunc_list_commands },
612
{ "quit", gtpfunc_quit },
613
{ "boardsize", gtpfunc_boardsize },
614
{ "clear_board", gtpfunc_clear_board },
615
{ "komi", gtpfunc_komi },
616
// Not supported: fixed_handicap,
617
// place_free_handicap,
619
{ "play", gtpfunc_play },
620
{ "genmove", gtpfunc_genmove },
621
{ "undo", gtpfunc_undo },
623
// final_status_list, load_sgf
624
{ "time_settings", gtpfunc_time_settings },
625
{ "time_left", gtpfunc_time_left },
626
{ "final_score", gtpfunc_final_score },
627
{ "showboard", gtpfunc_showboard },
628
{ "reg_genmove", gtpfunc_reg_genmove },
631
{ "set_game", gtpfunc_set_game },
632
{ "list_games", gtpfunc_list_games },
634
// GTP-Rhino extension
635
{ "grhino-auto_play", gtpfunc_auto_play },
636
{ "grhino-setup_board", gtpfunc_setup_board },
637
{ "grhino-show_history", gtpfunc_show_history },
641
void gtp_process_loop()
652
i = parse_id(str, has_id, id);
653
i = skip_space(str, i);
654
throw_command_error_if_end_of_line(str, i);
656
size_t j = skip_non_space(str, i);
658
for (k = 0; gtp_commands[k].command; ++k) {
659
if (!str.compare(i, j-i, gtp_commands[k].command)) {
660
gtp_commands[k].func(str, j, has_id, id);
664
if (!gtp_commands[k].command)
665
throw command_error();
668
output_error("unknown command", false, 0);
670
catch (command_error &) {
671
output_error("unknown command", has_id, id);
673
catch (syntax_error &) {
674
output_error("syntax error", has_id, id);
676
catch (command_quit &) {
685
void set_level(int level)
687
computer_level = level;
688
current_level_info.midgame_depth
689
= level_info[computer_level].midgame_depth;
690
current_level_info.num_empty_winlossdraw
691
= level_info[computer_level].num_empty_winlossdraw;
692
current_level_info.num_empty_exact
693
= level_info[computer_level].num_empty_exact;
694
set_midgame_depth(current_level_info.midgame_depth);
700
set_max_hash_move(57);
702
pattern_table_init();
706
set_level(1); // Default level
708
// Default parameters
710
set_eval_random(randomness);
712
set_book_random(opening_var);
715
start_game_mode = START_GAME_INITIAL;
720
int main_real(int argc, char *argv[])
722
// Need to parse parameter
724
for (int i = 1; i < argc; ++i) {
725
std::string arg = argv[i];
728
if (arg == "-h" || arg == "--help") {
729
std::cout << prog_name << ' ' << prog_ver << _(" - GTP Frontend for Rhino\n");
730
std::cout << _("(c) 2005 Kriang Lerdsuwanakij\n\n");
731
gtout(std::cout, _("Usage: %$ [options]\n")) << prog_name;
732
std::cout << _("Available options:\n");
733
std::cout << _(" -b N, --book=N Use open book variation N. Allowed = 0..5 (means None..Very high).\n");
734
std::cout << _(" Default = 2 (means Low)\n");
735
std::cout << _(" -e N, --end=N Use perfect end game search depth N instead of default value for\n");
736
std::cout << _(" level. Allowed = 1..20.\n");
737
std::cout << _(" -h, --help Display this help\n");
738
std::cout << _(" -l N, --level=N Use AI level N. Allowed = 1..5. Default = 3\n");
739
std::cout << _(" --log Log game to ~/grhino.log\n");
740
std::cout << _(" -m N, --mid=N Use mid game search depth N instead of default value for level.\n");
741
std::cout << _(" Allowed = 1..20\n");
742
std::cout << _(" -r N, --rand=N Use randomness N in AI evaluator. Allowed = 0..10. Default = 0\n");
743
std::cout << _(" -v, --version Display version number\n");
744
std::cout << _(" -w N, --win=N Use winning move search depth N instead of default value for level.\n");
745
std::cout << _(" Allowed = 1..20\n\n");
748
else if (arg == "-v" || arg == "--version") {
749
std::cout << prog_name << ' ' << prog_ver << '\n';
752
else if (process_unsigned_option(argc, argv, arg, i,
757
else if (process_unsigned_option(argc, argv, arg, i,
760
current_level_info.midgame_depth = u;
761
set_midgame_depth(current_level_info.midgame_depth);
763
else if (process_unsigned_option(argc, argv, arg, i,
766
current_level_info.num_empty_exact = u;
767
if (current_level_info.num_empty_winlossdraw
768
< static_cast<int>(u))
769
current_level_info.num_empty_winlossdraw = u;
771
else if (process_unsigned_option(argc, argv, arg, i,
774
current_level_info.num_empty_winlossdraw = u;
775
if (current_level_info.num_empty_exact
776
> static_cast<int>(u))
777
current_level_info.num_empty_exact = u;
779
else if (process_unsigned_option(argc, argv, arg, i,
783
set_eval_random(randomness);
785
else if (process_unsigned_option(argc, argv, arg, i,
789
set_book_random(opening_var);
791
else if (arg == "--log")
795
gtout(bufstr, _("unknown option `%$\'")) << arg;
796
throw std::runtime_error(bufstr.str());
811
int main(int argc, char *argv[])
815
return main_real(argc, argv);
817
catch (std::exception &e) {
818
std::cout << std::flush;
819
gtout(std::cerr, _("%$: %$\n")) << prog_name << e.what();
821
catch (const char *s) {
822
std::cout << std::flush;
823
gtout(std::cerr, _("%$: exception %$\n")) << prog_name << s;
826
std::cout << std::flush;
827
gtout(std::cerr, _("%$: unknown exception\n")) << prog_name;