My Project
ggs.c
Go to the documentation of this file.
1
11#include "board.h"
12#include "move.h"
13#include "options.h"
14#include "util.h"
15#include "ui.h"
16
17#include <assert.h>
18#include <ctype.h>
19#include <errno.h>
20#include <stdarg.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25
26#include <sys/types.h>
27#ifdef _WIN32
28 #include <winsock.h>
29 #include <winerror.h>
30 #include <ws2tcpip.h>
31 #define SHUT_RDWR SD_BOTH
32#else
33 #include <unistd.h>
34 #include <sys/socket.h>
35 #include <netdb.h>
36 #include <netinet/tcp.h>
37#endif
38
39
41#define WORD_SIZE 256
42
44#define GGS_BOARD_SIZE 256
45
47#define MOVELIST_SIZE 256
48
50typedef struct Text {
51 const char** line;
52 int n_lines;
54
69
71typedef struct GGSPlayer {
72 char *name;
73 double rating;
75
87
88/* match off message */
89typedef struct GGSMatchOff {
90 char *id;
93
94/* match on message */
100
101/* match request message */
108
109/* match board message */
128
129
130/* match admin message */
131typedef struct GGSAdmin {
132 char *command;
133 char name[16];
135
136/* GGSEvent. Deals with input from ggs */
137typedef struct GGSEvent {
138 int socket;
139 bool loop;
140 char *buffer;
141 Thread thread;
142 Lock lock;
144
145/* GGSClient structure */
146typedef struct GGSClient {
153 const char *me;
155 long long last_refresh;
156 struct {
157 char *cmd;
158 int i;
159 long long delay;
160 } loop[1];
161 struct {
162 char *cmd;
163 long long delay;
164 } once[1];
166
167static Log ggs_log[1];
168
169static char admin_list[][16] = {"delorme", "dan", "mic", "romano", "HCyrano", "romelica", ""};
170
171static const GGSClock GGS_CLOCK_INI = {0, 0, 0, 0, 0, 0, 0, 0, 0};
172static const GGSMatchType GGS_MATCH_TYPE_INI = {0, 0, 0, 0, 0, 0, 0, 0};
173
181static void text_init(Text *text)
182{
183 text->line = NULL;
184 text->n_lines =0;
185}
186
195static void text_add_line(Text *text, const char *line)
196{
197 ++text->n_lines;
198 text->line = (const char**) realloc(text->line, text->n_lines * sizeof (const char*));
199 if (text->line == NULL) fatal_error("Allocation error\n");
200 text->line[text->n_lines - 1] = line;
201 log_receive(ggs_log, "GGS ", "%s\n", line);
202}
203
212static void text_print(Text *text, FILE *f)
213{
214 int i;
215
216 for (i = 0; i < text->n_lines; ++i) {
217 fprintf(f, "GGS> %s\n", text->line[i]);
218 }
219}
220
228static void text_free(Text *text)
229{
230
231 int i;
232
233 for (i = 0; i < text->n_lines; ++i) {
234 free((void*)text->line[i]);
235 }
236 free((void*)text->line);
237 text_init(text);
238}
239
249static char *ggs_parse_line(const char *buffer, char **line)
250{
251 int n;
252 assert(buffer);
253
254 *line = NULL;
255 for (n = 0; buffer[n] && buffer[n] != '\n' && buffer[n] != '\r'; ++n) ;
256 if (buffer[n]) { /* complete line found */
257 *line = (char*) malloc(n + 1);
258 if (*line == NULL) fatal_error("Allocation error\n");
259 if (n > 0) memcpy(*line, buffer, n);
260 (*line)[n] = '\0';
261
262 while (buffer[n] == '\n' || buffer[n] == '\r') ++n;
263 } else { /* no or incomplete line found */
264 n = 0;
265 }
266 return (char*) (buffer + n);
267}
268
278static char* ggs_parse_text(const char *buffer, Text *text)
279{
280 char *line;
281 assert(buffer);
282
283 while (buffer[0] == '|' || text->n_lines == 0) {
284 buffer = ggs_parse_line(buffer, &line);
285 if (!line) break;
286 text_add_line(text, line);
287 };
288
289 return (char*) buffer;
290}
291
292
302static bool ggs_parse_int(int *value, const char *word)
303{
304 errno = 0;
305 parse_int(word, value);
306 return errno == 0;
307}
308
318static bool ggs_parse_double(double *value, const char *word) {
319 errno = 0;
320 parse_real(word, value);
321 return errno == 0;
322}
323
333static bool ggs_parse_move(int *move, const char *word) {
335 return *move != NOMOVE;
336}
337
347static bool ggs_parse_time(int *time, const char *word) {
348 errno = 0;
349 *time = string_to_time(parse_skip_spaces(word));
350 return errno == 0;
351}
352
362static bool ggs_parse_clock(GGSClock *ggsclock, const char *line) {
363 char time[WORD_SIZE];
364 const char *move;
365 char word[WORD_SIZE];
366
367 errno = 0;
368 *ggsclock = GGS_CLOCK_INI;
369 line = parse_field(line, word, WORD_SIZE, '/');
370 if (*word) {
371 move = parse_field(word, time, WORD_SIZE, ',');
372 if (!ggs_parse_time(&ggsclock->ini_time, time)) return false;
373 if (*move) {
374 if (*move == 'N') {
375 ggsclock->ini_flag = 1;
376 move++;
377 }
378 if (!ggs_parse_int(&ggsclock->ini_move, move)) return false;
379 }
380 }
381
382 line = parse_field(line, word, WORD_SIZE, '/');
383 if (*word) {
384 move = parse_field(word, time, WORD_SIZE, ',');
385 if (!ggs_parse_time(&ggsclock->inc_time, time)) return false;
386 if (*move) {
387 if (*move == 'N') {
388 ggsclock->inc_flag = 1;
389 move++;
390 }
391 if (!ggs_parse_int(&ggsclock->inc_move, move)) return false;
392 }
393 }
394
395 line = parse_field(line, word, WORD_SIZE, '\0');
396 if (*word) {
397 move = parse_field(word, time, WORD_SIZE, ',');
398 if (!ggs_parse_time(&ggsclock->ext_time, time)) return false;
399 if (*move) {
400 if (*move == 'N') {
401 ggsclock->ext_flag = 1;
402 move++;
403 }
404 if (!ggs_parse_int(&ggsclock->ext_move, move)) return false;
405 }
406 }
407
408 return true;
409}
410
411
422/* parse player name & rating */
423static bool ggs_player_set(GGSPlayer *player, const char *name, const char *rating) {
424 char word[WORD_SIZE];
425
426 if (name == NULL || *name == '\0') return false;
427
428 parse_word(name, word, WORD_SIZE);
429 player->name = string_duplicate(word);
430
431 rating = parse_skip_spaces(rating);
432 if (*rating == '(') ++rating;
433 return ggs_parse_double(&(player->rating), rating);
434}
435
444static void ggs_match_type_set(GGSMatchType *type, const char *word) {
445 const char *c;
446
447 *type = GGS_MATCH_TYPE_INI;
448
449 if (word) {
450 if (*word == 's') {
451 type->is_synchro = 1;
452 type->size = string_to_int(word + 1, 0);
453 } else {
454 type->size = string_to_int(word, 0);
455 }
456 for (c = word; *c; c++) {
457 if (*c == 'k') type->is_komi = 1;
458 if (*c == 'r') {
459 type->is_rand = 1;
460 type->discs = string_to_int(c + 1, 0);
461 }
462 if (*c == 'a') type->is_anti = 1;
463 }
464 }
465}
466
467
475static void ggs_player_free(GGSPlayer *player) {
476 assert(player);
477 free(player->name);
478 player->name = NULL;
479}
480
488static void ggs_MBR_free(void* v) {
489 GGSMatchOff *m = (GGSMatchOff*) v;
490 assert(m);
491 free(m->id);
492 m->id = 0;
494 ggs_player_free(m->player + 1);
495}
496
506static bool ggs_has_player(GGSPlayer *player, const char *me) {
507 return (strcmp(me, player[0].name) == 0 || strcmp(me, player[1].name) == 0);
508}
509
519static bool ggs_request(GGSRequest *request, Text *text)
520{
521 const char *line = text->line[0];
522 char word[WORD_SIZE];
523
524 line = parse_word(line, word, WORD_SIZE);
525 if (strcmp("/os:", word) == 0) {
526 line = parse_word(line, word, WORD_SIZE);
527 if (strcmp("+", word) == 0) {
528 if (*line) {
529 line = parse_word(line, word, WORD_SIZE);
530 request->id = string_duplicate(word);
531 return true;
532 }
533 }
534 }
535
536 return false;
537}
538
548static bool ggs_match_on(GGSMatchOn *match, Text *text)
549{
550 const char *line = text->line[0];
551 char word[WORD_SIZE];
552
553 line = parse_word(line, word, WORD_SIZE);
554 if (strcmp("/os:", word) != 0) return false;
555
556 line = parse_word(line, word, WORD_SIZE);
557 if (strcmp("+", word) != 0) return false;
558
559 line = parse_word(line, word, WORD_SIZE);
560 if (strcmp("match", word) != 0) return false;
561
562 line = parse_word(line, word, WORD_SIZE);
563 match->id = string_duplicate(word);
564
565 line = parse_word(line, word, WORD_SIZE);
566 if (!ggs_player_set(&(match->player[0]), line, word))return false;
567
568 line = parse_skip_word(line);
569
570 line = parse_word(line, word, WORD_SIZE);
571 if (!ggs_player_set(&(match->player[1]), line, word)) return false;
572 line = parse_skip_word(line);
573
574 line = parse_word(line, word, WORD_SIZE);
575 ggs_match_type_set(match->match_type, word);
576
577 line = parse_word(line, word, WORD_SIZE);
578 match->match_type->is_rated = (strcmp(word, "R") == 0) ? 1 : 0;
579
580 return true;
581}
582
593{
594 const char *line = text->line[0];
595 char word[WORD_SIZE];
596
597 line = parse_word(line, word, WORD_SIZE);
598 if (strcmp("/os:", word) != 0) return false;
599
600 line = parse_word(line, word, WORD_SIZE);
601 if (strcmp("-", word) != 0) return false;
602
603 line = parse_word(line, word, WORD_SIZE);
604 if (strcmp("match", word) != 0) return false;
605
606 line = parse_word(line, word, WORD_SIZE);
607 match->id = string_duplicate(word);
608
609 line = parse_word(line, word, WORD_SIZE);
610 if (!ggs_player_set(&(match->player[0]), line, word)) return false;
611 line = parse_skip_word(line);
612
613 line = parse_word(line, word, WORD_SIZE);
614 if (!ggs_player_set(&(match->player[1]), line, word)) return false;
615
616 return true;
617}
618
628static bool ggs_board(GGSBoard *board, Text *text)
629{
630 const char *line = text->line[0];
631 char word[WORD_SIZE];
632 int ii = 1, i, j;
633
634 if (text->n_lines < 17) return false;
635
636 if (*line == '\0') return false;
637
638 line = parse_word(line, word, WORD_SIZE);
639 if (strcmp("/os:", word) != 0) return false;
640
641 if (*line == '\0') return false;
642 line = parse_word(line, word, WORD_SIZE);
643 board->is_join = (strcmp("join", word) == 0);
644 board->is_update = (strcmp("update", word) == 0);
645
646 if ( !board->is_update && !board->is_join) {
647 return false;
648 }
649
650 if (*line == '\0') return false;
651 line = parse_word(line, word, WORD_SIZE);
652 board->id = string_duplicate(word);
653
654 if (*line == '\0') return false;
655 line = parse_word(line, word, WORD_SIZE);
656 ggs_match_type_set(board->match_type, word);
657
658 if (*line) {
659 line = parse_word(line, word, WORD_SIZE);
660 if (word[1] == '?') {
661 board->match_type->is_komi = 0;
662 board->komi = 0;
663 } else {
664 board->match_type->is_komi = 1;
665 ggs_parse_double(&board->komi, word + 1);
666 }
667 }
668
669 if (board->is_join) {
670 if (!ggs_parse_int(&board->move_list_n, text->line[1] + 1))
671 return false;
672 if (board->move_list_n > 0) {
673 if (text->n_lines < board->move_list_n + 30)
674 return false;
675 ii = 5;
676 for (i = 0; i < 8; i++) {
677 ++ii;
678 for (j = 0; j < 8; j++)
679 board->board_init[i * 8 + j] = text->line[ii][4 + j * 2];
680 }
681 ii += 3;
682 board->turn_init = text->line[ii][1];
683
684 for (i = 0; i < board->move_list_n; i++) {
685 ++ii;
686 parse_field(text->line[ii] + 6, word, WORD_SIZE, '/');
687 ggs_parse_move(board->move_list + i, word);
688 }
689 } else ii = 2;
690 }
691 if (text->n_lines < ii + 14)
692 return false;
693
694 line = parse_skip_word(text->line[ii]);
695 line = parse_word(line, word, WORD_SIZE);
696 ggs_parse_int(&board->move_no, word);
697 ggs_parse_move(&board->move, line);
698
699 ++ii;
700 line = parse_word(text->line[ii], word, WORD_SIZE);
701 if (!ggs_player_set(board->player, word + 1, line))
702 return false;
703 line = parse_skip_word(line + 1);
704 line = parse_word(line, word, WORD_SIZE);
705 board->color[0] = word[0];
706 if (!ggs_parse_clock(board->clock, line)) return false;
707
708 ++ii;
709 line = parse_word(text->line[ii], word, WORD_SIZE);
710 if (!ggs_player_set(board->player + 1, word + 1, line))
711 return false;
712 line = parse_skip_word(line + 1);
713 line = parse_word(line, word, WORD_SIZE);
714 board->color[1] = word[0];
715 if (!ggs_parse_clock(board->clock + 1, line)) return false;
716
717 ii += 2;
718
719 for (i = 0; i < 8; i++) {
720 ++ii;
721 for (j = 0; j < 8; j++)
722 board->board[i * 8 + j] = text->line[ii][4 + j * 2];
723 }
724 ii += 3;
725 board->turn = text->line[ii][1];
726
727 if (board->is_join && board->move_list_n == 0) {
728 memcpy(board->board_init, board->board, 64);
729 board->turn_init = board->turn;
730 }
731
732 return true;
733}
734
735
745static bool ggs_os_on(Text *text)
746{
747 if (strcmp(text->line[0], ": + /os 1") == 0) return true;
748 return false;
749}
750
760static bool ggs_os_off(Text *text)
761{
762 if (strcmp(text->line[0], ": - /os 1") == 0) return true;
763 return false;
764}
765
777static bool ggs_saio_delay(Text *text, long long *delay)
778{
779 const char *s = strstr(text->line[0], "Sorry, i will accept new games in");
780
781 if (s && strlen(s) > 35) {
782 errno = 0;
783 *delay = string_to_int(s + 34, 300) * 1000 + real_clock();
784 return (errno == 0);
785 }
786 return false;
787}
788
789
801static int ggs_admin(GGSAdmin *admin, Text *text)
802{
803 const char *line = text->line[0];
804 char word[WORD_SIZE];
805 int i;
806
807 line = parse_word(line, word, WORD_SIZE);
808 for (i = 0; *admin_list[i]; i++) {
809 if (strncmp(admin_list[i], word, strlen(admin_list[i])) == 0) {
810 admin->command = string_duplicate(line);
811 strcpy(admin->name, admin_list[i]);
812 return true;
813 }
814 }
815
816 return false;
817}
818
827static bool ggs_ready(Text *text)
828{
829 const char *line = text->line[0];
830 return strcmp(line, "READY") == 0;
831}
832
841static bool ggs_alert(Text *text)
842{
843 const char *line = text->line[0];
844 return strcmp(line, "ALERT") == 0;
845}
846
855static bool ggs_login(Text *text)
856{
857 const char *line = text->line[0];
858 return strcmp(line, ": Enter login (yours, or one you'd like to use).") == 0;
859}
860
869static bool ggs_password(Text *text)
870{
871 const char *line = text->line[0];
872 return strcmp(line, ": Enter your password.") == 0;
873}
874
883static void* ggs_event_loop(void *v)
884{
885 GGSEvent *event = (GGSEvent*) v;
886 enum {BUCKET_SIZE = 16384};
887 char buffer[BUCKET_SIZE + 1] = "";
888 int r, l;
889
890 while (event->loop) {
891 r = recv(event->socket, buffer, BUCKET_SIZE, 0);
892 if (r > 0) {
893 lock(event);
894 l = strlen(event->buffer);
895 event->buffer = (char*) realloc(event->buffer, r + l + 1);
896 memcpy(event->buffer + l, buffer, r);
897 event->buffer[l + r] = '\0';
898 *buffer = '\0';
899 unlock(event);
900 } else {
901 event->loop = false;
902 }
903 }
904
905 return NULL;
906}
907
915static void ggs_event_init(GGSEvent *event)
916{
917 struct addrinfo hints;
918 struct addrinfo *result, *rp = NULL;
919
920 lock_init(event);
921 event->loop = true;
922 event->buffer = (char*) calloc(1, 1);
923
924/* Windows needs this */
925#ifdef _WIN32
926 {
927 WSADATA wsaData;
928 int value = WSAStartup(MAKEWORD(2,2), &wsaData);
929 if (value != NO_ERROR) {
930 fatal_error("WSAStartup failed: %d \n", value);
931 }
932 }
933#endif
934
935 /* socket creation */
936 memset(&hints, 0, sizeof (struct addrinfo));
937 hints.ai_family = AF_INET;
938 hints.ai_socktype = SOCK_STREAM;
939 hints.ai_flags = AI_PASSIVE;
940 hints.ai_protocol = getprotobyname("tcp")->p_proto;
941 hints.ai_canonname = NULL;
942 hints.ai_addr = NULL;
943 hints.ai_next = NULL;
944
945 if (getaddrinfo(options.ggs_host, options.ggs_port, &hints, &result) == 0) {
946 for (rp = result; rp != NULL; rp = rp->ai_next) {
947 event->socket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
948 if (event->socket != -1) {
949 if (connect(event->socket, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Success */
950#ifdef _WIN32
951 closesocket(event->socket);
952 WSACleanup();
953#else
954 close(event->socket);
955#endif
956 }
957 }
958 if (rp == NULL) {
959 fatal_error("Could not connect to %s %s\n", options.ggs_host, options.ggs_port);
960 }
961 freeaddrinfo(result);
962 }
963
964 thread_create2(&event->thread, ggs_event_loop, event); // modified for iOS by lavox. 2018/1/16
965}
966
974static void ggs_event_free(GGSEvent *event)
975{
976 event->loop = false;
977 shutdown(event->socket, SHUT_RDWR);
978#ifdef _WIN32
979 closesocket(event->socket);
980 WSACleanup();
981#else
982 close(event->socket);
983#endif
984 thread_join(event->thread);
985 free(event->buffer);
986 lock_free(event);
987}
988
999static bool ggs_event_peek(GGSEvent *event, Text *text)
1000{
1001 bool ok = false;
1002 const char *s;
1003
1004 lock(event);
1005 if (*event->buffer) {
1006 s = ggs_parse_text(event->buffer, text);
1007 if (s > event->buffer) {
1008 memmove(event->buffer, s, strlen(s) + 1);
1009 ok = (*event->buffer != '|');
1010 }
1011 }
1012 unlock(event);
1013
1014 return ok;
1015}
1016
1024static void ggs_client_free(GGSClient *client) {
1025 ggs_event_free(&client->event);
1026 ggs_MBR_free(client->board);
1027 ggs_MBR_free(client->request);
1028 ggs_MBR_free(client->match_on);
1029 ggs_MBR_free(client->match_off);
1030}
1031
1043static void ggs_client_send(GGSClient *client, const char *fmt, ...) {
1044 int message_length;
1045 int size = 256;
1046 char *buffer;
1047 va_list ap;
1048
1049 if (fmt == NULL) return ;
1050
1051 for (;;) {
1052 buffer = (char*) malloc(size + 1);
1053 if (buffer == NULL) return;
1054 va_start(ap, fmt);
1055 message_length = vsnprintf(buffer, size, fmt, ap);
1056 va_end(ap);
1057
1058 if (message_length > 0 && message_length < size) break;
1059
1060 if (message_length > 0) size = message_length + 1;
1061 else size *= 2;
1062 free(buffer);
1063 }
1064
1065 log_send(ggs_log, "GGS", "%s", buffer);
1066 printf("GGS< %s", buffer);
1067 send(client->event.socket, buffer, message_length, 0);
1068
1069 free(buffer);
1070}
1071
1080static void ggs_client_refresh(GGSClient *client)
1081{
1082 /* send "tell /os continue" every minute */
1083 if (real_clock() - client->last_refresh > 60000) { // 60 sec.
1084 if (client->is_playing) ggs_client_send(client, "tell /os open 0\n" );
1085 else ggs_client_send(client, "tell /os open %d\n", options.ggs_open);
1086 ggs_client_send(client, "tell /os continue\n");
1087 client->last_refresh = real_clock();
1088 }
1089
1090 /* check loop */
1091 if (client->loop->delay != 0 && real_clock() - client->loop->delay > 0) {
1092 client->loop->delay = 0;
1093 ggs_client_send(client, "%s\n", client->loop->cmd);
1094 }
1095
1096 /* check once */
1097 if (client->once->cmd && client->once->delay != 0 && real_clock() - client->once->delay > 0) {
1098 client->once->delay = 0;
1099 ggs_client_send(client, "%s\n", client->once->cmd);
1100 }
1101}
1102
1110static void ui_login(UI *ui)
1111{
1112 GGSClient *client = ui->ggs;
1113
1114 /* sanity check */
1115 if (options.ggs_host == NULL) fatal_error("Unknown GGS host\n");
1116 if (options.ggs_port == NULL) fatal_error("Unknown GGS port\n");
1117 if (options.ggs_login == NULL) fatal_error("Unknown GGS login\n");
1118 if (options.ggs_password == NULL) fatal_error("Unknown GGS password\n");
1119 if (strlen(options.ggs_login) > 8) fatal_error("Bad GGS login %s (too much characters)\n", options.ggs_login);
1120
1121 printf("Connecting to GGS...\n");
1122 memset(client, 0, sizeof (GGSClient));
1123 client->me = options.ggs_login;
1124 client->loop->cmd = NULL;
1125 client->loop->i = 0;
1126 client->loop->delay = 0;
1127
1128 client->once->cmd = NULL;
1129 client->once->delay = 0;
1130 client->last_refresh = real_clock();
1131
1132 ggs_event_init(&client->event);
1133}
1134
1143static void ui_ggs_ponder(UI *ui, int turn) {
1144 Play *play;
1145
1147 play = ui->play;
1148 } else {
1149 play = ui->play + turn;
1150 }
1151
1152 play_ponder(play);
1153}
1154
1163static void ui_ggs_play(UI *ui, int turn) {
1164 long long real_time = -time_clock();
1165 int remaining_time = ui->ggs->board->clock[turn].ini_time;
1166 int extra_time = ui->ggs->board->clock[turn].ext_time;
1167 Play *play;
1168 Result *result;
1169 char move[4], line[32];
1170 const char *(search_state_array[6]) = {"running", "interrupted", "stop pondering", "out of time", "stopped on user demand", "completed"};
1171 char search_state[32];
1172
1173 if (ui->is_same_play) {
1174 play = ui->play;
1176 printf("<use a single %d tasks search while a single game is played>\n", options.n_task);
1179 play_stop_pondering(ui->play + 1);
1181 }
1182 } else {
1183 play = ui->play + turn;
1185 printf("<split single %d tasks search into two %d task searches>\n", options.n_task, options.n_task / 2);
1188 play_stop_pondering(ui->play + 1);
1190 search_share(ui->play[0].search, ui->play[1].search);
1191 ui_ggs_ponder(ui, turn ^ 1); // ponder opponent move
1192 }
1193 }
1194
1195 // game over detection...
1196 if (play_is_game_over(play)) {
1197 ggs_client_send(ui->ggs, "tell .%s *** GAME OVER ***\n", ui->ggs->me);
1198 return ;
1199 }
1200
1201 result = play->result;
1202
1203 if (remaining_time > 60000) remaining_time -= 10000; // keep 10s. for safety.
1204 else if (remaining_time > 10000) remaining_time -= 2000; // keep 2s. for safety.
1205 if (remaining_time < 1000) remaining_time = 1000; // set time to at list 1ms
1206 play_adjust_time(play, remaining_time, extra_time);
1207
1208 printf("<ggs: go thinking>\n");
1209 play_go(play, false);
1210
1211 real_time += time_clock();
1212
1213 move_to_string(result->move, play->player, move);
1214
1215 ggs_client_send(ui->ggs, "tell /os play %s %s/%d/%.2f\n", ui->ggs->board->id, move, result->score, 0.001 * (real_time + 1));
1216
1217 if (result->book_move) {
1218 printf("[%s plays %s in game %s ; score = %d from book]\n", ui->ggs->me, move, ui->ggs->board->id, result->score);
1219 ggs_client_send(ui->ggs, "tell .%s -----------------------------------------"
1220 "\\%s plays %s in game %s"
1221 "\\score == %d from book\n",
1222 ui->ggs->me,
1223 ui->ggs->me, move, ui->ggs->board->id,
1224 result->score
1225 );
1226 } else if (play->search->n_empties >= 15) { //avoid noisy display
1227 const char *bound;
1228 char s_nodes[16], s_speed[16];
1229
1230 if (result->bound[result->move].lower < result->score && result->score == result->bound[result->move].upper) bound = "<=";
1231 else if (result->bound[result->move].lower == result->score && result->score < result->bound[result->move].upper) bound = ">=";
1232 else bound = "==";
1233
1234 info("<%s plays %s in game %s ; score = %d at %d@%d%% ; %lld nodes in %.1fs (%.0f nodes/s.)>\n",
1235 ui->ggs->me, move, ui->ggs->board->id,
1236 result->score, result->depth, selectivity_table[result->selectivity].percent,
1237 result->n_nodes, 0.001 * real_time, (result->n_nodes / (0.001 * real_time + 0.001))
1238 );
1239 if (play->search->stop == STOP_TIMEOUT) {
1240 sprintf(search_state, "%s at %d@%d%%", search_state_array[play->search->stop], play->search->depth, selectivity_table[play->search->selectivity].percent);
1241 } else {
1242 sprintf(search_state, "%s", search_state_array[play->search->stop]);
1243 }
1244 ggs_client_send(ui->ggs, "tell .%s -----------------------------------------"
1245 "\\%s plays %s in game %s using %d thread%s"
1246 "\\score %s %+02d at %d@%d%% ; PV: %s ;"
1247 "\\nodes: %s ; time: search = %.1fs, move = %.1fs; speed: %s."
1248 "\\search %s\n",
1249 ui->ggs->me,
1250 ui->ggs->me, move, ui->ggs->board->id, search_count_tasks(play->search), search_count_tasks(play->search) > 1 ? "s ;" : " ;",
1251 bound, result->score,
1252 result->depth, selectivity_table[result->selectivity].percent,
1253 line_to_string(result->pv, 8, " ", line),
1254 format_scientific(result->n_nodes, "N", s_nodes), 0.001 * result->time, 0.001 * real_time, format_scientific(result->n_nodes / (0.001 * result->time+ 0.001), "N/s", s_speed),
1255 search_state
1256 );
1257 }
1258}
1259
1269static void ui_ggs_join(UI *ui) {
1270 char buffer[256];
1271 char s_move[4];
1272 Play *play;
1273 int edax_turn, i;
1274
1275 printf("[received GGS_BOARD_JOIN]\n");
1276
1277 // set correct played game
1278 if (strcmp(ui->ggs->board->player[0].name, ui->ggs->me) == 0) {
1279 play = ui->play;
1280 edax_turn = BLACK;
1281 } else if (strcmp(ui->ggs->board->player[1].name, ui->ggs->me) == 0) {
1282 play = ui->play + 1;
1283 edax_turn = WHITE;
1284 } else {
1285 warn("Edax is not concerned by this game\n");
1286 return ;
1287 }
1288
1289 // non synchro games => play a single match
1290 if (!ui->ggs->board->match_type->is_synchro) play = ui->play;
1291
1292 // set board
1293 sprintf(buffer, "%s %c", ui->ggs->board->board_init, ui->ggs->board->turn_init);
1294 play_set_board(play, buffer);
1295
1296 for (i = 0; i < ui->ggs->board->move_list_n; i++) {
1297 if (!play_move(play, ui->ggs->board->move_list[i])) {
1298 error("cannot play GGS move %s ?", move_to_string(ui->ggs->board->move_list[i], play->player, s_move));
1299 break;
1300 }
1301 }
1302 printf("[%s's turn in game %s]\n", ui->ggs->board->player[play->player].name, ui->ggs->board->id);
1303 board_print(play->board, play->player, stdout);
1304
1305 ui->is_same_play = (ui->ggs->board->move_list_n == 0 || board_equal(ui->play[0].board, ui->play[1].board) || !ui->ggs->board->match_type->is_synchro);
1306 if (ui->is_same_play) printf("[Playing same game]\n");
1307
1308 // set time & start thinking
1309 if (play->player == edax_turn) {
1310 printf("<My turn>\n");
1311 ggs_client_send(ui->ggs, "tell .%s =====================================\n", ui->ggs->me);
1312 ui_ggs_play(ui, edax_turn);
1313 ui_ggs_ponder(ui, edax_turn);
1314 } else {
1315 printf("[Waiting opponent move]\n");
1316// ui_ggs_ponder(ui, edax_turn);
1317 }
1318}
1319
1327static void ui_ggs_update(UI *ui) {
1328 char buffer[256], s_move[4];
1329 Play *play;
1330 int edax_turn, turn;
1331 Board board[1];
1332
1333 printf("[received GGS_BOARD_UPDATE]\n");
1334
1335 // set correct played game
1336 if (strcmp(ui->ggs->board->player[0].name, ui->ggs->me) == 0) {
1337 play = ui->play;
1338 edax_turn = BLACK;
1339 } else if (strcmp(ui->ggs->board->player[1].name, ui->ggs->me) == 0) {
1340 play = ui->play + 1;
1341 edax_turn = WHITE;
1342 } else {
1343 return ;
1344 }
1345
1346 if (!ui->ggs->board->match_type->is_synchro) play = ui->play;
1347
1348 // set board as an edax's board
1349 sprintf(buffer, "%s %c", ui->ggs->board->board, ui->ggs->board->turn);
1350 turn = board_set(board, buffer);
1351
1352 // update the board... if possible
1353 if (!play_move(play, ui->ggs->board->move)) {
1354 info("<Updating with bad move %s>\n", move_to_string(ui->ggs->board->move, play->player, s_move));
1355 }
1356
1357 if (!board_equal(board, play->board)) { // may happens when game diverges
1358 info("<Resynchronize boards: diverging games>\n");
1359 *play->board = *board; play->player = turn;
1360 }
1361
1362 if (turn != play->player) { // should never happen: TODO fatal error?
1363 printf("[WARNING: updating player's turn]\n");
1364 play->player = turn;
1365 }
1366
1367 printf("[%s's turn in game %s]\n", ui->ggs->board->player[play->player].name, ui->ggs->board->id);
1368
1369 // playing same game... ?
1370 ui->is_same_play = (!ui->ggs->board->match_type->is_synchro || board_equal(ui->play[0].board, ui->play[1].board));
1371 if (ui->is_same_play) printf("<Playing same game...>\n");
1372
1373 // set time & start thinking
1374 if (play->player == edax_turn) {
1375 printf("<My turn>\n");
1376 ui_ggs_play(ui, edax_turn);
1377 } else {
1378 printf("<Opponent turn>\n");
1379 ui_ggs_ponder(ui, edax_turn);
1380 }
1381}
1382
1390void ui_init_ggs(UI *ui) {
1391 const int n_task = options.n_task;
1392
1393 ui->ggs = (GGSClient*) malloc (sizeof (GGSClient));
1394 if (ui->ggs == NULL) fatal_error("ui_init_ggs: cannot allocate the GGS client\n");
1395
1396 play_init(ui->play, ui->book);
1397 ui->book->search = ui->play->search;
1399
1400 ui->play[0].search->id = 1;
1401 options.n_task = 1;
1402 play_init(ui->play + 1, ui->book);
1403 ui->play[1].search->id = 2;
1404 options.n_task = n_task;
1406
1407 ui_login(ui);
1408}
1409
1418void ui_loop_ggs(UI *ui) {
1419 char *cmd = NULL, *param = NULL;
1420 Text text[1];
1421 GGSClient *client = ui->ggs;
1422
1423 ui->mode = 3;
1424
1425 text_init(text);
1426 for (;;) {
1427 relax(10);
1428
1429 /* look for a user event */
1430 if (ui_event_peek(ui, &cmd, &param)) {
1431 /* stop the search */
1432 if (strcmp(cmd, "stop") == 0) {
1433 if (ui->play[0].state == IS_THINKING) play_stop(ui->play);
1434 else if (ui->play[1].state == IS_THINKING) play_stop(ui->play + 1);
1435
1436 /* repeat a cmd <n> times */
1437 } else if (strcmp(cmd, "loop") == 0) {
1438 free(client->loop->cmd);
1439 errno = 0;
1440 client->loop->cmd = string_duplicate(parse_int(param, &client->loop->i));
1441 if (errno) client->loop->i = 100;
1442 if (client->loop->i > 0) {
1443 info("<loop %d>\n", client->loop->i);
1444 --client->loop->i;
1445 ggs_client_send(client, "%s\n", client->loop->cmd);
1446 }
1447
1448 /* exit from ggs */
1449 } else if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "q") == 0) {
1450 ggs_client_send(client, "tell .%s Bye bye!\n", client->me);
1451 ggs_client_send(client, "quit\n");
1452 free(cmd); free(param);
1453 return;
1454
1455 /* send the command to ggs */
1456 } else {
1457 ggs_client_send(client, "%s %s\n", cmd, param);
1458 }
1459 }
1460
1461 /* stay on line... */
1462 ggs_client_refresh(client);
1463
1464 /* look for a ggs event */
1465 if (!ggs_event_peek(&client->event, text)) {
1466 continue;
1467 }
1468
1469 text_print(text, stdout);
1470
1471 /* login */
1472 if (ggs_login(text)) {
1473 ggs_client_send(client, "%s\n", options.ggs_login);
1474
1475 /* password */
1476 } else if (ggs_password(text)) {
1477 ggs_client_send(client, "%s\n", options.ggs_password);
1478
1479 ggs_client_send(client, "vt100 -\n");
1480 ggs_client_send(client, "bell -t -tc -tg -n -nc -ng -ni -nn\n");
1481 ggs_client_send(client, "verbose -news -faq -help -ack\n");
1482 ggs_client_send(client, "chann %%\n");
1483 ggs_client_send(client, "chann + .chat\n");
1484 ggs_client_send(client, "chann + .%s\n", client->me);
1485 ggs_client_send(client, "tell .%s Hello!\n", client->me);
1486
1487 /* os on */
1488 } else if (ggs_os_on(text)) {
1489 printf("[received GGS_OS_ON]\n");
1490 ggs_client_send(client, "tell /os trust +\n" );
1491 ggs_client_send(client, "tell /os rated +\n" );
1492 ggs_client_send(client, "tell /os request +\n" );
1493 ggs_client_send(client, "tell /os client -\n" );
1494 ggs_client_send(client, "tell /os open %d\n", options.ggs_open);
1495 ggs_client_send(client, "mso\n" );
1496
1497 /* os off */
1498 } else if (ggs_os_off(text)) {
1499 printf("[received GGS_OS_OFF]\n");
1500
1501 /* match on */
1502 } else if (ggs_match_on(client->match_on, text)) {
1503 if (ggs_has_player(client->match_on->player, client->me)) {
1504 printf("[received GGS_MATCH_ON]\n");
1505 client->is_playing = true;
1506 ggs_client_send(client, "tell /os open 0\n" );
1507 } else {
1508 printf("[received GGS_WATCH_ON]\n");
1509 }
1510
1511 /* match off */
1512 } else if (ggs_match_off(client->match_off, text)) {
1513 if (ggs_has_player(client->match_off->player, client->me)) {
1514 printf("[received GGS_MATCH_OFF]\n");
1515
1516 if (!client->match_on->match_type->is_rand) {
1517 if (client->match_on->match_type->is_synchro) {
1518 printf("[store match #1]\n");
1519 play_store(ui->play);
1520 printf("[store match #2]\n");
1521 play_store(ui->play + 1);
1522 } else {
1523 printf("[store match]\n");
1524 play_store(ui->play);
1525 }
1526 if (ui->book->need_saving) {
1528 ui->book->need_saving = false;
1529 }
1530 }
1531
1532 client->is_playing = false;
1533 ggs_client_send(client, "tell /os open %d\n", options.ggs_open);
1534 if (client->loop->i > 0) {
1535 info("<loop %d>\n", client->loop->i);
1536 --client->loop->i;
1537 client->loop->delay = 10000 + real_clock(); // wait 10 sec.
1538 }
1539 } else {
1540 printf("[received GGS_WATCH_OFF]\n");
1541 }
1542
1543 /* board join/update */
1544 } else if (ggs_board(client->board, text)) {
1545 if (ggs_has_player(client->board->player, client->me)) {
1546 if (client->board->is_join) ui_ggs_join(ui);
1547 else ui_ggs_update(ui);
1548 } else {
1549 printf("[received GGS_WATCH_BOARD]\n");
1550 }
1551
1552 /* request */
1553 } else if (ggs_request(client->request, text)) {
1554 printf("[received GGS_REQUEST]\n");
1555
1556 /* admin on */
1557 } else if (ggs_admin(client->admin, text)) {
1558 printf("[received GGS_ADMIN_CMD]\n");
1559 ggs_client_send(client, client->admin->command);
1560 ggs_client_send(client, "\ntell %s command processed\n", client->admin->name);
1561
1562 /* To request Saio a game later */
1563 } else if (ggs_saio_delay(text, &client->once->delay)) {
1564 printf("[received GGS_SAIO_DELAY]\n");
1565 free(client->once->cmd); client->once->cmd = NULL;
1566 if (cmd != NULL && param != NULL) {
1567 if (strcmp(cmd, "loop") == 0) {
1568 client->once->cmd = string_duplicate(client->loop->cmd);
1569 } else {
1570 client->once->cmd = (char*) malloc(strlen(cmd) + strlen(param) + 3);
1571 sprintf(client->once->cmd, "%s %s\n", cmd, param);
1572 }
1573 printf("[received GGS_SAIO_DELAY, retry request in %.1f s]\n", 0.001 * (client->once->delay - real_clock()));
1574 } else {
1575 client->once->delay = 0;
1576 }
1577
1578 /* READY */
1579 } else if (ggs_ready(text)) {
1580
1581 /* ALERT */
1582 } else if (ggs_alert(text)) {
1583 printf("[received ALERT]\n");
1584
1585 /* Other messages */
1586 } else {
1587 }
1588 text_free(text);
1589 }
1590}
1591
1599void ui_free_ggs(UI *ui) {
1600 play_free(ui->play);
1601 play_free(ui->play + 1);
1603 book_free(ui->book);
1604 ggs_client_free(ui->ggs);
1605 free(ui->ggs->loop->cmd);
1606 free(ui->ggs->once->cmd);
1607 free(ui->ggs);
1609}
1610
void board_print(const Board *board, const int player, FILE *f)
Print out the board.
Definition board.c:1230
bool board_equal(const Board *b1, const Board *b2)
Compare two board for equality.
Definition board.c:335
int board_set(Board *board, const char *string)
Set a board from a string description.
Definition board.c:154
void book_free(Book *book)
Free resources used by the opening book.
Definition book.c:1422
void book_save(Book *book, const char *file)
Save an opening book.
Definition book.c:1622
void book_load(Book *book, const char *file)
Load the opening book.
Definition book.c:1471
@ NOMOVE
Definition const.h:37
@ WHITE
Definition const.h:43
@ BLACK
Definition const.h:42
@ STOP_TIMEOUT
Definition const.h:74
@ IS_THINKING
Definition const.h:103
static void ggs_client_free(GGSClient *client)
ggs_client_free
Definition ggs.c:1024
static void text_init(Text *text)
text_init
Definition ggs.c:181
static bool ggs_match_on(GGSMatchOn *match, Text *text)
ggs_match_on
Definition ggs.c:548
void ui_free_ggs(UI *ui)
ui_free_ggs
Definition ggs.c:1599
static char * ggs_parse_line(const char *buffer, char **line)
ggs_parse_line
Definition ggs.c:249
static Log ggs_log[1]
Definition ggs.c:167
struct Text Text
struct GGSEvent GGSEvent
void ui_loop_ggs(UI *ui)
ui_loop_ggs
Definition ggs.c:1418
struct GGSClock GGSClock
static bool ggs_player_set(GGSPlayer *player, const char *name, const char *rating)
ggs_player_set
Definition ggs.c:423
static bool ggs_alert(Text *text)
ggs_alert
Definition ggs.c:841
static void ggs_client_refresh(GGSClient *client)
ggs_client_refresh
Definition ggs.c:1080
static bool ggs_password(Text *text)
ggs_password
Definition ggs.c:869
static void text_print(Text *text, FILE *f)
text_print
Definition ggs.c:212
static const GGSMatchType GGS_MATCH_TYPE_INI
Definition ggs.c:172
static bool ggs_has_player(GGSPlayer *player, const char *me)
ggs_match_check_destination
Definition ggs.c:506
static void ui_login(UI *ui)
ui_login
Definition ggs.c:1110
static void ui_ggs_play(UI *ui, int turn)
ui_ggs_play
Definition ggs.c:1163
static bool ggs_login(Text *text)
ggs_login
Definition ggs.c:855
struct GGSMatchOn GGSMatchOn
static bool ggs_board(GGSBoard *board, Text *text)
ggs_board
Definition ggs.c:628
static bool ggs_parse_time(int *time, const char *word)
ggs_parse_move
Definition ggs.c:347
static bool ggs_os_on(Text *text)
ggs_os_on
Definition ggs.c:745
static bool ggs_parse_clock(GGSClock *ggsclock, const char *line)
ggs_parse_clock
Definition ggs.c:362
static void text_free(Text *text)
text_free
Definition ggs.c:228
static void ggs_player_free(GGSPlayer *player)
ggs_player_free
Definition ggs.c:475
static void ggs_event_init(GGSEvent *event)
ggs_event_init
Definition ggs.c:915
static void ggs_event_free(GGSEvent *event)
ggs_event_free
Definition ggs.c:974
struct GGSAdmin GGSAdmin
#define GGS_BOARD_SIZE
Definition ggs.c:44
static char admin_list[][16]
Definition ggs.c:169
static bool ggs_saio_delay(Text *text, long long *delay)
ggs_saio_delay
Definition ggs.c:777
static bool ggs_match_off(GGSMatchOff *match, Text *text)
ggs_match_off
Definition ggs.c:592
static bool ggs_os_off(Text *text)
ggs_os_off
Definition ggs.c:760
#define WORD_SIZE
Definition ggs.c:41
static bool ggs_parse_move(int *move, const char *word)
ggs_parse_move
Definition ggs.c:333
static void ggs_client_send(GGSClient *client, const char *fmt,...)
ggs_client_send
Definition ggs.c:1043
static const GGSClock GGS_CLOCK_INI
Definition ggs.c:171
struct GGSBoard GGSBoard
struct GGSRequest GGSRequest
struct GGSClient GGSClient
static bool ggs_request(GGSRequest *request, Text *text)
ggs_request
Definition ggs.c:519
struct GGSMatchOff GGSMatchOff
static bool ggs_parse_int(int *value, const char *word)
ggs_parse_int
Definition ggs.c:302
static bool ggs_ready(Text *text)
ggs_ready
Definition ggs.c:827
struct GGSPlayer GGSPlayer
static bool ggs_parse_double(double *value, const char *word)
ggs_parse_double
Definition ggs.c:318
void ui_init_ggs(UI *ui)
ui_init_ggs
Definition ggs.c:1390
#define MOVELIST_SIZE
Definition ggs.c:47
static void ui_ggs_ponder(UI *ui, int turn)
ui_ggs_ponder
Definition ggs.c:1143
static void * ggs_event_loop(void *v)
ggs_event_loop
Definition ggs.c:883
static int ggs_admin(GGSAdmin *admin, Text *text)
ggs_admin
Definition ggs.c:801
struct GGSMatchType GGSMatchType
static void ui_ggs_update(UI *ui)
ui_ggs_update
Definition ggs.c:1327
static char * ggs_parse_text(const char *buffer, Text *text)
ggs_parse_text
Definition ggs.c:278
static void text_add_line(Text *text, const char *line)
text_add_line
Definition ggs.c:195
static void ggs_MBR_free(void *v)
ggs_MBR_free
Definition ggs.c:488
static void ggs_match_type_set(GGSMatchType *type, const char *word)
ggs_match_type_set
Definition ggs.c:444
static bool ggs_event_peek(GGSEvent *event, Text *text)
ggs_event_peek
Definition ggs.c:999
static void ui_ggs_join(UI *ui)
ui_ggs_join
Definition ggs.c:1269
char * line_to_string(const Line *line, int n, const char *separator, char *string)
Line to string.
Definition move.c:635
char * move_to_string(const int x, const int player, char *s)
Print out a move.
Definition move.c:76
static bool match(const char *s1, const char *s2)
Definition opening.c:1274
Options options
Definition options.c:22
void play_store(Play *play)
store the game into the opening book
Definition play.c:1175
void play_set_board(Play *play, const char *board)
Set a new board.
Definition play.c:810
void play_ponder(Play *play)
Ponder.
Definition play.c:729
void play_stop_pondering(Play *play)
Stop pondering.
Definition play.c:749
bool play_move(Play *play, int x)
Play a move.
Definition play.c:889
void play_init(Play *play, Book *book)
Initialization.
Definition play.c:27
void play_adjust_time(Play *play, const int left, const int extra)
adjust time.
Definition play.c:1211
bool play_is_game_over(Play *play)
Check if game is over.
Definition play.c:190
void play_go(Play *play, const bool update)
Start thinking.
Definition play.c:214
void play_stop(Play *play)
Stop thinking.
Definition play.c:769
void play_free(Play *play)
Free resources.
Definition play.c:52
const Selectivity selectivity_table[]
Definition search.c:97
void search_set_task_number(Search *search, const int n)
Change the number of task.
Definition search.c:847
int search_count_tasks(const Search *search)
Count the number of tasks used in parallel search.
Definition search.c:1324
void search_share(const Search *src, Search *dest)
Share search information.
Definition search.c:1312
Definition board.h:26
bool need_saving
Definition book.h:47
Search * search
Definition book.h:49
int lower
Definition search.h:36
int upper
Definition search.h:37
Definition ggs.c:131
char * command
Definition ggs.c:132
char name[16]
Definition ggs.c:133
Definition ggs.c:110
int move_list[MOVELIST_SIZE]
Definition ggs.c:125
int move_list_n
Definition ggs.c:126
int move
Definition ggs.c:118
double komi
Definition ggs.c:115
char board_init[GGS_BOARD_SIZE]
Definition ggs.c:123
int move_no
Definition ggs.c:119
int is_join
Definition ggs.c:116
GGSPlayer player[2]
Definition ggs.c:112
char turn
Definition ggs.c:122
char board[GGS_BOARD_SIZE]
Definition ggs.c:121
int is_update
Definition ggs.c:117
char * id
Definition ggs.c:111
char color[2]
Definition ggs.c:120
GGSClock clock[2]
Definition ggs.c:114
GGSMatchType match_type[1]
Definition ggs.c:113
char turn_init
Definition ggs.c:124
Definition ggs.c:146
long long delay
Definition ggs.c:159
struct GGSClient::@17 loop[1]
GGSRequest request[1]
Definition ggs.c:148
GGSEvent event
Definition ggs.c:152
const char * me
Definition ggs.c:153
char * cmd
Definition ggs.c:157
GGSAdmin admin[1]
Definition ggs.c:151
GGSBoard board[1]
Definition ggs.c:147
struct GGSClient::@18 once[1]
bool is_playing
Definition ggs.c:154
GGSMatchOn match_on[1]
Definition ggs.c:149
GGSMatchOff match_off[1]
Definition ggs.c:150
int i
Definition ggs.c:158
long long last_refresh
Definition ggs.c:155
Definition ggs.c:56
int inc_flag
Definition ggs.c:58
int inc_time
Definition ggs.c:66
int ext_flag
Definition ggs.c:59
int ini_flag
Definition ggs.c:57
int ini_time
Definition ggs.c:65
int ext_move
Definition ggs.c:63
int ext_time
Definition ggs.c:67
int inc_move
Definition ggs.c:62
int ini_move
Definition ggs.c:61
Definition ggs.c:137
bool loop
Definition ggs.c:139
int socket
Definition ggs.c:138
char * buffer
Definition ggs.c:140
Thread thread
Definition ggs.c:141
Lock lock
Definition ggs.c:142
Definition ggs.c:89
char * id
Definition ggs.c:90
GGSPlayer player[2]
Definition ggs.c:91
Definition ggs.c:95
GGSPlayer player[2]
Definition ggs.c:97
char * id
Definition ggs.c:96
GGSMatchType match_type[1]
Definition ggs.c:98
Definition ggs.c:77
int is_rand
Definition ggs.c:82
int is_synchro
Definition ggs.c:80
int is_rated
Definition ggs.c:79
int is_komi
Definition ggs.c:81
int is_anti
Definition ggs.c:83
int is_saved
Definition ggs.c:78
int size
Definition ggs.c:85
int discs
Definition ggs.c:84
Definition ggs.c:71
double rating
Definition ggs.c:73
char * name
Definition ggs.c:72
Definition ggs.c:102
char * id
Definition ggs.c:103
GGSPlayer player[2]
Definition ggs.c:104
GGSClock clock[2]
Definition ggs.c:106
GGSMatchType match_type[1]
Definition ggs.c:105
LogFile.
Definition util.h:423
int n_task
Definition options.h:29
char * ggs_host
Definition options.h:63
char * ggs_password
Definition options.h:65
char * ggs_login
Definition options.h:64
bool ggs_open
Definition options.h:67
char * ggs_log_file
Definition options.h:79
char * ggs_port
Definition options.h:66
char * book_file
Definition options.h:59
Definition play.h:25
int player
Definition play.h:32
Board board[1]
Definition play.h:26
Result result[1]
Definition play.h:29
Search search[1]
Definition play.h:28
volatile PlayState state
Definition play.h:37
Definition search.h:41
bool book_move
Definition search.h:50
int move
Definition search.h:44
unsigned long long n_nodes
Definition search.h:49
int score
Definition search.h:45
long long time
Definition search.h:48
int selectivity
Definition search.h:43
Line pv[1]
Definition search.h:47
int depth
Definition search.h:42
Bound bound[BOARD_SIZE+2]
Definition search.h:46
int n_empties
Definition search.h:99
int id
Definition search.h:101
int depth
Definition search.h:117
volatile Stop stop
Definition search.h:122
int selectivity
Definition search.h:118
int percent
Definition search.h:28
Definition ggs.c:50
const char ** line
Definition ggs.c:51
int n_lines
Definition ggs.c:52
Definition ui.h:31
struct GGSClient * ggs
Definition ui.h:34
Play play[2]
Definition ui.h:32
Book book[1]
Definition ui.h:33
bool is_same_play
Definition ui.h:35
int mode
Definition ui.h:37
bool ui_event_peek(UI *ui, char **cmd, char **param)
Wait input.
Definition ui.c:160
User interface header.
char * string_duplicate(const char *s)
Duplicate a string.
Definition util.c:299
char * parse_int(const char *string, int *result)
Parse an integer.
Definition util.c:761
void thread_create2(Thread *thread, void *(*function)(void *), void *data)
Create a thread.
Definition util.c:922
char * parse_skip_word(const char *string)
Skip word.
Definition util.c:528
void thread_join(Thread thread)
Join a thread.
Definition util.c:940
long long(* time_clock)(void)
Time clock.
Definition util.c:122
int string_to_coordinate(const char *s)
Convert the two first chars of a string into a coordinate.
Definition util.c:384
char * parse_field(const char *string, char *word, unsigned int n, char separator)
Parse a field.
Definition util.c:582
char * parse_real(const char *string, double *result)
Parse a real number (as a double floating point).
Definition util.c:796
int string_to_int(const char *s, const int default_value)
Convert a string into an integer.
Definition util.c:457
char * parse_skip_spaces(const char *string)
Skip spaces.
Definition util.c:514
char * parse_word(const char *string, char *word, unsigned int n)
Parse a word.
Definition util.c:562
char * format_scientific(double v, const char *unit, char *f)
Format a value with a unit.
Definition util.c:222
void relax(int t)
sleep for t ms.
Definition util.c:203
long long string_to_time(const char *string)
Read time as "D:HH:MM:SS.C".
Definition util.c:320
Miscellaneous utilities header.
#define log_receive(l, title,...)
log a reception
Definition util.h:451
#define log_close(l)
Close an opened log file.
Definition util.h:435
#define error(...)
Display an error message as "ERROR : filename : funcname : line number : ...".
Definition util.h:361
long long real_clock(void)
#define fatal_error(...)
Display an error message as "FATAL_ERROR : file name : function name : line number : ....
Definition util.h:349
#define info(...)
Display a message.
Definition util.h:382
#define warn(...)
Display a warning message as "WARNING : ... ".
Definition util.h:373
#define log_open(l, file)
open a log file if allowed.
Definition util.h:429
#define log_send(l, title,...)
log a sending
Definition util.h:460