Index: engine/board.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/board.c,v retrieving revision 1.52 diff -u -r1.52 board.c --- engine/board.c 5 Oct 2002 09:15:44 -0000 1.52 +++ engine/board.c 13 Oct 2002 17:06:25 -0000 @@ -1047,6 +1047,19 @@ return move_history_pos[move_history_pointer - 1]; } +/* Return the color of the player doing the last move. If no move was + * found, EMPTY is returned. + */ +int +get_last_player() +{ + if (move_history_pointer == 0) + return EMPTY; + + return move_history_color[move_history_pointer - 1]; +} + + /* ================================================================ */ /* Utility functions */ /* ================================================================ */ Index: engine/globals.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/globals.c,v retrieving revision 1.31 diff -u -r1.31 globals.c --- engine/globals.c 30 Sep 2002 20:09:57 -0000 1.31 +++ engine/globals.c 13 Oct 2002 17:06:25 -0000 @@ -142,6 +142,8 @@ int play_mirror_go = 0; /* try to play mirror go if possible */ int mirror_stones_limit = -1; /* but stop at this number of stones */ +int gtp_version = 2; /* Use GTP version 2 by default. */ + float best_move_values[10]; int best_moves[10]; Index: engine/gnugo.h =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/gnugo.h,v retrieving revision 1.70 diff -u -r1.70 gnugo.h --- engine/gnugo.h 29 Sep 2002 02:45:46 -0000 1.70 +++ engine/gnugo.h 13 Oct 2002 17:06:35 -0000 @@ -279,6 +279,7 @@ extern int play_out_aftermath; /* make everything unconditionally settled */ extern int play_mirror_go; /* try to play mirror go if possible */ extern int mirror_stones_limit; /* but stop at this number of stones */ +extern int gtp_version; /* version of Go Text Protocol */ #if EXPERIMENTAL_READING extern int defend_by_pattern; /* use patterns for tactical reading defense */ @@ -325,7 +326,8 @@ void draw_color_char(int m, int n, int c, int color); void draw_char(int m, int n, int c); void end_draw_board(void); -void showboard(int xo); /* ascii rep. of board to stdout */ +void showboard(int xo); /* ascii rep. of board to stderr */ +void simple_showboard(FILE *outfile); /* ascii rep. of board to outfile */ /* printutils.c */ int gprintf(const char *fmt, ...); @@ -429,6 +431,7 @@ void play_move(int pos, int color); int undo_move(int n); int get_last_move(void); +int get_last_player(void); int get_last_opponent_move(int color); int is_pass(int pos); int is_legal(int pos, int color); Index: engine/showbord.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/engine/showbord.c,v retrieving revision 1.17 diff -u -r1.17 showbord.c --- engine/showbord.c 6 Aug 2002 19:04:11 -0000 1.17 +++ engine/showbord.c 13 Oct 2002 17:06:37 -0000 @@ -149,16 +149,16 @@ /* Print a line with coordinate letters above the board. */ static void -draw_letter_coordinates(void) +draw_letter_coordinates(FILE *outfile) { int i; int ch; - fprintf(stderr, " "); + fprintf(outfile, " "); for (i = 0, ch = 'A'; i < board_size; i++, ch++) { if (ch == 'I') ch++; - fprintf(stderr, " %c", ch); + fprintf(outfile, " %c", ch); } } @@ -186,7 +186,7 @@ start_draw_board() { gg_init_color(); - draw_letter_coordinates(); + draw_letter_coordinates(stderr); } /* Draw a colored character. If c has the value EMPTY, either a "." or @@ -234,7 +234,7 @@ end_draw_board() { fprintf(stderr, "\n"); - draw_letter_coordinates(); + draw_letter_coordinates(stderr); fprintf(stderr, "\n"); } @@ -368,14 +368,14 @@ fprintf(stderr, " %d", ii); - if ((xo == 0) && ((board_size < 10 && i == board_size-2) - || (board_size >= 10 && i == 8))) + if (xo == 0 && ((board_size < 10 && i == board_size-2) + || (board_size >= 10 && i == 8))) fprintf(stderr, " WHITE has captured %d stones", black_captured); - if ((xo == 0) && ((board_size < 10 && i == board_size-1) - || (board_size >= 10 && i == 9))) + if (xo == 0 && ((board_size < 10 && i == board_size-1) + || (board_size >= 10 && i == 9))) fprintf(stderr, " BLACK has captured %d stones", white_captured); - + if (xo == 3) { if (i == board_size-5) write_color_string(GG_COLOR_GREEN, " green=alive"); @@ -394,6 +394,40 @@ } +/* Bare bones version of showboard(0). No fancy options, no hint of + * color, and you can choose where to write it. + */ +void +simple_showboard(FILE *outfile) +{ + int i, j; + + draw_letter_coordinates(outfile); + + for (i = 0; i < board_size; i++) { + fprintf(outfile, "\n%2d", board_size - i); + + for (j = 0; j < board_size; j++) { + if (BOARD(i, j) == EMPTY) + fprintf(outfile, " %c", is_hoshi_point(i, j) ? '+' : '.'); + else + fprintf(outfile, " %c", BOARD(i, j) == BLACK ? 'X' : 'O'); + } + + fprintf(outfile, " %d", board_size - i); + + if ((board_size < 10 && i == board_size-2) + || (board_size >= 10 && i == 8)) + fprintf(outfile, " WHITE has captured %d stones", black_captured); + + if ((board_size < 10 && i == board_size-1) + || (board_size >= 10 && i == 9)) + fprintf(outfile, " BLACK has captured %d stones", white_captured); + } + + fprintf(outfile, "\n"); + draw_letter_coordinates(outfile); +} /* * Local Variables: Index: interface/gtp.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/interface/gtp.c,v retrieving revision 1.12 diff -u -r1.12 gtp.c --- interface/gtp.c 8 Aug 2002 21:35:21 -0000 1.12 +++ interface/gtp.c 13 Oct 2002 17:07:07 -0000 @@ -90,7 +90,7 @@ /* Convert HT (9) to SPACE (32). */ if (c == 9) *p++ = 32; - /* Remove CR (13) and all other control characters except for LF (10). */ + /* Remove CR (13) and all other control characters except LF (10). */ else if ((c > 0 && c <= 9) || (c >= 11 && c <= 31) || c == 127) @@ -128,7 +128,7 @@ } } if (commands[i].name == NULL) - gtp_failure("unknown command: '%s'", command); + gtp_failure("unknown command"); if (status == GTP_FATAL) gtp_panic(); @@ -157,7 +157,7 @@ /* * This function works like printf, except that it only understands * very few of the standard formats, to be precise %c, %d, %f, %s. - * But it also accepts %m, which takes two integers and writes a move, + * But it also accepts %m, which takes two integers and writes a vertex, * and %C, which takes a color value and writes a color string. */ void @@ -365,12 +365,13 @@ /* Convert a move, i.e. "b" or "w" followed by a vertex to a color and * coordinates. Return the number of characters read from the string - * s. + * s. The vertex may be "pass" and then the coordinates are set to (-1, -1). */ int gtp_decode_move(char *s, int *color, int *i, int *j) { int n1, n2; + int k; assert(gtp_boardsize > 0); @@ -379,9 +380,18 @@ return 0; n2 = gtp_decode_coord(s + n1, i, j); - if (n2 == 0) - return 0; - + if (n2 == 0) { + char buf[6]; + if (sscanf(s + n1, "%5s%n", buf, &n2) != 1) + return 0; + for (k = 0; k < (int) strlen(buf); k++) + buf[k] = tolower((int) buf[k]); + if (strcmp(buf, "pass") != 0) + return 0; + *i = -1; + *j = -1; + } + return n1 + n2; } Index: interface/main.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/interface/main.c,v retrieving revision 1.54 diff -u -r1.54 main.c --- interface/main.c 29 Sep 2002 02:45:46 -0000 1.54 +++ interface/main.c 13 Oct 2002 17:07:23 -0000 @@ -73,6 +73,7 @@ OPT_QUIET, OPT_GTP_INPUT, OPT_GTP_INITIAL_ORIENTATION, + OPT_GTP_VERSION, OPT_SHOWCOPYRIGHT, OPT_REPLAY_GAME, OPT_DECIDE_STRING, @@ -169,6 +170,7 @@ {"orientation", required_argument, 0, OPT_GTP_INITIAL_ORIENTATION}, {"gtp-initial-orientation", required_argument, 0, OPT_GTP_INITIAL_ORIENTATION}, + {"gtp-version", required_argument, 0, OPT_GTP_VERSION}, {"infile", required_argument, 0, 'l'}, {"until", required_argument, 0, 'L'}, {"outfile", required_argument, 0, 'o'}, @@ -333,7 +335,7 @@ sgftree_clear(&sgftree); gameinfo_clear(&gameinfo, board_size, komi); - /* Now weed through all of the command line options. */ + /* Weed through all of the command line options. */ while ((i = gg_getopt_long(argc, argv, "-ab:B:d:D:EF:gh::H:K:l:L:M:m:o:O:p:r:fsStTvw", long_options, NULL)) != EOF) @@ -404,6 +406,10 @@ fprintf(stderr, "Try `gnugo --help' for more information.\n"); exit(EXIT_FAILURE); } + break; + + case OPT_GTP_VERSION: + gtp_version = atoi(gg_optarg); break; case OPT_OPTIONS: Index: interface/play_gtp.c =================================================================== RCS file: /cvsroot/gnugo/gnugo/interface/play_gtp.c,v retrieving revision 1.94 diff -u -r1.94 play_gtp.c --- interface/play_gtp.c 9 Oct 2002 18:36:23 -0000 1.94 +++ interface/play_gtp.c 13 Oct 2002 17:08:25 -0000 @@ -33,7 +33,10 @@ #include "gg_utils.h" /* Internal state that's not part of the engine. */ -int handicap; +static int handicap = 0; +static int main_time = 0; +static int byo_yomi_time = 0; +static int byo_yomi_stones = 0; static int report_uncertainty = 0; static int gtp_orientation = 0; @@ -53,6 +56,7 @@ DECLARE(gtp_aa_confirm_safety); DECLARE(gtp_all_legal); DECLARE(gtp_attack); +DECLARE(gtp_clear_board); DECLARE(gtp_combination_attack); DECLARE(gtp_connect); DECLARE(gtp_countlib); @@ -84,15 +88,17 @@ DECLARE(gtp_get_owl_node_counter); DECLARE(gtp_get_reading_node_counter); DECLARE(gtp_get_trymove_counter); -DECLARE(gtp_help); +DECLARE(gtp_gg_genmove); +DECLARE(gtp_gg_undo); DECLARE(gtp_increase_depths); DECLARE(gtp_influence); DECLARE(gtp_is_legal); +DECLARE(gtp_known_command); DECLARE(gtp_ladder_attack); +DECLARE(gtp_list_commands); DECLARE(gtp_list_stones); DECLARE(gtp_loadsgf); DECLARE(gtp_name); -DECLARE(gtp_new_game); DECLARE(gtp_estimate_score); DECLARE(gtp_experimental_score); DECLARE(gtp_owl_analyze_semeai); @@ -106,6 +112,7 @@ DECLARE(gtp_owl_threaten_attack); DECLARE(gtp_owl_threaten_defense); DECLARE(gtp_place_free_handicap); +DECLARE(gtp_play); DECLARE(gtp_playblack); DECLARE(gtp_playwhite); DECLARE(gtp_popgo); @@ -114,6 +121,7 @@ DECLARE(gtp_query_boardsize); DECLARE(gtp_query_orientation); DECLARE(gtp_quit); +DECLARE(gtp_reg_genmove); DECLARE(gtp_report_uncertainty); DECLARE(gtp_reset_connection_node_counter); DECLARE(gtp_reset_life_node_counter); @@ -122,6 +130,7 @@ DECLARE(gtp_reset_trymove_counter); DECLARE(gtp_same_dragon); DECLARE(gtp_set_boardsize); +DECLARE(gtp_set_free_handicap); DECLARE(gtp_set_orientation); DECLARE(gtp_set_komi); DECLARE(gtp_get_komi); @@ -129,6 +138,8 @@ DECLARE(gtp_showboard); DECLARE(gtp_start_sgftrace); DECLARE(gtp_test_eyeshape); +DECLARE(gtp_time_left); +DECLARE(gtp_time_settings); DECLARE(gtp_top_moves); DECLARE(gtp_top_moves_white); DECLARE(gtp_top_moves_black); @@ -136,7 +147,7 @@ DECLARE(gtp_tryko); DECLARE(gtp_tune_move_ordering); DECLARE(gtp_undo); -DECLARE(gtp_version); +DECLARE(gtp_program_version); DECLARE(gtp_what_color); DECLARE(gtp_worm_cutstone); DECLARE(gtp_worm_data); @@ -150,6 +161,7 @@ {"black", gtp_playblack}, {"boardsize", gtp_set_boardsize}, {"captures", gtp_captures}, + {"clear_board", gtp_clear_board}, {"color", gtp_what_color}, {"combination_attack", gtp_combination_attack}, {"connect", gtp_connect}, @@ -176,6 +188,7 @@ {"get_handicap", gtp_get_handicap}, {"get_random_seed", gtp_get_random_seed}, {"set_random_seed", gtp_set_random_seed}, + {"genmove", gtp_genmove}, {"genmove_black", gtp_genmove_black}, {"genmove_white", gtp_genmove_white}, {"get_connection_node_counter", gtp_get_connection_node_counter}, @@ -183,19 +196,21 @@ {"get_owl_node_counter", gtp_get_owl_node_counter}, {"get_reading_node_counter",gtp_get_reading_node_counter}, {"get_trymove_counter", gtp_get_trymove_counter}, - {"gg_genmove", gtp_genmove}, - {"help", gtp_help}, + {"gg_genmove", gtp_gg_genmove}, + {"gg-undo", gtp_gg_undo}, + {"help", gtp_list_commands}, {"increase_depths", gtp_increase_depths}, {"influence", gtp_influence}, {"is_legal", gtp_is_legal}, + {"known_command", gtp_known_command}, {"komi", gtp_set_komi}, {"get_komi", gtp_get_komi}, {"ladder_attack", gtp_ladder_attack}, {"level", gtp_set_level}, + {"list_commands", gtp_list_commands}, {"list_stones", gtp_list_stones}, {"loadsgf", gtp_loadsgf}, {"name", gtp_name}, - {"new_game", gtp_new_game}, {"new_score", gtp_estimate_score}, {"owl_analyze_semeai", gtp_owl_analyze_semeai}, {"tactical_analyze_semeai", gtp_tactical_analyze_semeai}, @@ -207,13 +222,15 @@ {"owl_substantial", gtp_owl_substantial}, {"owl_threaten_attack", gtp_owl_threaten_attack}, {"owl_threaten_defense", gtp_owl_threaten_defense}, + {"play", gtp_play}, {"popgo", gtp_popgo}, {"orientation", gtp_set_orientation}, - {"protocol_version", gtp_protocol_version}, {"place_free_handicap", gtp_place_free_handicap}, + {"protocol_version", gtp_protocol_version}, {"query_boardsize", gtp_query_boardsize}, {"query_orientation", gtp_query_orientation}, {"quit", gtp_quit}, + {"reg_genmove", gtp_reg_genmove}, {"report_uncertainty", gtp_report_uncertainty}, {"reset_connection_node_counter", gtp_reset_connection_node_counter}, {"reset_life_node_counter", gtp_reset_life_node_counter}, @@ -221,9 +238,12 @@ {"reset_reading_node_counter", gtp_reset_reading_node_counter}, {"reset_trymove_counter", gtp_reset_trymove_counter}, {"same_dragon", gtp_same_dragon}, + {"set_free_handicap", gtp_set_free_handicap}, {"showboard", gtp_showboard}, {"start_sgftrace", gtp_start_sgftrace}, {"test_eyeshape", gtp_test_eyeshape}, + {"time_left", gtp_time_left}, + {"time_settings", gtp_time_settings}, {"top_moves", gtp_top_moves}, {"top_moves_black", gtp_top_moves_black}, {"top_moves_white", gtp_top_moves_white}, @@ -231,7 +251,7 @@ {"tryko", gtp_tryko}, {"tune_move_ordering", gtp_tune_move_ordering}, {"undo", gtp_undo}, - {"version", gtp_version}, + {"version", gtp_program_version}, {"white", gtp_playwhite}, {"worm_cutstone", gtp_worm_cutstone}, {"worm_data", gtp_worm_data}, @@ -270,6 +290,8 @@ * Arguments: none * Fails: never * Returns: nothing + * + * Status: GTP version 2 standard command. */ static int gtp_quit(char *s) @@ -284,24 +306,14 @@ * Arguments: none * Fails: never * Returns: protocol version number + * + * Status: GTP version 2 standard command. */ static int gtp_protocol_version(char *s) { UNUSED(s); - return gtp_success("1"); -} - -/* Function: Start a new game - * Arguments: none - * Fails: always - * Returns: nothing - */ -static int -gtp_new_game(char *s) -{ - UNUSED(s); - return gtp_failure("not implemented"); + return gtp_success("%d", gtp_version); } @@ -313,6 +325,8 @@ * Arguments: none * Fails: never * Returns: program name + * + * Status: GTP version 2 standard command. */ static int gtp_name(char *s) @@ -328,9 +342,11 @@ * Arguments: none * Fails: never * Returns: version number + * + * Status: GTP version 2 standard command. */ static int -gtp_version(char *s) +gtp_program_version(char *s) { UNUSED(s); return gtp_success(VERSION); @@ -345,28 +361,29 @@ * Arguments: integer * Fails: board size outside engine's limits * Returns: nothing + * + * Status: GTP version 2 standard command. */ static int gtp_set_boardsize(char *s) { int boardsize; - int pos; if (sscanf(s, "%d", &boardsize) < 1) return gtp_failure("boardsize not an integer"); - if (boardsize < MIN_BOARD || boardsize > MAX_BOARD) - return gtp_failure("unacceptable boardsize"); + if (boardsize < MIN_BOARD || boardsize > MAX_BOARD) { + if (gtp_version == 1) + return gtp_failure("unacceptable boardsize"); + else + return gtp_failure("unacceptable size"); + } /* If this is called with a non-empty board, we assume that a new * game will be started, for which we want a new random seed. */ - for (pos = BOARDMIN; pos < BOARDMAX; pos++) { - if (ON_BOARD(pos) && board[pos] != EMPTY) { - update_random_seed(); - break; - } - } + if (stones_on_board(BLACK | WHITE) > 0) + update_random_seed(); board_size = boardsize; clear_board(); @@ -388,6 +405,32 @@ return gtp_success("%d", board_size); } +/*********************** + * Clearing the board. * + ***********************/ + +/* Function: Clear the board. + * Arguments: none + * Fails: never + * Returns: nothing + * + * Status: GTP version 2 standard command. + */ +static int +gtp_clear_board(char *s) +{ + UNUSED(s); + + /* If this is called with a non-empty board, we assume that a new + * game will be started, for which we want a new random seed. + */ + if (stones_on_board(BLACK | WHITE) > 0) + update_random_seed(); + + clear_board(); + return gtp_success(""); +} + /**************************** * Setting the orientation. * ****************************/ @@ -434,6 +477,8 @@ * Arguments: float * Fails: incorrect argument * Returns: nothing + * + * Status: GTP version 2 standard command. */ static int gtp_set_komi(char *s) @@ -470,6 +515,8 @@ * Arguments: vertex * Fails: invalid vertex, illegal move * Returns: nothing + * + * Status: Obsolete GTP version 1 command. */ static int gtp_playblack(char *s) @@ -499,6 +546,8 @@ * Arguments: vertex * Fails: invalid vertex, illegal move * Returns: nothing + * + * Status: Obsolete GTP version 1 command. */ static int gtp_playwhite(char *s) @@ -524,24 +573,60 @@ } +/* Function: Play a black stone at the given vertex. + * Arguments: vertex + * Fails: invalid vertex, illegal move + * Returns: nothing + * + * Status: GTP version 2 standard command. + */ +static int +gtp_play(char *s) +{ + int i, j; + int color; + + if (!gtp_decode_move(s, &color, &i, &j)) + return gtp_failure("invalid color or coordinate"); + + if (!is_legal(POS(i, j), color)) + return gtp_failure("illegal move"); + + play_move(POS(i, j), color); + return gtp_success(""); +} + + /* Function: Set up fixed placement handicap stones. * Arguments: number of handicap stones * Fails: invalid number of stones for the current boardsize * Returns: list of vertices with handicap stones + * + * Status: GTP version 2 standard command. */ static int gtp_fixed_handicap(char *s) { int m, n; int first = 1; - int handicap; - if (sscanf(s, "%d", &handicap) < 1) + int this_handicap; + + if (gtp_version == 1) + clear_board(); + else if (stones_on_board(BLACK | WHITE) > 0) + return gtp_failure("board not empty"); + + if (sscanf(s, "%d", &this_handicap) < 1) return gtp_failure("handicap not an integer"); - clear_board(); - if (place_fixed_handicap(handicap) != handicap) + if (this_handicap < 2 && (gtp_version > 1 || this_handicap != 0)) return gtp_failure("invalid handicap"); + if (place_fixed_handicap(this_handicap) != this_handicap) + return gtp_failure("invalid handicap"); + + handicap = this_handicap; + gtp_start_response(GTP_SUCCESS); for (m = 0; m < board_size; m++) @@ -558,25 +643,29 @@ } -/* Function: Set up free placement handicap stones. +/* Function: Choose free placement handicap stones and put them on the board. * Arguments: number of handicap stones * Fails: invalid number of stones * Returns: list of vertices with handicap stones + * + * Status: GTP version 2 standard command. */ static int gtp_place_free_handicap(char *s) { int m, n; int first = 1; - int handicap; - if (sscanf(s, "%d", &handicap) < 1) + int this_handicap; + if (sscanf(s, "%d", &this_handicap) < 1) return gtp_failure("handicap not an integer"); - clear_board(); - if (handicap < 0 || handicap == 1) + if (stones_on_board(BLACK | WHITE) > 0) + return gtp_failure("board not empty"); + + if (this_handicap < 2) return gtp_failure("invalid handicap"); - place_free_handicap(handicap); + handicap = place_free_handicap(this_handicap); gtp_start_response(GTP_SUCCESS); @@ -594,6 +683,50 @@ } +/* Function: Put free placement handicap stones on the board. + * Arguments: list of vertices with handicap stones + * Fails: board not empty, bad list of vertices + * Returns: nothing + * + * Status: GTP version 2 standard command. + */ +static int +gtp_set_free_handicap(char *s) +{ + int n; + int i, j; + int k; + + if (stones_on_board(BLACK | WHITE) > 0) + return gtp_failure("board not empty"); + + for (k = 0; k < MAX_BOARD * MAX_BOARD; k++) { + n = gtp_decode_coord(s, &i, &j); + if (n > 0) { + if (board[POS(i, j)] != EMPTY) { + clear_board(); + return gtp_failure("repeated vertex"); + } + add_stone(POS(i, j), BLACK); + s += n; + } + else if (sscanf(s, "%*s") != EOF) + return gtp_failure("invalid coordinate"); + else + break; + } + + if (k < 2) { + clear_board(); + return gtp_failure("invalid handicap"); + } + + handicap = k; + + return gtp_success(""); +} + + /* Function: Get the handicap * Arguments: none * Fails: never @@ -612,6 +745,8 @@ * Arguments: filename + move number, vertex, or nothing * Fails: missing filename or failure to open or parse file * Returns: color to play + * + * Status: GTP version 2 standard command. */ static int gtp_loadsgf(char *s) @@ -828,7 +963,7 @@ { int i, j; int color; - if (!gtp_decode_move(s, &color, &i, &j)) + if (!gtp_decode_move(s, &color, &i, &j) || POS(i, j) == PASS_MOVE) return gtp_failure("invalid color or coordinate"); if (!trymove(POS(i, j), color, "gtp_trymove", NO_MOVE, EMPTY, NO_MOVE)) @@ -848,7 +983,7 @@ { int i, j; int color; - if (!gtp_decode_move(s, &color, &i, &j)) + if (!gtp_decode_move(s, &color, &i, &j) || POS(i, j) == PASS_MOVE) return gtp_failure("invalid color or coordinate"); if (!tryko(POS(i, j), color, "gtp_tryko", EMPTY, NO_MOVE)) @@ -1685,7 +1820,7 @@ char saved_worms[BOARDMAX]; n = gtp_decode_move(s, &color, &i, &j); - if (n == 0) + if (n == 0 || POS(i, j) == NO_MOVE) return gtp_failure("invalid color or coordinate"); sscanf(s + n, "%d", &minsize); @@ -1715,6 +1850,8 @@ * Arguments: none * Fails: never * Returns: a move coordinate (or "PASS") + * + * Status: Obsolete GTP version 1 command. */ static int gtp_genmove_black(char *s) @@ -1739,6 +1876,8 @@ * Arguments: none * Fails: never * Returns: a move coordinate (or "PASS") + * + * Status: Obsolete GTP version 1 command. */ static int gtp_genmove_white(char *s) @@ -1759,13 +1898,79 @@ return gtp_finish_response(); } +/* Function: Generate and play the supposedly best move for either color. + * Arguments: color to move + * Fails: invalid color + * Returns: a move coordinate (or "PASS") + * + * Status: GTP version 2 standard command. + */ +static int +gtp_genmove(char *s) +{ + int i, j; + int color; + int n; + + n = gtp_decode_color(s, &color); + if (!n) + return gtp_failure("invalid color"); + + if (stackp > 0) + return gtp_failure("genmove cannot be called when stackp > 0"); + + genmove(&i, &j, color); + play_move(POS(i, j), color); + + gtp_start_response(GTP_SUCCESS); + gtp_print_vertex(i, j); + return gtp_finish_response(); +} + + +/* Function: Generate the supposedly best move for either color. + * Arguments: color to move + * Fails: invalid color + * Returns: a move coordinate (or "PASS") + * + * Status: GTP version 2 standard command. + */ +static int +gtp_reg_genmove(char *s) +{ + int i, j; + int color; + int n; + + n = gtp_decode_color(s, &color); + if (!n) + return gtp_failure("invalid color"); + + if (stackp > 0) + return gtp_failure("genmove cannot be called when stackp > 0"); + + /* This is intended for regression purposes and should therefore be + * deterministic. The best way to ensure this is to reset the random + * number generator before calling genmove(). It is always seeded by + * 0. + */ + random_seed = 0; + + genmove_conservative(&i, &j, color); + gtp_start_response(GTP_SUCCESS); + gtp_print_vertex(i, j); + return gtp_finish_response(); +} + /* Function: Generate the supposedly best move for either color. * Arguments: color to move, optionally a random seed * Fails: invalid color * Returns: a move coordinate (or "PASS") + * + * This differs from reg_genmove in the optional random seed. */ static int -gtp_genmove(char *s) +gtp_gg_genmove(char *s) { int i, j; int color; @@ -1875,14 +2080,36 @@ } /* Function: Undo a number of moves - * Arguments: optional int + * Arguments: none * Fails: If move history is too short. * Returns: nothing + * + * Status: GTP version 2 standard command. */ static int gtp_undo(char *s) { + UNUSED(s); + + if (!undo_move(1)) + return gtp_failure("cannot undo"); + + reset_engine(); + + return gtp_success(""); +} + + +/* Function: Undo a number of moves + * Arguments: optional int + * Fails: If move history is too short. + * Returns: nothing + */ + +static int +gtp_gg_undo(char *s) +{ int number_moves = 1; sscanf(s, "%d", &number_moves); @@ -1891,7 +2118,7 @@ return gtp_failure("can't undo a negative number of moves"); if (!undo_move(number_moves)) - return gtp_failure("undo failed"); + return gtp_failure("cannot undo"); reset_engine(); @@ -1899,6 +2126,65 @@ } +/***************** + * time handling * + *****************/ + +/* Function: Set time allowance + * Arguments: int main_time, int byo_yomi_time, int byo_yomi_stones + * Fails: syntax error + * Returns: nothing + * + * Status: GTP version 2 standard command. + * + * FIXME: This command stores the time settings but noone ever takes notice. + */ + +static int +gtp_time_settings(char *s) +{ + int a, b, c; + + if (sscanf(s, "%d %d %d", &a, &b, &c) < 3) + return gtp_failure("not three integers"); + + main_time = a; + byo_yomi_time = b; + byo_yomi_stones = c; + + return gtp_success(""); +} + + +/* Function: Report remaining time + * Arguments: color color, int time, int stones + * Fails: syntax error + * Returns: nothing + * + * Status: GTP version 2 standard command. + * + * FIXME: This command does not take any action. + */ + +static int +gtp_time_left(char *s) +{ + int color; + int time; + int stones; + int n; + + n = gtp_decode_color(s, &color); + if (!n) + return gtp_failure("invalid color"); + + if (sscanf(s+n, "%d %d", &time, &stones) < 2) + return gtp_failure("time and stones not two integers"); + + return gtp_success(""); +} + + /*********** * scoring * ***********/ @@ -1947,8 +2233,14 @@ doing_scoring = 1; store_board(&saved_pos); - /* FIXME: Letting black always start is a preliminary solution. */ - next = BLACK; + /* Let black start if we have no move history. Otherwise continue + * alternation. + */ + if (get_last_player() == EMPTY) + next = BLACK; + else + next = OTHER_COLOR(get_last_player()); + do { move_val = genmove_conservative(&i, &j, next); play_move(POS(i, j), next); @@ -2019,6 +2311,8 @@ * Arguments: Optional random seed * Fails: never * Returns: Score in SGF format (RE property). + * + * Status: GTP version 2 standard command. */ static int gtp_final_score(char *s) @@ -2097,6 +2391,10 @@ * Returns: Vertices having the specified status. These are split with * one string on each line if the vertices are nonempty (i.e. * for "alive", "dead", and "seki"). + * + * Status: GTP version 2 standard command. + * However, "dame", "white_territory", and "black_territory" + * are private extensions. */ static int gtp_final_status_list(char *s) @@ -2424,17 +2722,22 @@ -/* Function: Write the position to stderr. +/* Function: Write the position to stdout. * Arguments: none * Fails: never * Returns: nothing + * + * Status: GTP version 2 standard command. */ static int gtp_showboard(char *s) { UNUSED(s); - showboard(0); - return gtp_success(""); + + gtp_start_response(GTP_SUCCESS); + gtp_printf("\n"); + simple_showboard(stdout); + return gtp_finish_response(); } @@ -2890,9 +3193,11 @@ * Arguments: none * Fails: never * Returns: list of known commands, one per line + * + * Status: GTP version 2 standard command. */ static int -gtp_help(char *s) +gtp_list_commands(char *s) { int k; UNUSED(s); @@ -2904,6 +3209,25 @@ gtp_printf("\n"); return GTP_OK; +} + + +/* Function: Tell whether a command is known. + * Arguments: command name + * Fails: never + * Returns: "true" if command exists, "false" if not + * + * Status: GTP version 2 standard command. + */ +static int +gtp_known_command(char *s) +{ + int k; + for (k = 0; commands[k].name != NULL; k++) + if (strcmp(s, commands[k].name) == 0) + return gtp_success("true"); + + return gtp_success("false"); }