pachi_py/pachi/pachi.c (209 lines of code) (raw):
#define DEBUG
#include <assert.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "board.h"
#include "debug.h"
#include "engine.h"
#include "replay/replay.h"
#include "montecarlo/montecarlo.h"
#include "random/random.h"
#include "patternscan/patternscan.h"
#include "patternplay/patternplay.h"
#include "joseki/joseki.h"
#include "t-unit/test.h"
#include "uct/uct.h"
#include "distributed/distributed.h"
#include "gtp.h"
#include "chat.h"
#include "timeinfo.h"
#include "random.h"
#include "version.h"
#include "network.h"
#include "dcnn.h"
int debug_level = 3;
bool debug_boardprint = true;
long verbose_logs = 0;
int seed;
enum engine_id {
E_RANDOM,
E_REPLAY,
E_PATTERNSCAN,
E_PATTERNPLAY,
E_MONTECARLO,
E_UCT,
E_DISTRIBUTED,
E_JOSEKI,
E_MAX,
};
static struct engine *(*engine_init[E_MAX])(char *arg, struct board *b) = {
engine_random_init,
engine_replay_init,
engine_patternscan_init,
engine_patternplay_init,
engine_montecarlo_init,
engine_uct_init,
engine_distributed_init,
engine_joseki_init,
};
static struct engine *init_engine(enum engine_id engine, char *e_arg, struct board *b)
{
char *arg = e_arg? strdup(e_arg) : e_arg;
assert(engine < E_MAX);
struct engine *e = engine_init[engine](arg, b);
if (arg) free(arg);
return e;
}
static void done_engine(struct engine *e)
{
if (e->done) e->done(e);
if (e->data) free(e->data);
free(e);
}
static void usage(char *name)
{
fprintf(stderr, "Pachi version %s\n", PACHI_VERSION);
fprintf(stderr, "Usage: %s [-e random|replay|montecarlo|uct|distributed]\n"
" [-d DEBUG_LEVEL] [-D] [-r RULESET] [-s RANDOM_SEED] [-t TIME_SETTINGS] [-u TEST_FILENAME]\n"
" [-g [HOST:]GTP_PORT] [-l [HOST:]LOG_PORT] [-f FBOOKFILE] [ENGINE_ARGS]\n", name);
}
int main(int argc, char *argv[])
{
enum engine_id engine = E_UCT;
struct time_info ti_default = { .period = TT_NULL };
char *testfile = NULL;
char *gtp_port = NULL;
char *log_port = NULL;
int gtp_sock = -1;
char *chatfile = NULL;
char *fbookfile = NULL;
char *ruleset = NULL;
seed = time(NULL) ^ getpid();
int opt;
while ((opt = getopt(argc, argv, "c:e:d:Df:g:l:r:s:t:u:")) != -1) {
switch (opt) {
case 'c':
chatfile = strdup(optarg);
break;
case 'e':
if (!strcasecmp(optarg, "random")) {
engine = E_RANDOM;
} else if (!strcasecmp(optarg, "replay")) {
engine = E_REPLAY;
} else if (!strcasecmp(optarg, "montecarlo")) {
engine = E_MONTECARLO;
} else if (!strcasecmp(optarg, "uct")) {
engine = E_UCT;
} else if (!strcasecmp(optarg, "distributed")) {
engine = E_DISTRIBUTED;
} else if (!strcasecmp(optarg, "patternscan")) {
engine = E_PATTERNSCAN;
} else if (!strcasecmp(optarg, "patternplay")) {
engine = E_PATTERNPLAY;
} else if (!strcasecmp(optarg, "joseki")) {
engine = E_JOSEKI;
} else {
fprintf(stderr, "%s: Invalid -e argument %s\n", argv[0], optarg);
exit(1);
}
break;
case 'd':
debug_level = atoi(optarg);
break;
case 'D':
debug_boardprint = false;
break;
case 'f':
fbookfile = strdup(optarg);
break;
case 'g':
gtp_port = strdup(optarg);
break;
case 'l':
log_port = strdup(optarg);
break;
case 'r':
ruleset = strdup(optarg);
break;
case 's':
seed = atoi(optarg);
break;
case 't':
/* Time settings to follow; if specified,
* GTP time information is ignored. Useful
* e.g. when you want to force your bot to
* play weaker while giving the opponent
* reasonable time to play, or force play
* by number of simulations in timed games. */
/* Please see timeinfo.h:time_parse()
* description for syntax details. */
if (!time_parse(&ti_default, optarg)) {
fprintf(stderr, "%s: Invalid -t argument %s\n", argv[0], optarg);
exit(1);
}
ti_default.ignore_gtp = true;
assert(ti_default.period != TT_NULL);
break;
case 'u':
testfile = strdup(optarg);
break;
default: /* '?' */
usage(argv[0]);
exit(1);
}
}
dcnn_quiet_caffe(argc, argv);
if (log_port)
open_log_port(log_port);
fast_srandom(seed);
if (DEBUGL(0))
fprintf(stderr, "Random seed: %d\n", seed);
struct board *b = board_init(fbookfile);
if (ruleset) {
if (!board_set_rules(b, ruleset)) {
fprintf(stderr, "Unknown ruleset: %s\n", ruleset);
exit(1);
}
}
struct time_info ti[S_MAX];
ti[S_BLACK] = ti_default;
ti[S_WHITE] = ti_default;
chat_init(chatfile);
char *e_arg = NULL;
if (optind < argc)
e_arg = argv[optind];
struct engine *e = init_engine(engine, e_arg, b);
if (testfile) {
unittest(testfile);
return 0;
}
if (gtp_port) {
open_gtp_connection(>p_sock, gtp_port);
}
for (;;) {
char buf[4096];
while (fgets(buf, 4096, stdin)) {
if (DEBUGL(1))
fprintf(stderr, "IN: %s", buf);
enum parse_code c = gtp_parse(b, e, ti, buf);
if (c == P_ENGINE_RESET) {
ti[S_BLACK] = ti_default;
ti[S_WHITE] = ti_default;
if (!e->keep_on_clear) {
b->es = NULL;
done_engine(e);
e = init_engine(engine, e_arg, b);
}
} else if (c == P_UNKNOWN_COMMAND && gtp_port) {
/* The gtp command is a weak identity check,
* close the connection with a wrong peer. */
break;
}
}
if (!gtp_port) break;
open_gtp_connection(>p_sock, gtp_port);
}
done_engine(e);
chat_done();
free(testfile);
free(gtp_port);
free(log_port);
free(chatfile);
free(fbookfile);
free(ruleset);
return 0;
}