Skip to content

Commit

Permalink
Merge pull request #98 from lemonsqueeze/lizzie
Browse files Browse the repository at this point in the history
Lizzie !
  • Loading branch information
lemonsqueeze authored Feb 8, 2019
2 parents 02042f4 + 4d56b97 commit 4d8e916
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 39 deletions.
7 changes: 3 additions & 4 deletions HACKING
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
This is brief developer-oriented overview in Pachi structure.
This is brief developer-oriented overview of Pachi structure.

Pachi is completely Go-specific (c.f. Fuego; though e.g. atari go support
should be easy to add), but fairly modular. It has been built with focus
Expand Down Expand Up @@ -176,9 +176,8 @@ or bad input attacks and allowing arbitrary input to be entered within
is a major security hole. Yes, this needs to be cleaned up. Also, currently
engines cannot plug in their own commands.

Pachi supports only few GTP commands now. Most importantly, it does not
support the undo command. The final_status_list command requires engine
support.
Pachi supports only few GTP commands now.
The final_status_list command requires engine support.


DCNN
Expand Down
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,16 @@ To build Pachi, simply type:
<img align="right" src="media/screenshot_sabaki.jpg" title="playing through sabaki">

The resulting binary program `pachi` is a GTP client. Connect to it
with your favorite Go program interface (e.g. [gogui][1], [sabaki][2], [qgo][3]),
or use [kgsGtp][4] to connect it to KGS.
with your favorite Go program interface (e.g. [gogui][1], [sabaki][2], [lizzie](#Lizzie)),
or use [kgsGtp][3] to connect it to KGS.

> DO NOT make the GTP interface accessible directly to untrusted users
> since the parser is not secure - see the [HACKING](HACKING?raw=true)
> file for details.
[1]: https://sourceforge.net/projects/gogui/
[2]: http://sabaki.yichuanshen.de/
[3]: http://qgo.sourceforge.net/
[4]: http://www.michna.com/kgsbot.htm
[3]: http://www.michna.com/kgsbot.htm

The pachi program can take many parameters. The defaults should be fine
for initial usage, see below for some more tips.
Expand Down Expand Up @@ -192,6 +191,21 @@ via the live gfx commands.
There are some non-gui tools for game analysis as well, see below.


## Lizzie

<a href="media/screenshot_lizzie_big.jpg?raw=true"> <img align="right" src="media/screenshot_lizzie.jpg" title="pachi in lizzie v0.6 !" /> </a>

It's also possible to run Pachi with [Lizzie](https://github.com/featurecat/lizzie) to analyze things !
This is a great way to explore variations, analyze games or visualize what Pachi is doing while it's thinking,
the graphics are amazing.

To make Lizzie use Pachi instead of Leela-Zero edit Lizzie config.txt:

"engine-command": "/path/to/pachi --version=0.16 reporting=leelaz,reportfreq=500",

Tweak reportfreq to change update speed.


## Logs

Pachi logs details of its activity on stderr, which can be viewed via
Expand Down
4 changes: 4 additions & 0 deletions engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ typedef void (*engine_best_moves_t)(struct engine *e, struct board *b, struct t
typedef char *(*engine_genmoves_t)(struct engine *e, struct board *b, struct time_info *ti, enum stone color,
char *args, bool pass_all_alive, void **stats_buf, int *stats_size);
typedef void (*engine_evaluate_t)(struct engine *e, struct board *b, struct time_info *ti, floating_t *vals, enum stone color);
typedef void (*engine_analyze_t)(struct engine *e, struct board *b, enum stone color, int start);
typedef void (*engine_dead_group_list_t)(struct engine *e, struct board *b, struct move_queue *mq);
typedef void (*engine_stop_t)(struct engine *e);
typedef void (*engine_done_t)(struct engine *e);
Expand Down Expand Up @@ -78,6 +79,9 @@ struct engine {
* 1-max(opponent_win_likelihood) in vals[i]. */
engine_evaluate_t evaluate;

/* Tell engine to start pondering for the sake of frontend running Pachi. */
engine_analyze_t analyze;

/* One dead group per queued move (coord_t is (ab)used as group_t). */
engine_dead_group_list_t dead_group_list;

Expand Down
2 changes: 1 addition & 1 deletion gogui.c
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@ cmd_gogui_spatial_size(struct board *b, struct engine *e, struct time_info *ti,
{
char *arg; next_tok(arg);
/* Return current value */
if (!*arg) { gtp_reply_printf(gtp, "%i\n", spatial_dist); return P_OK; }
if (!*arg) { gtp_reply_printf(gtp, "%i", spatial_dist); return P_OK; }

int d = atoi(arg);
if (d < 3 || d > 10) { gtp_error(gtp, "Between 3 and 10 please", NULL); return P_OK; }
Expand Down
66 changes: 54 additions & 12 deletions gtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,15 @@ gtp_reply(gtp_t *gtp, ...)
va_end(params);
}

/* Like gtp_reply() takes care of final \n\n so format must not have it. */
void
gtp_reply_printf(gtp_t *gtp, const char *format, ...)
{
va_list ap;
va_start(ap, format);
gtp_prefix('=', gtp);
vprintf(format, ap);
putchar('\n');
gtp_flush();
va_end(ap);
}
Expand Down Expand Up @@ -182,10 +184,12 @@ cmd_protocol_version(struct board *board, struct engine *engine, struct time_inf
}

static enum parse_code
cmd_name(struct board *board, struct engine *engine, struct time_info *ti, gtp_t *gtp)
cmd_name(struct board *b, struct engine *e, struct time_info *ti, gtp_t *gtp)
{
/* KGS hack */
gtp_reply(gtp, "Pachi ", engine->name, NULL);
char *name = "Pachi %s";
if (!strcmp(e->name, "UCT")) name = "Pachi";
if (gtp->custom_name) name = gtp->custom_name;
gtp_reply_printf(gtp, name, e->name);
return P_OK;
}

Expand All @@ -196,16 +200,19 @@ cmd_echo(struct board *board, struct engine *engine, struct time_info *ti, gtp_t
return P_OK;
}

/* Return engine comment if playing on kgs, Pachi version otherwise.
* See "banner" uct param to set engine comment. */
static enum parse_code
cmd_version(struct board *b, struct engine *e, struct time_info *ti, gtp_t *gtp)
{
/* kgs displays 'version' gtp command output on game start. */
if (gtp->kgs) {
/* %s in engine comment stands for Pachi version. */
gtp_reply_printf(gtp, e->comment, PACHI_VERSION, NULL);
}
else gtp_reply(gtp, PACHI_VERSION, NULL);
/* kgs hijacks 'version' gtp command for game start message. */
char *version = (gtp->kgs ? e->comment : "%s");

/* Custom gtp version ? */
if (gtp->custom_version) version = gtp->custom_version;

/* %s in version string stands for Pachi version. */
gtp_reply_printf(gtp, version, PACHI_VERSION);
return P_OK;
}

Expand Down Expand Up @@ -465,6 +472,36 @@ cmd_pachi_genmoves(struct board *board, struct engine *engine, struct time_info
return P_OK;
}

/* Start tree search in the background and output stats for the sake of frontend running Pachi.
* Sortof like pondering without a genmove.
* Stop processing when we receive some other command or "pachi-analyze 0".
* Similar to Leela-Zero's lz-analyze so we can feed data to lizzie. */
static enum parse_code
cmd_pachi_analyze(struct board *b, struct engine *e, struct time_info *ti, gtp_t *gtp)
{
char *arg;
next_tok(arg);

int start = 1;
if (isdigit(*arg)) start = atoi(arg);

enum stone color = S_BLACK;
if (b->last_move.color != S_NONE)
color = stone_other(b->last_move.color);

if (e->analyze) { e->analyze(e, b, color, start); gtp->analyze_running = true; }
else gtp_error(gtp, "pachi-analyze not supported for this engine", NULL);

return P_OK;
}

static void
stop_analyzing(gtp_t *gtp, struct board *b, struct engine *e)
{
gtp->analyze_running = false;
e->analyze(e, b, S_BLACK, 0);
}

static enum parse_code
cmd_set_free_handicap(struct board *b, struct engine *e, struct time_info *ti, gtp_t *gtp)
{
Expand Down Expand Up @@ -536,9 +573,9 @@ cmd_final_score(struct board *b, struct engine *e, struct time_info *ti, gtp_t *

if (DEBUGL(1)) fprintf(stderr, "counted score %.1f\n", score);

if (score == 0) gtp_reply_printf(gtp, "0\n");
else if (score > 0) gtp_reply_printf(gtp, "W+%.1f\n", score);
else gtp_reply_printf(gtp, "B+%.1f\n", -score);
if (score == 0) gtp_reply_printf(gtp, "0");
else if (score > 0) gtp_reply_printf(gtp, "W+%.1f", score);
else gtp_reply_printf(gtp, "B+%.1f", -score);
return P_OK;
}

Expand Down Expand Up @@ -919,6 +956,8 @@ static gtp_command_t commands[] =
{ "pachi-evaluate", cmd_pachi_evaluate },
{ "pachi-result", cmd_pachi_result },
{ "pachi-score_est", cmd_pachi_score_est },
{ "pachi-analyze", cmd_pachi_analyze },
{ "lz-analyze", cmd_pachi_analyze }, /* For Lizzie */

/* Short aliases */
{ "predict", cmd_pachi_predict },
Expand Down Expand Up @@ -975,6 +1014,9 @@ gtp_parse(gtp_t *gtp, struct board *b, struct engine *e, char *e_arg, struct tim
if (!*gtp->cmd)
return P_OK;

if (gtp->analyze_running && strcasecmp(gtp->cmd, "pachi-analyze"))
stop_analyzing(gtp, b, e);

/* Undo: reload engine after first non-undo command. */
if (gtp->undo_pending && strcasecmp(gtp->cmd, "undo"))
undo_reload_engine(gtp, b, e, e_arg);
Expand Down
5 changes: 4 additions & 1 deletion gtp.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ typedef struct
struct move move[1500]; /* move history, for undo */
int moves;
bool undo_pending;
bool noundo; /* undo only allowed for pass */
bool noundo; /* undo only allowed for pass */
bool kgs;
bool analyze_running;
char* custom_name;
char* custom_version;
} gtp_t;

#define next_tok(to_) \
Expand Down
Binary file added media/screenshot_lizzie.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/screenshot_lizzie_big.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 12 additions & 4 deletions pachi.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ usage()
" -s, --seed RANDOM_SEED set random seed \n"
" -u, --unit-test FILE run unit tests \n"
" -v, --version show version \n"
" --version=VERSION version to return to gtp frontend \n"
" --name=NAME name to return to gtp frontend \n"
" \n"
"Gameplay: \n"
" -f, --fbook FBOOKFILE use opening book \n"
Expand Down Expand Up @@ -171,6 +173,7 @@ show_version(FILE *s)
#define OPT_FUSEKI 266
#define OPT_NOUNDO 267
#define OPT_KGS 268
#define OPT_NAME 269
static struct option longopts[] = {
{ "fuseki-time", required_argument, 0, OPT_FUSEKI_TIME },
{ "fuseki", required_argument, 0, OPT_FUSEKI },
Expand All @@ -186,6 +189,7 @@ static struct option longopts[] = {
{ "kgs", no_argument, 0, OPT_KGS },
{ "log-file", required_argument, 0, 'o' },
{ "log-port", required_argument, 0, 'l' },
{ "name", required_argument, 0, OPT_NAME },
{ "nodcnn", no_argument, 0, OPT_NODCNN },
{ "noundo", no_argument, 0, OPT_NOUNDO },
{ "nojoseki", no_argument, 0, OPT_NOJOSEKI },
Expand All @@ -197,7 +201,7 @@ static struct option longopts[] = {
{ "time", required_argument, 0, 't' },
{ "unit-test", required_argument, 0, 'u' },
{ "verbose-caffe", no_argument, 0, OPT_VERBOSE_CAFFE },
{ "version", no_argument, 0, 'v' },
{ "version", optional_argument, 0, 'v' },
{ 0, 0, 0, 0 }
};

Expand Down Expand Up @@ -227,7 +231,7 @@ int main(int argc, char *argv[])
int opt;
int option_index;
/* Leading ':' -> we handle error messages. */
while ((opt = getopt_long(argc, argv, ":c:e:d:Df:g:hl:o:r:s:t:u:v", longopts, &option_index)) != -1) {
while ((opt = getopt_long(argc, argv, ":c:e:d:Df:g:hl:o:r:s:t:u:v::", longopts, &option_index)) != -1) {
switch (opt) {
case 'c':
chatfile = strdup(optarg);
Expand Down Expand Up @@ -333,15 +337,19 @@ int main(int argc, char *argv[])
ti_fuseki.ignore_gtp = true;
assert(ti_fuseki.period != TT_NULL);
break;
case OPT_NAME:
gtp->custom_name = strdup(optarg);
break;
case 'u':
testfile = strdup(optarg);
break;
case OPT_VERBOSE_CAFFE:
verbose_caffe = true;
break;
case 'v':
show_version(stdout);
exit(0);
if (optarg) gtp->custom_version = strdup(optarg);
else { show_version(stdout); exit(0); }
break;
case ':':
die("%s: Missing argument\n"
"Try 'pachi --help' for more information.\n", argv[optind-1]);
Expand Down
2 changes: 2 additions & 0 deletions uct/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct uct {
UR_TEXT,
UR_JSON,
UR_JSON_BIG,
UR_LEELAZ,
} reporting;
int reportfreq;

Expand Down Expand Up @@ -65,6 +66,7 @@ struct uct {

bool pondering_opt; /* User wants pondering */
bool pondering; /* Actually pondering now */
bool genmove_pondering; /* Regular pondering (after a genmove) */
int dcnn_pondering_prior; /* Prior next move guesses */
int dcnn_pondering_mcts; /* Genmove next move guesses */
coord_t dcnn_pondering_mcts_c[20];
Expand Down
2 changes: 1 addition & 1 deletion uct/search.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ spawn_worker(void *ctx_)

if (tree_leaf_node(n) && !__sync_lock_test_and_set(&n->is_expanded, 1)) {
tree_expand_node(t, n, ctx->b, player_color, u, 1);
if (u->pondering && using_dcnn(ctx->b))
if (u->genmove_pondering && using_dcnn(ctx->b))
uct_expand_next_best_moves(u, t, ctx->b, player_color);
}
else if (DEBUGL(2)) { /* Show previously computed priors */
Expand Down
Loading

0 comments on commit 4d8e916

Please sign in to comment.