221 lines
7.0 KiB
C
221 lines
7.0 KiB
C
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
||
|
* This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
|
||
|
* http://www.gnu.org/software/gnugo/ for more information. *
|
||
|
* *
|
||
|
* Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
|
||
|
* 2008 and 2009 by the Free Software Foundation. *
|
||
|
* *
|
||
|
* This program is free software; you can redistribute it and/or *
|
||
|
* modify it under the terms of the GNU General Public License as *
|
||
|
* published by the Free Software Foundation - version 3 or *
|
||
|
* (at your option) any later version. *
|
||
|
* *
|
||
|
* This program is distributed in the hope that it will be useful, *
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||
|
* GNU General Public License in file COPYING for more details. *
|
||
|
* *
|
||
|
* You should have received a copy of the GNU General Public *
|
||
|
* License along with this program; if not, write to the Free *
|
||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
||
|
* Boston, MA 02111, USA. *
|
||
|
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
#include "gnugo.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
#include "interface.h"
|
||
|
#include "sgftree.h"
|
||
|
#include "gg_utils.h"
|
||
|
#include "liberty.h"
|
||
|
|
||
|
static void replay_node(SGFNode *node, int color_to_test, float *replay_score,
|
||
|
float *total_score);
|
||
|
|
||
|
|
||
|
/* --------------------------------------------------------------*/
|
||
|
/* replay a game */
|
||
|
/* --------------------------------------------------------------*/
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#define BUFSIZE 128
|
||
|
|
||
|
/*
|
||
|
* Handle this node.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
replay_node(SGFNode *node, int color_to_replay, float *replay_score,
|
||
|
float *total_score)
|
||
|
{
|
||
|
SGFProperty *sgf_prop; /* iterate over properties of the node */
|
||
|
SGFProperty *move_prop = NULL; /* remember if we see a move property */
|
||
|
int color; /* color of move to be made at this node. */
|
||
|
|
||
|
int old_move; /* The move played in the file. */
|
||
|
int new_move; /* The move generated by GNU Go. */
|
||
|
|
||
|
char buf[BUFSIZE];
|
||
|
|
||
|
/* Handle any AB / AW properties, and note presence
|
||
|
* of move properties.
|
||
|
*/
|
||
|
|
||
|
for (sgf_prop = node->props; sgf_prop; sgf_prop = sgf_prop->next) {
|
||
|
switch (sgf_prop->name) {
|
||
|
case SGFAB:
|
||
|
/* add black */
|
||
|
add_stone(get_sgfmove(sgf_prop), BLACK);
|
||
|
break;
|
||
|
case SGFAW:
|
||
|
/* add white */
|
||
|
add_stone(get_sgfmove(sgf_prop), WHITE);
|
||
|
break;
|
||
|
case SGFB:
|
||
|
case SGFW:
|
||
|
move_prop = sgf_prop; /* remember it for later */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Only generate moves at move nodes. */
|
||
|
if (!move_prop)
|
||
|
return;
|
||
|
|
||
|
old_move = get_sgfmove(move_prop);
|
||
|
color = (move_prop->name == SGFW) ? WHITE : BLACK;
|
||
|
|
||
|
if (color == color_to_replay || color_to_replay == GRAY) {
|
||
|
float new_move_value = 0.0;
|
||
|
float old_move_value = 0.0;
|
||
|
|
||
|
/* Get a move from the engine for color. */
|
||
|
int resign;
|
||
|
new_move = genmove(color, NULL, &resign);
|
||
|
|
||
|
/* Pick up the relevant values from the potential_moves[] array. */
|
||
|
if (new_move != PASS_MOVE)
|
||
|
new_move_value = potential_moves[new_move];
|
||
|
if (old_move != PASS_MOVE)
|
||
|
old_move_value = potential_moves[old_move];
|
||
|
|
||
|
/* Now report on how well the computer generated the move. */
|
||
|
if (new_move != old_move || !quiet) {
|
||
|
mprintf("Move %d (%C): ", movenum + 1, color);
|
||
|
|
||
|
if (resign)
|
||
|
printf("GNU Go resigns ");
|
||
|
else {
|
||
|
mprintf("GNU Go plays %1m ", new_move);
|
||
|
if (new_move != PASS_MOVE)
|
||
|
printf("(%.2f) ", new_move_value);
|
||
|
}
|
||
|
|
||
|
mprintf("- Game move %1m ", old_move);
|
||
|
if (new_move != PASS_MOVE && old_move_value > 0.0)
|
||
|
printf("(%.2f) ", old_move_value);
|
||
|
printf("\n");
|
||
|
|
||
|
*replay_score += new_move_value - old_move_value;
|
||
|
*total_score += new_move_value;
|
||
|
}
|
||
|
|
||
|
if (new_move != old_move) {
|
||
|
if (resign)
|
||
|
gg_snprintf(buf, BUFSIZE, "GNU Go resigns - Game move %s (%.2f)",
|
||
|
location_to_string(old_move), old_move_value);
|
||
|
else {
|
||
|
gg_snprintf(buf, BUFSIZE,
|
||
|
"GNU Go plays %s (%.2f) - Game move %s (%.2f)",
|
||
|
location_to_string(new_move), new_move_value,
|
||
|
location_to_string(old_move), old_move_value);
|
||
|
if (new_move != PASS_MOVE)
|
||
|
sgfCircle(node, I(new_move), J(new_move));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
gg_snprintf(buf, BUFSIZE, "GNU Go plays the same move %s (%.2f)",
|
||
|
location_to_string(new_move), new_move_value);
|
||
|
|
||
|
sgfAddComment(node, buf);
|
||
|
sgffile_add_debuginfo(node, 0.0);
|
||
|
}
|
||
|
|
||
|
/* Finally, do play the move from the file. */
|
||
|
play_move(old_move, color);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Local Variables:
|
||
|
* tab-width: 8
|
||
|
* c-basic-offset: 2
|
||
|
* End:
|
||
|
*/
|