hex_t hex_load_sgf (hex_format_t format, char * filename) { hex_t hex; char * size_str; SGFNode * root; SGFNode * node; if ((root = readsgffile (filename)) == NULL) return NULL; if (! sgfGetCharProperty (root, "SZ", &size_str)) return NULL; hex = hex_new (atoi (size_str)); for (node = root->child; node != NULL; node = node->child) { uint i, x; char * move; char * prop_name; /* Swap isn't supported yet */ switch (format) { case HEX_AUTO: if (sgfGetCharProperty (node, "W ", &move)) format = HEX_LG_SGF; else if (sgfGetCharProperty (node, "B ", &move)) format = HEX_SGF; else return NULL; break; case HEX_SGF: sgfGetCharProperty (node, hex_get_player (hex) == 1 ? "B " : "W ", &move); if (! (strcmp ("swap-sides", move) || strcmp ("swap-pieces", move))) return NULL; if (! strcmp ("resign", move)) goto end; break; case HEX_LG_SGF: sgfGetCharProperty (node, hex_get_player (hex) == 1 ? "W " : "B ", &move); if (! strcmp ("swap", move)) return NULL; if (! strcmp ("resign", move)) goto end; break; default: return NULL; } errno = 0; i = hex_decode_sgf_pos (move[0]); if (errno || i >= hex->size) return NULL; if (format == HEX_SGF) x = atoi (move+1); else if (format == HEX_LG_SGF) x = hex_decode_sgf_pos (move[1]); if (errno || x >= hex->size) return NULL; hex_move (hex, i, hex->size-x-1); } end: sgfFreeNode (root); return hex; }
void play_replay(SGFTree *tree, int color_to_replay) { char *tmpc = NULL; float replay_score = 0.0; float total_score = 0.0; SGFNode *node = tree->root; /* Board size and komi are already set up correctly since the game * has already been loaded before this function is called. Now we * only have to clear the board before starting over. */ clear_board(); if (!quiet) { printf("Board Size: %d\n", board_size); if (sgfGetCharProperty(node, "HA", &tmpc)) printf("Handicap: %s\n", tmpc); printf("Komi: %.1f\n", komi); if (sgfGetCharProperty(node, "RU", &tmpc)) printf("Ruleset: %s\n", tmpc); if (sgfGetCharProperty(node, "GN", &tmpc)) printf("Game Name: %s\n", tmpc); if (sgfGetCharProperty(node, "DT", &tmpc)) printf("Game Date: %s\n", tmpc); if (sgfGetCharProperty(node, "GC", &tmpc)) printf("Game Comment: %s\n", tmpc); if (sgfGetCharProperty(node, "US", &tmpc)) printf("Game User: %s\n", tmpc); if (sgfGetCharProperty(node, "PB", &tmpc)) printf("Black Player: %s\n", tmpc); if (sgfGetCharProperty(node, "PW", &tmpc)) printf("White Player: %s\n", tmpc); if (sgfGetCharProperty(node, "RE", &tmpc)) printf("Result: %s\n", tmpc); } /* * Now actually run through the file. This is the interesting part. * We need to traverse the SGF tree, and every time we encounter a node * we need to check what move GNU Go would make, and see if it is OK. */ while (node) { replay_node(node, color_to_replay, &replay_score, &total_score); sgffile_output(tree); node = node->child; } if (!quiet) printf("Global score: %.2f / %.2f\n", replay_score, total_score); if (showtime) { gprintf("SLOWEST MOVE: %d at %1m ", slowest_movenum, slowest_move); fprintf(stderr, "(%.2f seconds)\n", slowest_time); fprintf(stderr, "AVERAGE TIME: %.2f seconds per move\n", total_time / movenum); fprintf(stderr, "TOTAL TIME: %.2f seconds\n", total_time); } }
void load_and_score_sgf_file(SGFTree *tree, Gameinfo *gameinfo, const char *scoringmode) { int i, j, move_val; float result; char *tempc = NULL; char dummy; char text[250]; char winner; int next; int pass = 0; SGFTree score_tree; sgftree_clear(&score_tree); sgftreeCreateHeaderNode(&score_tree, board_size, komi); sgffile_printboard(&score_tree); next = gameinfo->to_move; doing_scoring = 1; reset_engine(); if (!strcmp(scoringmode, "finish") || !strcmp(scoringmode, "aftermath")) { do { move_val = genmove_conservative(&i, &j, next); if (move_val >= 0) { pass = 0; gprintf("%d %s move %m\n", movenum, next == WHITE ? "white (O)" : "black (X)", i, j); } else { ++pass; gprintf("%d %s move : PASS!\n", movenum, next == WHITE ? "white (O)" : "black (X)"); } play_move(POS(i, j), next); sgffile_add_debuginfo(score_tree.lastnode, move_val); sgftreeAddPlay(&score_tree, next, i, j); sgffile_output(&score_tree); next = OTHER_COLOR(next); } while (movenum <= 10000 && pass < 2); if (pass >= 2) { /* Calculate the score */ if (!strcmp(scoringmode, "aftermath")) score = aftermath_compute_score(next, komi, &score_tree); else score = gnugo_estimate_score(&lower_bound, &upper_bound); if (score < 0.0) { sprintf(text, "Black wins by %1.1f points\n", -score); winner = 'B'; } else if (score > 0.0) { sprintf(text, "White wins by %1.1f points\n", score); winner = 'W'; } else { sprintf(text, "Jigo\n"); winner = '0'; } fputs(text, stdout); sgftreeAddComment(&score_tree, text); if (sgfGetCharProperty(tree->root, "RE", &tempc)) { if (sscanf(tempc, "%1c%f", &dummy, &result) == 2) { fprintf(stdout, "Result from file: %1.1f\n", result); fputs("GNU Go result and result from file are ", stdout); if (result == fabs(score) && winner == dummy) fputs("identical\n", stdout); else fputs("different\n", stdout); } else { if (tempc[2] == 'R') { fprintf(stdout, "Result from file: Resign\n"); fputs("GNU Go result and result from file are ", stdout); if (tempc[0] == winner) fputs("identical\n", stdout); else fputs("different\n", stdout); } } } sgfWriteResult(score_tree.root, score, 1); sgffile_output(&score_tree); } } doing_scoring = 0; if (strcmp(scoringmode, "aftermath")) { /* Before we call estimate_score() we must make sure that the dragon * status is computed. Therefore the call to examine_position(). */ examine_position(next, EXAMINE_ALL); score = estimate_score(NULL, NULL); fprintf(stdout, "\n%s seems to win by %1.1f points\n", score < 0 ? "B" : "W", score < 0 ? -score : score); } }
void load_and_score_sgf_file(SGFTree *tree, Gameinfo *gameinfo, const char *scoringmode) { int move; float move_value; char *tempc = NULL; char text[250]; char winner; int next; int pass = 0; int method; float score; SGFTree local_tree; SGFTree *score_tree = tree; /* Default scoring method is ESTIMATE since it's fastest. */ method = ESTIMATE; if (strcmp(scoringmode, "finish") == 0) method = FINISH; else if (strcmp(scoringmode, "aftermath") == 0) method = AFTERMATH; /* For aftermath scoring we compress the previous moves to a static * board position in the output sgf. This helps a lot when debugging * scoring mistakes. We don't do this for the finish method, * however, since users may be better served by having GNU Go's * selfplay added to the original game record. */ if (method == AFTERMATH) { sgftree_clear(&local_tree); /* Modify komi to compensate for captured stones. We start at a * setup position and since there is no standard sgf property to * tell the number of captured stones, a modified komi is the best * available solution. */ sgftreeCreateHeaderNode(&local_tree, board_size, komi + black_captured - white_captured, handicap); sgffile_printboard(&local_tree); sgfAddProperty(local_tree.lastnode, "PL", gameinfo->to_move == WHITE ? "W" : "B"); score_tree = &local_tree; } next = gameinfo->to_move; reset_engine(); /* Complete the game by selfplay for the finish and aftermath methods. */ if (method != ESTIMATE) { doing_scoring = 1; while (pass < 2) { move = genmove_conservative(next, &move_value); if (move != PASS_MOVE) { pass = 0; gprintf("%d %s move %1m\n", movenum, next == WHITE ? "white (O)" : "black (X)", move); } else { pass++; gprintf("%d %s move PASS\n", movenum, next == WHITE ? "white (O)" : "black (X)"); } play_move(move, next); sgffile_add_debuginfo(score_tree->lastnode, move_value); sgftreeAddPlay(score_tree, next, I(move), J(move)); sgffile_output(score_tree); next = OTHER_COLOR(next); } doing_scoring = 0; } /* Calculate the score. */ if (method == AFTERMATH) score = aftermath_compute_score(next, score_tree); else score = gnugo_estimate_score(NULL, NULL); if (score < 0.0) { sprintf(text, "Black wins by %1.1f points\n", -score); winner = 'B'; } else if (score > 0.0) { sprintf(text, "White wins by %1.1f points\n", score); winner = 'W'; } else { sprintf(text, "Jigo\n"); winner = '0'; } fputs(text, stdout); sgftreeAddComment(score_tree, text); /* For the finish and aftermath methods we compare the score with * what's stored in the game record. * * FIXME: No comparison is made if the stored result was 0. Wins by * time or forfeit are not handled either. * * FIXME: Does anybody actually care about this information? Just * removing this piece of code is a tempting alternative. */ if (method != ESTIMATE && sgfGetCharProperty(tree->root, "RE", &tempc)) { char dummy; float result; if (sscanf(tempc, "%1c%f", &dummy, &result) == 2) { fprintf(stdout, "Result from file: %c+%1.1f\n", dummy, result); fputs("GNU Go result and result from file are ", stdout); if (result == fabs(score) && winner == dummy) fputs("identical\n", stdout); else fputs("different\n", stdout); } else { if (tempc[2] == 'R') { fprintf(stdout, "Result from file: Resign\n"); fputs("GNU Go result and result from file are ", stdout); if (tempc[0] == winner) fputs("identical\n", stdout); else fputs("different\n", stdout); } } } if (method != ESTIMATE) sgfWriteResult(score_tree->root, score, 1); sgffile_output(score_tree); }