/* Copyright (C) 2016 Otsuki Tomoshi <tomoshi@m00.itscom.net> */
#include <stdio.h>
#include <stdarg.h>
#include <direct.h>
#include "go.h"
const char* X_CORD = { "-ABCDEFGHJKLMNOPQRST-\0" };
const char* (Y_CORD[BOARD_EDGE_SIZE + 2]) = { "-",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"
};
void send_gtp(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stdout, fmt, ap); // 標準出力に書き出す
va_end(ap);
}
// 相手の手を受信 "play W D17" のように来る
int get_receive_pos(int* tbn, char* str)
{
int pos_x = 0, pos_y = 0, x, y, y2;
if (!strncmp(&str[5], "W", 1)) {
*tbn = TBN_WH;
}
else if (!strncmp(&str[5], "B", 1)) {
*tbn = TBN_BK;
}
else {
fprintf(stderr, "tbn_err\n");
}
for (x = 1; x <= BOARD_EDGE_SIZE; x++) {
if (!strncmp(&str[7], &X_CORD[x], 1)) {
pos_x = x;
break;
}
}
for (y = 1; y <= 9; y++) { /* 1 keta me */
if (!strncmp(&str[8], Y_CORD[y], 1)) {
if (y == 1) {
for (y2 = 10; y2 <= 19; y2++) { /* 2 keta me */
if (!strncmp(&str[8], Y_CORD[y2], 2)) {
y = y2;
break;
}
}
}
pos_y = BOARD_EDGE_SIZE + 1 - y;
break;
}
}
fprintf(stderr, "x = %d, y = %d\n", pos_x, pos_y);
return X_Y_TO_POS(pos_x, pos_y);
}
int gtp(game_hdl_t* hdl)
{
char str[FRAME];
goban_t* ban = hdl->ban;
// stdoutをバッファリングしないように。GTPで通信に失敗するので。
//setvbuf(stdout, NULL);
// 修正: setvbuf 関数には 3 つの引数が必要です。
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0); // stderrに書くとGoGuiに表示される。
while (1) {
writeBan(ban);
fprintf(stderr, " NOW: tesuu: %d, tbn: %.1s, (PREV): ", ban->tesuu, &COLOR_NAME[TBN2COLOR(ban->tbn)]);
outPos(ban->histInfo[ban->tesuu - 1].pos), fprintf(stderr, "\n");
if (fgets(str, FRAME, stdin) == NULL) break; // 標準入力から読む
if (strstr(str, "boardsize")) {
send_gtp("= \n\n"); // "boardsize 19": 19路盤
if (atoi(&str[10]) != BOARD_EDGE_SIZE) {
fprintf(stderr, "illegal boardsize (%d != %d)\n", atoi(&str[10]), BOARD_EDGE_SIZE);
}
fprintf(stderr, "if you write in stderr, output into gogui\n");
}
else if (strstr(str, "clear_board")) {
set_initial_pos(ban);
send_gtp("= \n\n");
}
else if (strstr(str, "komi")) {
ban->komi = atof(&str[5]);
fprintf(stderr, "komi = %f\n", ban->komi);
send_gtp("= \n\n");
}
else if (strstr(str, "undo")) {
if (ban->tesuu >= 3) {
unmake_move(ban);
unmake_move(ban);
}
send_gtp("= \n\n");
}
else if (strstr(str, "name")) {
send_gtp("= deltaGo\n\n");
}
else if (strstr(str, "protocol_version")) {
send_gtp("= 2\n\n");
}
else if (strstr(str, "version")) {
send_gtp("= 1.0.0\n\n");
}
else if (strstr(str, "genmove w") || strstr(str, "genmove b")) {
int x, y, pos;
double pos2prob[XY_SIZE];
fprintf(stderr, "I'm thinking... \n");
double time_s = Tool_GetTimeNow();
get_feature(NULL, 0, ban->tesuu - 1, ban);
pos = get_cnn_prob(ban, hdl, pos2prob);
if (pos == 0) {
fprintf(stderr, "PASS\n\n");
send_gtp("= PASS\n\n");
}
else {
x = POS_TO_X(pos);
y = POS_TO_Y(pos);
fprintf(stderr, "%.1s%s\n\n", &X_CORD[x], Y_CORD[y]);
send_gtp("= %.1s%s\n\n", &X_CORD[x], Y_CORD[BOARD_EDGE_SIZE + 1 - y]);
}
outPos(pos);
fprintf(stderr, "\ntime = %f\n", Tool_GetTimeNow() - time_s);
make_move(pos, ban);
}
else if (strstr(str, "play")) { // 相手の手を受信 "play W D17" のように来る
int tbn;
int pos = get_receive_pos(&tbn, str);
if (tbn == ban->tbn) {
make_move(pos, ban);
}
else { // 置き碁の場合?はPASSを挿入
make_move(0, ban);
make_move(pos, ban);
}
send_gtp("= \n\n");
}
else {
send_gtp("= \n\n"); // それ以外のコマンドにはOKを返す
}
}
return 0;
}
int main(int argc, char** argv)
{
game_hdl_t* hdl;
if ((hdl = open_game_hdl(argc, argv)) == NULL) {
fprintf(stderr, "open game_hdl error\n");
return 0;
}
// read cnn parameter
FILE* fp_in;
errno_t err = fopen_s(&fp_in, "paramter.bin", "rb");
if (err != 0) {
fprintf(stderr, "file open error: %s\n", "paramter.bin");
char path[260];
if (_getcwd(path, sizeof(path)) != NULL) {
printf("カレントディレクトリ: %s\n", path);
}
else {
perror("getcwd");
}
return 1;
}
fread(cnn_param, sizeof(cnn_t), sizeof(parameter_t) / sizeof(cnn_t), fp_in);
gtp(hdl);
return 0;
}