static int gtp_set_free_handicap(char *s) { int i, j; int n; int handicap = 0; if (!board_empty()) return gtp_failure("board not empty"); while ((n = gtp_decode_coord(s, &i, &j)) > 0) { s += n; if (get_board(i, j) != EMPTY) { clear_board(); return gtp_failure("repeated vertex"); } play_move(i, j, BLACK); handicap++; } if (sscanf(s, "%*s") != EOF) { clear_board(); return gtp_failure("invalid coordinate"); } if (handicap < 2 || handicap >= board_size * board_size) { clear_board(); return gtp_failure("invalid handicap"); } return gtp_success(""); }
/* Function: Play a stone of the given color at the given vertex. * Arguments: color, vertex * Fails: invalid vertex, illegal move * Returns: nothing * * Status: GTP version 2 standard command. */ static int gtp_play(char *s) { DataGo move; if (!gtp_decode_move(s, &move)) return gtp_failure("invalid color or coordinate"); if (!game->play_move(move)) return gtp_failure("illegal move"); return gtp_success(""); }
static int gtp_play(char *s) { int i, j; int color = EMPTY; if (!gtp_decode_move(s, &color, &i, &j)) return gtp_failure("invalid color or coordinate"); if (!legal_move(i, j, color)) return gtp_failure("illegal move"); play_move(i, j, color); return gtp_success(""); }
static int gtp_final_status_list(char *s) { int n; int i, j; int status = UNKNOWN; char status_string[GTP_BUFSIZE]; int first_string; if (sscanf(s, "%s %n", status_string, &n) != 1) return gtp_failure("missing status"); if (!strcmp(status_string, "alive")) status = ALIVE; else if (!strcmp(status_string, "dead")) status = DEAD; else if (!strcmp(status_string, "seki")) status = SEKI; else return gtp_failure("invalid status"); compute_final_status(); gtp_start_response(GTP_SUCCESS); first_string = 1; for (i = 0; i < board_size; i++) for (j = 0; j < board_size; j++) if (get_final_status(i, j) == status) { int k; int stonei[MAX_BOARD * MAX_BOARD]; int stonej[MAX_BOARD * MAX_BOARD]; int num_stones = get_string(i, j, stonei, stonej); /* Clear the status so we don't find the string again. */ for (k = 0; k < num_stones; k++) set_final_status(stonei[k], stonej[k], UNKNOWN); if (first_string) first_string = 0; else gtp_printf("\n"); gtp_print_vertices(num_stones, stonei, stonej); } return gtp_finish_response(); }
static int gtp_komi(char *s) { if (sscanf(s, "%f", &komi) < 1) return gtp_failure("komi not a float"); return gtp_success(""); }
static int gtp_boardsize(char *s) { int boardsize; if (sscanf(s, "%d", &boardsize) < 1) return gtp_failure("boardsize not an integer"); if (boardsize < MIN_BOARD || boardsize > MAX_BOARD) return gtp_failure("unacceptable size"); board_size = boardsize; gtp_internal_set_boardsize(boardsize); init_brown(); return gtp_success(""); }
static int gtp_set_komi(char *s) { float komi; if (sscanf(s, "%f", &komi) < 1) return gtp_failure("komi not a float"); game->set_komi(komi); return gtp_success(""); }
/* Function: Set the board size to NxN and clear the board. * 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; if (sscanf(s, "%d", &boardsize) < 1) return gtp_failure("boardsize not an integer"); if (boardsize <= 0 || boardsize > MAX_BOARD) { if (GTP_VERSION == 1) return gtp_failure("unacceptable boardsize"); else return gtp_failure("unacceptable size"); } game->set_boardsize(boardsize); game->clear_board(); gtp_internal_set_boardsize(boardsize); return gtp_success(""); }
/* Read stdin linewise and interpret as GTP commands. */ void gtp_main_loop(struct gtp_command commands[]) { char line[GTP_BUFSIZE]; char command[GTP_BUFSIZE]; char *p; int i; int id; int n; int status = GTP_OK; while (status == GTP_OK) { /* Read a line from stdin. */ if (!fgets(line, GTP_BUFSIZE, stdin)) break; /* EOF or some error */ /* Remove comments. */ if ((p = strchr(line, '#')) != NULL) *p = 0; p = line; /* Look for an identification number. */ if (sscanf(p, "%d%n", &id, &n) == 1) p += n; else id = -1; /* No identification number. */ /* Look for command name. */ if (sscanf(p, " %s %n", command, &n) < 1) continue; /* Whitespace only on this line, ignore. */ p += n; /* Search the list of commands and call the corresponding function * if it's found. */ for (i = 0; commands[i].name != NULL; i++) { if (strcmp(command, commands[i].name) == 0) { status = (*commands[i].function)(p, id); break; } } if (commands[i].name == NULL) gtp_failure(id, "unknown command: '%s'", command); if (status == GTP_FATAL) gtp_panic(); } }
/* Common code for fixed_handicap and place_free_handicap. */ static int place_handicap(char *s, int fixed) { int handicap; int m, n; int first_stone = 1; if (!board_empty()) return gtp_failure("board not empty"); if (sscanf(s, "%d", &handicap) < 1) return gtp_failure("handicap not an integer"); if (handicap < 2) return gtp_failure("invalid handicap"); if (fixed && !valid_fixed_handicap(handicap)) return gtp_failure("invalid handicap"); if (fixed) place_fixed_handicap(handicap); else place_free_handicap(handicap); gtp_start_response(GTP_SUCCESS); for (m = 0; m < board_size; m++) for (n = 0; n < board_size; n++) if (get_board(m, n) != EMPTY) { if (first_stone) first_stone = 0; else gtp_printf(" "); gtp_mprintf("%m", m, n); } return gtp_finish_response(); }
static int gtp_genmove(char *s) { int i, j; int color = EMPTY; if (!gtp_decode_color(s, &color)) return gtp_failure("invalid color"); generate_move(&i, &j, color); play_move(i, j, color); gtp_start_response(GTP_SUCCESS); gtp_mprintf("%m", i, j); 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" (or "resign" if resignation_allowed) * * Status: GTP version 2 standard command. */ static int gtp_genmove(char *s) { DataGo move; Player color; if (!gtp_decode_color(s, &color)) return gtp_failure("invalid color"); move = game->gen_move(color); if (IS_RESIGN(move)) return gtp_success("resign"); assert(game->play_move(move)); gtp_start_response(GTP_SUCCESS); if (IS_PASS(move)) gtp_print_vertex(-1, -1); else gtp_print_vertex(move.i, move.j); return gtp_finish_response(); }
/* Read filehandle gtp_input linewise and interpret as GTP commands. */ void gtp_main_loop(struct gtp_command commands[], FILE *gtp_input) { char line[GTP_BUFSIZE]; char command[GTP_BUFSIZE]; char *p; int i; int n; int status = GTP_OK; while (status == GTP_OK) { /* Read a line from gtp_input. */ if (!fgets(line, GTP_BUFSIZE, gtp_input)) break; /* EOF or some error */ /* Preprocess the line. */ for (i = 0, p = line; line[i]; i++) { char c = line[i]; /* Convert HT (9) to SPACE (32). */ if (c == 9) *p++ = 32; /* Remove CR (13) and all other control characters except LF (10). */ else if ((c > 0 && c <= 9) || (c >= 11 && c <= 31) || c == 127) continue; /* Remove comments. */ else if (c == '#') break; /* Keep ordinary text. */ else *p++ = c; } /* Terminate string. */ *p = 0; p = line; /* Look for an identification number. */ if (sscanf(p, "%d%n", ¤t_id, &n) == 1) p += n; else current_id = -1; /* No identification number. */ /* Look for command name. */ if (sscanf(p, " %s %n", command, &n) < 1) continue; /* Whitespace only on this line, ignore. */ p += n; /* Search the list of commands and call the corresponding function * if it's found. */ for (i = 0; commands[i].name != NULL; i++) { if (strcmp(command, commands[i].name) == 0) { status = (*commands[i].function)(p); break; } } if (commands[i].name == NULL) gtp_failure("unknown command"); if (status == GTP_FATAL) gtp_panic(); } }