/* Copyright (C) 2016 Otsuki Tomoshi <tomoshi@m00.itscom.net> */
#include "go.h"
#include <stdarg.h>
#ifdef _WIN32
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#include <limits.h>
#define GetCurrentDir getcwd
#endif
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で通信に失敗するので。
setbuf(stdout, NULL);
setbuf(stderr, NULL); // 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;
if ((fp_in = fopen("paramter.bin","rb")) == NULL){
fprintf(stderr, "file open error: %s\n", "paramter.bin");
char path[260];
if (GetCurrentDir(path, sizeof(path)) != NULL) {
printf("please put paramter.bin into the directory: %s\n", path);
} else {
perror("getcwd");
}
return 0;
}
int n = fread(cnn_param,sizeof(cnn_t), sizeof(parameter_t)/sizeof(cnn_t), fp_in);
gtp(hdl);
return 0;
}