Merge pull request #41 from avysk/msys-fixes
[pachi.git] / pachi.c
blob8a5c21b0f514945a8eb5746716aa30b6926bb54f
1 #define DEBUG
2 #include <assert.h>
3 #include <getopt.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <time.h>
8 #include <unistd.h>
10 #include "board.h"
11 #include "debug.h"
12 #include "engine.h"
13 #include "replay/replay.h"
14 #include "montecarlo/montecarlo.h"
15 #include "random/random.h"
16 #include "patternscan/patternscan.h"
17 #include "patternplay/patternplay.h"
18 #include "joseki/joseki.h"
19 #include "t-unit/test.h"
20 #include "uct/uct.h"
21 #include "distributed/distributed.h"
22 #include "gtp.h"
23 #include "chat.h"
24 #include "timeinfo.h"
25 #include "random.h"
26 #include "version.h"
27 #include "network.h"
28 #include "uct/tree.h"
29 #include "dcnn.h"
31 int debug_level = 3;
32 bool debug_boardprint = true;
33 long verbose_logs = 0;
34 int seed;
37 enum engine_id {
38 E_RANDOM,
39 E_REPLAY,
40 E_PATTERNSCAN,
41 E_PATTERNPLAY,
42 E_MONTECARLO,
43 E_UCT,
44 E_DISTRIBUTED,
45 E_JOSEKI,
46 #ifdef DCNN
47 E_DCNN,
48 #endif
49 E_MAX,
52 static struct engine *(*engine_init[E_MAX])(char *arg, struct board *b) = {
53 engine_random_init,
54 engine_replay_init,
55 engine_patternscan_init,
56 engine_patternplay_init,
57 engine_montecarlo_init,
58 engine_uct_init,
59 engine_distributed_init,
60 engine_joseki_init,
61 #ifdef DCNN
62 engine_dcnn_init,
63 #endif
66 static struct engine *init_engine(enum engine_id engine, char *e_arg, struct board *b)
68 char *arg = e_arg? strdup(e_arg) : e_arg;
69 assert(engine < E_MAX);
70 struct engine *e = engine_init[engine](arg, b);
71 if (arg) free(arg);
72 return e;
75 static void done_engine(struct engine *e)
77 if (e->done) e->done(e);
78 if (e->data) free(e->data);
79 free(e);
82 static void usage(char *name)
84 fprintf(stderr, "Pachi version %s\n", PACHI_VERSION);
85 fprintf(stderr, "Usage: %s [-e random|replay|montecarlo|uct|distributed|dcnn]\n"
86 " [-d DEBUG_LEVEL] [-D] [-r RULESET] [-s RANDOM_SEED] [-t TIME_SETTINGS] [-u TEST_FILENAME]\n"
87 " [-g [HOST:]GTP_PORT] [-l [HOST:]LOG_PORT] [-f FBOOKFILE] [ENGINE_ARGS]\n", name);
90 int main(int argc, char *argv[])
92 enum engine_id engine = E_UCT;
93 struct time_info ti_default = { .period = TT_NULL };
94 char *testfile = NULL;
95 char *gtp_port = NULL;
96 char *log_port = NULL;
97 int gtp_sock = -1;
98 char *chatfile = NULL;
99 char *fbookfile = NULL;
100 char *ruleset = NULL;
102 seed = time(NULL) ^ getpid();
104 int opt;
105 while ((opt = getopt(argc, argv, "c:e:d:Df:g:l:r:s:t:u:")) != -1) {
106 switch (opt) {
107 case 'c':
108 chatfile = strdup(optarg);
109 break;
110 case 'e':
111 if (!strcasecmp(optarg, "random")) {
112 engine = E_RANDOM;
113 } else if (!strcasecmp(optarg, "replay")) {
114 engine = E_REPLAY;
115 } else if (!strcasecmp(optarg, "montecarlo")) {
116 engine = E_MONTECARLO;
117 } else if (!strcasecmp(optarg, "uct")) {
118 engine = E_UCT;
119 } else if (!strcasecmp(optarg, "distributed")) {
120 engine = E_DISTRIBUTED;
121 } else if (!strcasecmp(optarg, "patternscan")) {
122 engine = E_PATTERNSCAN;
123 } else if (!strcasecmp(optarg, "patternplay")) {
124 engine = E_PATTERNPLAY;
125 } else if (!strcasecmp(optarg, "joseki")) {
126 engine = E_JOSEKI;
127 #ifdef DCNN
128 } else if (!strcasecmp(optarg, "dcnn")) {
129 engine = E_DCNN;
130 #endif
131 } else {
132 fprintf(stderr, "%s: Invalid -e argument %s\n", argv[0], optarg);
133 exit(1);
135 break;
136 case 'd':
137 debug_level = atoi(optarg);
138 break;
139 case 'D':
140 debug_boardprint = false;
141 break;
142 case 'f':
143 fbookfile = strdup(optarg);
144 break;
145 case 'g':
146 gtp_port = strdup(optarg);
147 break;
148 case 'l':
149 log_port = strdup(optarg);
150 break;
151 case 'r':
152 ruleset = strdup(optarg);
153 break;
154 case 's':
155 seed = atoi(optarg);
156 break;
157 case 't':
158 /* Time settings to follow; if specified,
159 * GTP time information is ignored. Useful
160 * e.g. when you want to force your bot to
161 * play weaker while giving the opponent
162 * reasonable time to play, or force play
163 * by number of simulations in timed games. */
164 /* Please see timeinfo.h:time_parse()
165 * description for syntax details. */
166 if (!time_parse(&ti_default, optarg)) {
167 fprintf(stderr, "%s: Invalid -t argument %s\n", argv[0], optarg);
168 exit(1);
170 ti_default.ignore_gtp = true;
171 assert(ti_default.period != TT_NULL);
172 break;
173 case 'u':
174 testfile = strdup(optarg);
175 break;
176 default: /* '?' */
177 usage(argv[0]);
178 exit(1);
182 dcnn_quiet_caffe(argc, argv);
183 if (log_port)
184 open_log_port(log_port);
186 fast_srandom(seed);
187 if (DEBUGL(0))
188 fprintf(stderr, "Random seed: %d\n", seed);
190 struct board *b = board_init(fbookfile);
191 if (ruleset) {
192 if (!board_set_rules(b, ruleset)) {
193 fprintf(stderr, "Unknown ruleset: %s\n", ruleset);
194 exit(1);
198 struct time_info ti[S_MAX];
199 ti[S_BLACK] = ti_default;
200 ti[S_WHITE] = ti_default;
202 chat_init(chatfile);
204 char *e_arg = NULL;
205 if (optind < argc)
206 e_arg = argv[optind];
207 struct engine *e = init_engine(engine, e_arg, b);
209 if (testfile) {
210 unittest(testfile);
211 return 0;
214 if (gtp_port) {
215 open_gtp_connection(&gtp_sock, gtp_port);
218 for (;;) {
219 char buf[4096];
220 while (fgets(buf, 4096, stdin)) {
221 if (DEBUGL(1))
222 fprintf(stderr, "IN: %s", buf);
224 enum parse_code c = gtp_parse(b, e, ti, buf);
225 if (c == P_ENGINE_RESET) {
226 ti[S_BLACK] = ti_default;
227 ti[S_WHITE] = ti_default;
228 if (!e->keep_on_clear) {
229 b->es = NULL;
230 done_engine(e);
231 e = init_engine(engine, e_arg, b);
233 } else if (c == P_UNKNOWN_COMMAND && gtp_port) {
234 /* The gtp command is a weak identity check,
235 * close the connection with a wrong peer. */
236 break;
239 if (!gtp_port) break;
240 open_gtp_connection(&gtp_sock, gtp_port);
242 done_engine(e);
243 chat_done();
244 free(testfile);
245 free(gtp_port);
246 free(log_port);
247 free(chatfile);
248 free(fbookfile);
249 free(ruleset);
250 return 0;