Beispiel #1
0
void 
load_and_analyze_sgf_file(Gameinfo *gameinfo)
{
  SGFTree sgftree;
  int move;
  int next;
  float move_value;
  
  next = gameinfo->to_move;
  sgftree = gameinfo->game_record;

  if (metamachine)
    sgffile_begindump(&sgftree);

  move = genmove(next, &move_value, NULL);

  gprintf("%s move %1m\n", next == WHITE ? "white (O)" : "black (X)", move);

  if (metamachine)
    sgffile_enddump(outfilename);
  else {
    gnugo_play_move(move, next);
    sgftreeAddPlay(&sgftree, next, I(move), J(move));
    sgftreeAddComment(&sgftree, "load and analyze mode");
    sgffile_add_debuginfo(sgftree.lastnode, move_value);
    sgffile_output(&sgftree);
  }
}
Beispiel #2
0
static int
computer_move(Gameinfo *gameinfo, int *passes)
{
  int move;
  float move_value;
  int resign;
  int resignation_declined = 0;
  float upper_bound, lower_bound;

  init_sgf(gameinfo);

  /* Generate computer move. */
  if (autolevel_on)
    adjust_level_offset(gameinfo->to_move);
  move = genmove(gameinfo->to_move, &move_value, &resign);
  if (resignation_allowed && resign) {
    int state = ascii_endgame(gameinfo, 2);
    if (state != -1)
      return state;

    /* The opponent declined resignation. Remember not to resign again. */
    resignation_allowed = 0;
    resignation_declined = 1;
  }

  if (showscore) {
    gnugo_estimate_score(&upper_bound, &lower_bound);
    current_score_estimate = (int) ((lower_bound + upper_bound) / 2.0);
  }
  
  mprintf("%s(%d): %1m\n", color_to_string(gameinfo->to_move),
	  movenum + 1, move);
  if (is_pass(move))
    (*passes)++;
  else
    *passes = 0;

  gnugo_play_move(move, gameinfo->to_move);
  sgffile_add_debuginfo(sgftree.lastnode, move_value);
  sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move));
  if (resignation_declined)
    sgftreeAddComment(&sgftree, "GNU Go resignation was declined");
  sgffile_output(&sgftree);

  gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
  return 0;
}
Beispiel #3
0
static int
do_pass(Gameinfo *gameinfo, int *passes, int force)
{
  (*passes)++;
  init_sgf(gameinfo);
  gnugo_play_move(PASS_MOVE, gameinfo->to_move);
  sgffile_add_debuginfo(sgftree.lastnode, 0.0);
  sgftreeAddPlay(&sgftree, gameinfo->to_move, -1, -1);
  sgffile_output(&sgftree);

  gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
  if (force) {
    gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
    sgftreeAddComment(&sgftree, "forced");
    return 0;
  }

  return computer_move(gameinfo, passes);
}
Beispiel #4
0
static int
do_move(Gameinfo *gameinfo, char *command, int *passes, int force)
{
  int move = string_to_location(board_size, command);

  if (move == NO_MOVE) {
    printf("\nInvalid move: %s\n", command);
    return 0;
  }
  
  if (!is_allowed_move(move, gameinfo->to_move)) {
    printf("\nIllegal move: %s", command);
    return 0;
  }

  *passes = 0;
  TRACE("\nyour move: %1m\n\n", move);
  init_sgf(gameinfo);
  gnugo_play_move(move, gameinfo->to_move);
  sgffile_add_debuginfo(sgftree.lastnode, 0.0);
  sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move));
  sgffile_output(&sgftree);
  
  if (opt_showboard) {
    ascii_showboard();
    printf("GNU Go is thinking...\n");
  }

  if (force) {
    gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
    gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
    sgftreeAddComment(&sgftree, "forced");
    return 0;
  }

  gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
  return computer_move(gameinfo, passes);
}
void 
load_and_analyze_sgf_file(Gameinfo *gameinfo)
{
  SGFTree sgftree;
  int i, j;
  int next;
  int move_val;
  
  next = gameinfo->to_move;
  sgftree = gameinfo->game_record;

  move_val = gnugo_genmove(&i, &j, next);

  if (is_pass(POS(i, j)))
    gprintf("%s move: PASS!\n", next == WHITE ? "white (O)" : "black (X)");
  else
    gprintf("%s move %m\n", next == WHITE ? "white (O)" : "black (X)", i, j);

  gnugo_play_move(i, j, next);
  sgftreeAddPlay(&sgftree, next, i, j);
  sgftreeAddComment(&sgftree, "load and analyze mode");
  sgffile_add_debuginfo(sgftree.lastnode, move_val);
  sgffile_output(&sgftree);
}
Beispiel #6
0
/* --------------------------------------------------------------*/
void
play_gmp(Gameinfo *gameinfo, int simplified)
{
  SGFTree sgftree;

  Gmp *ge;
  GmpResult message;
  const char *error;
  
  int i, j;
  int passes = 0; /* two passes and its over */
  int to_move;  /* who's turn is next ? */

  int mycolor = -1;  /* who has which color */
  int yourcolor;

  if (gameinfo->computer_player == WHITE)
    mycolor = 1;
  else if (gameinfo->computer_player == BLACK)
    mycolor = 0;

  sgftree_clear(&sgftree);
  sgftreeCreateHeaderNode(&sgftree, board_size, komi, gameinfo->handicap);

  ge = gmp_create(0, 1);
  TRACE("board size=%d\n", board_size);

  /* 
   * The specification of the go modem protocol doesn't even discuss
   * komi. So we have to guess the komi. If the komi is set on the
   * command line, keep it. Otherwise, its value will be 0.0 and we
   * use 5.5 in an even game, 0.5 otherwise.
   */
  if (komi == 0.0) {
    if (gameinfo->handicap == 0)
      komi = 5.5;
    else
      komi = 0.5;
  }

  if (!simplified) {
    /* Leave all the -1's so the client can negotiate the game parameters. */
    if (chinese_rules)
      gmp_startGame(ge, -1, -1, 5.5, -1, mycolor, 0);
    else
      gmp_startGame(ge, -1, -1, 5.5, 0, mycolor, 0);
  }
  else {
    gmp_startGame(ge, board_size, gameinfo->handicap,
		  komi, chinese_rules, mycolor, 1);
  }

  do {
    message = gmp_check(ge, 1, NULL, NULL, &error);
  } while (message == gmp_nothing || message == gmp_reset);
  
  if (message == gmp_err) {
    fprintf(stderr, "gnugo-gmp: Error \"%s\" occurred.\n", error);
    exit(EXIT_FAILURE);
  }
  else if (message != gmp_newGame) {
    fprintf(stderr, "gnugo-gmp: Expecting a newGame, got %s\n",
	    gmp_resultString(message));
    exit(EXIT_FAILURE);
  }

  gameinfo->handicap = gmp_handicap(ge);
  if (!check_boardsize(gmp_size(ge), stderr))
    exit(EXIT_FAILURE);
  
  gnugo_clear_board(gmp_size(ge));

  /* Let's pretend GMP knows about komi in case something will ever change. */
  komi = gmp_komi(ge);

#if ORACLE
  if (metamachine && oracle_exists)
    oracle_clear_board(board_size);
#endif

  sgfOverwritePropertyInt(sgftree.root, "SZ", board_size);

  TRACE("size=%d, handicap=%d, komi=%f\n", board_size,
	gameinfo->handicap, komi);

  if (gameinfo->handicap)
    to_move = WHITE;
  else
    to_move = BLACK;

  if (gmp_iAmWhite(ge)) {
    mycolor = WHITE;     /* computer white */
    yourcolor = BLACK;   /* human black */
  }
  else {
    mycolor = BLACK;
    yourcolor = WHITE;
  }

  gameinfo->computer_player = mycolor;
  sgf_write_header(sgftree.root, 1, get_random_seed(), komi,
		   gameinfo->handicap, get_level(), chinese_rules);
  gameinfo->handicap = gnugo_sethand(gameinfo->handicap, sgftree.root);
  sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);

  /* main GMP loop */
  while (passes < 2) {

    if (to_move == yourcolor) {
      int move;
      /* Get opponent's move from gmp client. */
      message = gmp_check(ge, 1, &j, &i, &error);

      if (message == gmp_err) {
	fprintf(stderr, "GNU Go: Sorry, error from gmp client\n");
        sgftreeAddComment(&sgftree, "got error from gmp client");
        sgffile_output(&sgftree);
	return;
      }

      if (message == gmp_undo) {
	int k;
	assert(j > 0);
	
	for (k = 0; k < j; k++) {
	  if (!undo_move(1)) {
	    fprintf(stderr, "GNU Go: play_gmp UNDO: can't undo %d moves\n",
		    j - k);
	    break;
	  }
	  sgftreeAddComment(&sgftree, "undone");
	  sgftreeBack(&sgftree);
	  to_move = OTHER_COLOR(to_move);
	}
	continue;
      }

      if (message == gmp_pass) {
	passes++;
	move = PASS_MOVE;
      }
      else {
	passes = 0;
	move = POS(i, j);
      }

      TRACE("\nyour move: %1m\n\n", move);
      sgftreeAddPlay(&sgftree, to_move, I(move), J(move));
      gnugo_play_move(move, yourcolor);
      sgffile_output(&sgftree);

    }
    else {
      /* Generate my next move. */
      float move_value;
      int move;
      if (autolevel_on)
	adjust_level_offset(mycolor);
      move = genmove(mycolor, &move_value, NULL);
      gnugo_play_move(move, mycolor);
      sgffile_add_debuginfo(sgftree.lastnode, move_value);
      
      if (is_pass(move)) {
	/* pass */
        sgftreeAddPlay(&sgftree, to_move, -1, -1);
	gmp_sendPass(ge);
	++passes;
      }
      else {
	/* not pass */
        sgftreeAddPlay(&sgftree, to_move, I(move), J(move));
	gmp_sendMove(ge, J(move), I(move));
	passes = 0;
	TRACE("\nmy move: %1m\n\n", move);
      }
      sgffile_add_debuginfo(sgftree.lastnode, 0.0);
      sgffile_output(&sgftree);
    }
    
    to_move = OTHER_COLOR(to_move);
  }
  
  /* two passes: game over */
  gmp_sendPass(ge);   
  
  if (!quiet)
    fprintf(stderr, "Game over - waiting for client to shut us down\n");
  who_wins(mycolor, stderr);

  if (showtime) {
    gprintf("\nSLOWEST MOVE: %d at %1m ", slowest_movenum, slowest_move);
    fprintf(stderr, "(%.2f seconds)\n", slowest_time);
    fprintf(stderr, "\nAVERAGE TIME: %.2f seconds per move\n",
	    total_time / movenum);
    fprintf(stderr, "\nTOTAL TIME: %.2f seconds\n",
	    total_time);
  }
  
  
  /* play_gmp() does not return to main(), therefore the score
   * writing code is here.
   */
  { 
    float score = gnugo_estimate_score(NULL, NULL);
    sgfWriteResult(sgftree.root, score, 1);
  }
  sgffile_output(&sgftree);

  if (!simplified) {
    /* We hang around here until cgoban asks us to go, since
     * sometimes cgoban crashes if we exit first.
     *
     * FIXME: Check if this is still needed.  I made it dependand on
     *	      `simplifed' just to avoid changes in GMP mode.
     */
    while (1) {
      message = gmp_check(ge, 1, &j, &i, &error);
      if (!quiet)
	fprintf(stderr, "Message %d from gmp\n", message);
      if (message == gmp_err)
	break;
    }
  }

#if ORACLE
  if (metamachine && oracle_exists)
    dismiss_oracle();
#endif

  if (!quiet)
    fprintf(stderr, "gnugo going down\n");
}
void
play_solo(Gameinfo *gameinfo, int moves)
{
  SGFTree sgftree;
  int passes = 0; /* num. consecutive passes */
  int move_val;
  double t1, t2;
  int save_moves = moves;
  int boardsize = gnugo_get_boardsize();

  struct stats_data totalstats;
  int total_owl_count = 0;

  /* It tends not to be very imaginative in the opening,
   * so we scatter a few stones randomly to start with.
   * We add two random numbers to reduce the probability
   * of playing stones near the edge.
   */
  
  int n = 6 + 2*gg_rand()%5;
  int i, j;

  gnugo_set_komi(5.5);

  sgftree_clear(&sgftree);
  sgftreeCreateHeaderNode(&sgftree, gnugo_get_boardsize(), gnugo_get_komi());
  sgf_write_header(sgftree.root, 1, random_seed, 5.5, level, chinese_rules);
 
  /* Generate some random moves. */
  if (boardsize > 6) {
    do {
      do {
	i = (gg_rand() % 4) + (gg_rand() % (boardsize - 4));
	j = (gg_rand() % 4) + (gg_rand() % (boardsize - 4));
      } while (!gnugo_is_legal(i, j, gameinfo->to_move));

      gnugo_play_move(i, j, gameinfo->to_move);
      sgftreeAddPlay(&sgftree, gameinfo->to_move, i, j);
      sgftreeAddComment(&sgftree, "random move");
      gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
    } while (--n > 0);
  }
  
  t1 = gg_cputime();
  memset(&totalstats, '\0', sizeof(totalstats));
  while (passes < 2 && --moves >= 0) {
    reset_owl_node_counter();
    move_val = gnugo_genmove(&i, &j, gameinfo->to_move);

    gnugo_play_move(i, j, gameinfo->to_move);
    sgffile_add_debuginfo(sgftree.lastnode, move_val);
    sgftreeAddPlay(&sgftree, gameinfo->to_move, i, j);
    sgffile_output(&sgftree);
    gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);

    if (move_val < 0) {
      ++passes;
      printf("%s(%d): Pass\n", gameinfo->to_move == BLACK ? "Black" : "White",
	     movenum);
    }
    else {
      passes = 0;
      gprintf("%s(%d): %m\n", gameinfo->to_move == BLACK ? "Black" : "White",
	      movenum, i, j);
    }

    totalstats.nodes               += stats.nodes;
    totalstats.position_entered    += stats.position_entered;
    totalstats.position_hits       += stats.position_hits;
    totalstats.read_result_entered += stats.read_result_entered;
    totalstats.hash_collisions     += stats.hash_collisions;
    total_owl_count                += get_owl_node_counter();
  }
  t2 = gg_cputime();
  
  /* Two passes and it's over. (EMPTY == BOTH) */
  gnugo_who_wins(EMPTY, stdout);

  score = gnugo_estimate_score(&lower_bound, &upper_bound);
  sgfWriteResult(sgftree.root, score, 1);
  sgffile_output(&sgftree);

#if 0
  if (t2 == t1)
    printf("%.3f moves played\n", (double) (save_moves-moves));
  else
    printf("%.3f moves/sec\n", (save_moves-moves)/(t2-t1));
#else
  printf("%10d moves played in %0.3f seconds\n", save_moves-moves, t2-t1);
  if (save_moves != moves)
    printf("%10.3f seconds/move\n", (t2-t1)/(save_moves-moves));
  printf("%10d nodes\n", totalstats.nodes);
  printf("%10d positions entered\n", totalstats.position_entered);
  printf("%10d position hits\n", totalstats.position_hits);
  printf("%10d read results entered\n", totalstats.read_result_entered);
  printf("%10d hash collisions\n", totalstats.hash_collisions);
  printf("%10d owl nodes\n", total_owl_count);
#endif
}
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);
  }
}
Beispiel #9
0
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);
  }
}
Beispiel #10
0
void
play_solo(Gameinfo *gameinfo, int moves)
{
  SGFTree sgftree;
  int passes = 0; /* num. consecutive passes */
  float move_value;
  double t1, t2;
  int save_moves = moves;

  struct stats_data totalstats;
  int total_owl_count = 0;

  /* It tends not to be very imaginative in the opening,
   * so we scatter a few stones randomly to start with.
   * We add two random numbers to reduce the probability
   * of playing stones near the edge.
   */
  
  int n = 6 + 2*gg_rand()%5;
  int i, j;

  komi = 5.5;

  sgftree_clear(&sgftree);
  sgftreeCreateHeaderNode(&sgftree, board_size, komi, handicap);
  sgf_write_header(sgftree.root, 1, get_random_seed(), 5.5, handicap,
                   get_level(), chinese_rules);
 
  /* Generate some random moves. */
  if (board_size > 6) {
    do {
      do {
	i = (gg_rand() % 4) + (gg_rand() % (board_size - 4));
	j = (gg_rand() % 4) + (gg_rand() % (board_size - 4));
      } while (!is_allowed_move(POS(i, j), gameinfo->to_move));

      gnugo_play_move(POS(i, j), gameinfo->to_move);
      sgftreeAddPlay(&sgftree, gameinfo->to_move, i, j);
      sgftreeAddComment(&sgftree, "random move");
      gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
    } while (--n > 0);
  }
  
  t1 = gg_cputime();
  memset(&totalstats, '\0', sizeof(totalstats));
  while (passes < 2 && --moves >= 0) {
    int move;
    reset_owl_node_counter();
    move = genmove(gameinfo->to_move, &move_value, NULL);

    gnugo_play_move(move, gameinfo->to_move);
    sgffile_add_debuginfo(sgftree.lastnode, move_value);
    sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move));
    sgffile_output(&sgftree);
    gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);

    if (move == PASS_MOVE) {
      passes++;
      printf("%s(%d): Pass\n", gameinfo->to_move == BLACK ? "Black" : "White",
	     movenum);
    }
    else {
      passes = 0;
      gprintf("%s(%d): %1m\n", gameinfo->to_move == BLACK ? "Black" : "White",
	      movenum, move);
    }

    totalstats.nodes                    += stats.nodes;
    totalstats.read_result_entered      += stats.read_result_entered;
    totalstats.read_result_hits         += stats.read_result_hits;
    totalstats.trusted_read_result_hits += stats.trusted_read_result_hits;
    total_owl_count                     += get_owl_node_counter();
  }
  t2 = gg_cputime();
  
  /* Two passes and it's over. (EMPTY == BOTH) */
  who_wins(EMPTY, stdout);

  {
    float score = gnugo_estimate_score(NULL, NULL);
    sgfWriteResult(sgftree.root, score, 1);
  }
  sgffile_output(&sgftree);

  printf("%10d moves played in %0.3f seconds\n", save_moves-moves, t2-t1);
  if (save_moves != moves)
    printf("%10.3f seconds/move\n", (t2-t1)/(save_moves-moves));
  
  printf("%10d nodes\n", totalstats.nodes);
  printf("%10d read results entered\n", totalstats.read_result_entered);
  printf("%10d read result hits\n", totalstats.read_result_hits);
  printf("%10d trusted read result hits\n",
	 totalstats.trusted_read_result_hits);
  printf("%10d owl nodes\n", total_owl_count);
}
Beispiel #11
0
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);
}
Beispiel #12
0
void
do_play_ascii(Gameinfo *gameinfo)
{
  int m, num;
  float fnum;
  int passes = 0;  /* two passes and its over */
  int tmp;
  char line[80];
  char *line_ptr = line;
  char *command;
  char *tmpstring;
  int state = 1;

  if (have_time_settings())
    clock_on = 1;

  while (state == 1) {
    state = 0;

    /* No score is estimated yet. */
    current_score_estimate = NO_SCORE;

    /* Allow resignation at interface level (the engine may still be not
     * allowed to resign.
     */
    resignation_allowed = 1;

    printf("\nBeginning ASCII mode game.\n\n");
    gameinfo_print(gameinfo);

    /* Does the computer play first?  If so, make a move. */
    if (gameinfo->computer_player == gameinfo->to_move)
      state = computer_move(gameinfo, &passes);

    /* main ASCII Play loop */
    while (state == 0) {
      /* Display game board. */
      if (opt_showboard)
	ascii_showboard();

#if !READLINE
      /* Print the prompt */
      mprintf("%s(%d): ", color_to_string(gameinfo->to_move), movenum + 1);

      /* Read a line of input. */
      line_ptr = line;
      if (!fgets(line, 80, stdin))
	return;
#else
      snprintf(line, 79, "%s(%d): ",
	       color_to_string(gameinfo->to_move), movenum + 1);
      if (!(line_ptr = readline(line)))
	return;

      add_history(line_ptr);
#endif

      while (state == 0
	     && (command = strtok(line_ptr, ";"), line_ptr = 0, command)) {
	/* Get the command or move. */
	switch (get_command(command)) {
	case RESIGN:
	  state = ascii_endgame(gameinfo, 1);
	  break;

	case END:
	case EXIT:
	case QUIT:
	  return;

	case HELP:
	  show_commands();
	  break;

	case CMD_HELPDEBUG:
	  printf(DEBUG_COMMANDS);
	  break;

	case SHOWBOARD:
	  opt_showboard = !opt_showboard;
	  break;

	case INFO:
	  printf("\n");
	  gameinfo_print(gameinfo);
	  break;

	case SETBOARDSIZE:
	  if (sgf_initialized) {
	    printf("Boardsize cannot be changed after record is started!\n");
	    break;
	  }
	  command += 10;
	  if (sscanf(command, "%d", &num) != 1) {
	    printf("\nInvalid command syntax!\n");
	    break;
	  }
	  if (!check_boardsize(num, stdout))
	    break;
	  /* Init board. */
	  board_size = num;
	  clear_board();
	  /* In case max handicap changes on smaller board. */
	  gameinfo->handicap = place_fixed_handicap(gameinfo->handicap);
	  sgfOverwritePropertyInt(sgftree.root, "SZ", board_size);
	  sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
	  break;

	case SETHANDICAP:
	  if (sgf_initialized) {
	    printf("Handicap cannot be changed after game is started!\n");
	    break;
	  }
	  command += 9;
	  if (sscanf(command, "%d", &num) != 1) {
	    printf("\nInvalid command syntax!\n");
	    break;
	  }
	  if (num < 0 || num > MAX_HANDICAP) {
	    printf("\nInvalid handicap: %d\n", num);
	    break;
	  }
	  /* Init board. */
	  clear_board();
	  /* Place stones on board but don't record sgf 
	   * in case we change more info. */
	  gameinfo->handicap = place_fixed_handicap(num);
	  printf("\nSet handicap to %d\n", gameinfo->handicap);
          gameinfo->to_move = (gameinfo->handicap ? WHITE : BLACK);
	  break;

	case FREEHANDICAP:
	  if (sgf_initialized) {
	    printf("Handicap cannot be changed after game is started!\n");
	    break;
	  }
	  while (*command && *command != ' ')
	    command++;
	  ascii_free_handicap(gameinfo, command);
	  break;

	case SETKOMI:
	  if (sgf_initialized) {
	    printf("Komi cannot be modified after game record is started!\n");
	    break;
	  }
	  command += 5;
	  if (sscanf(command, "%f", &fnum) != 1) {
	    printf("\nInvalid command syntax!\n");
	    break;
	  }
	  komi = fnum;
	  printf("\nSet Komi to %.1f\n", komi);
	  break;

	case SETDEPTH:
	  command += 6;
	  if (sscanf(command, "%d", &num) != 1) {
	    printf("\nInvalid command syntax!\n");
	    break;
	  }
	  mandated_depth = num;
	  printf("\nSet depth to %d\n", mandated_depth);
	  break;

	case SETLEVEL:
	  command += 6;
	  if (sscanf(command, "%d", &num) != 1) {
	    printf("\nInvalid command syntax!\n");
	    break;
	  }
	  set_level(num);
	  printf("\nSet level to %d\n", num);
	  break;

	case DISPLAY:
	  if (!opt_showboard)
	    ascii_showboard();
	  break;

	case FORCE:
	  command += 6; /* skip the force part... */
	  switch (get_command(command)) {
	  case MOVE:
	    state = do_move(gameinfo, command, &passes, 1);
	    break;
	  case PASS:
	    state = do_pass(gameinfo, &passes, 1);
	    break;
	  default:
	    printf("Illegal forced move: %s %d\n", command,
		   get_command(command));
	    break;
	  }
	  break;

	case MOVE:
	  state = do_move(gameinfo, command, &passes, 0);
	  break;

	case PASS:
	  state = do_pass(gameinfo, &passes, 0);
	  break;

	case PLAY:
	  command += 5;
	  if (sscanf(command, "%d", &num) != 1) {
	    printf("\nInvalid command syntax!\n");
	    break;
	  }
	  if (num >= 0)
	    for (m = 0; m < num; m++) {
	      gameinfo->computer_player 
		= OTHER_COLOR(gameinfo->computer_player);
	      state = computer_move(gameinfo, &passes);
	      if (state)
		break;
	      if (passes >= 2)
		break;
	    }
	  else {
	    printf("\nInvalid number of moves specified: %d\n", num);
	    break;
	  }
	  break;

	case PLAYBLACK:
	  if (gameinfo->computer_player == WHITE)
	    gameinfo->computer_player = BLACK;
	  if (gameinfo->computer_player == gameinfo->to_move)
	    state = computer_move(gameinfo, &passes);
	  break;

	case PLAYWHITE:
	  if (gameinfo->computer_player == BLACK)
	    gameinfo->computer_player = WHITE;
	  if (gameinfo->computer_player == gameinfo->to_move)
	    state = computer_move(gameinfo, &passes);
	  break;

	case SWITCH:
	  gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
	  state = computer_move(gameinfo, &passes);
	  break;

	case UNDO:
	case CMD_BACK:
	  if (undo_move(1)) {
            sgftreeAddComment(&sgftree, "undone");
	    sgftreeBack(&sgftree);
	    gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
	  }
	  else
	    printf("\nCan't undo.\n");
	  break;

	case CMD_FORWARD:
         if (sgftreeForward(&sgftree))
           gameinfo->to_move = gnugo_play_sgfnode(sgftree.lastnode,
						  gameinfo->to_move);
	  else
	    printf("\nEnd of game tree.\n");
	  break;

	case CMD_LAST:
         while (sgftreeForward(&sgftree))
           gameinfo->to_move = gnugo_play_sgfnode(sgftree.lastnode,
						  gameinfo->to_move);
	  break;

	case COMMENT:
	  printf("\nEnter comment. Press ENTER when ready.\n");
	  fgets(line, 80, stdin);
	  sgftreeAddComment(&sgftree, line);
	  break;

	case SCORE:
	  showscore = !showscore;
	  if (!showscore)
	    current_score_estimate = NO_SCORE;
	  break;

	case CMD_DEAD:
	  silent_examine_position(FULL_EXAMINE_DRAGONS);
	  showdead = !showdead;
	  break;

	case CMD_CAPTURE:
	  strtok(command, " ");
	  showcapture(strtok(NULL, " "));
	  break;

	case CMD_DEFEND:
	  strtok(command, " ");
	  showdefense(strtok(NULL, " "));
	  break;

	case CMD_SHOWMOYO:
	  tmp = printmoyo;
	  printmoyo = PRINTMOYO_MOYO;
	  silent_examine_position(EXAMINE_DRAGONS);
	  printmoyo = tmp;
	  break;

	case CMD_SHOWTERRI:
	  tmp = printmoyo;
	  printmoyo = PRINTMOYO_TERRITORY;
	  silent_examine_position(EXAMINE_DRAGONS);
	  printmoyo = tmp;
	  break;

	case CMD_SHOWAREA:
	  tmp = printmoyo;
	  printmoyo = PRINTMOYO_AREA;
	  silent_examine_position(EXAMINE_DRAGONS);
	  printmoyo = tmp;
	  break;

	case CMD_SHOWDRAGONS:
	  silent_examine_position(EXAMINE_DRAGONS);
	  showboard(1);
	  break;

	case CMD_GOTO:
	  strtok(command, " ");
	  ascii_goto(gameinfo, strtok(NULL, " "));
	  break;

	case CMD_SAVE:
	  strtok(command, " ");
	  tmpstring = strtok(NULL, " ");
	  if (tmpstring) {
	    /* discard newline */
	    tmpstring[strlen(tmpstring) - 1] = 0;
	    /* make sure we are saving proper handicap */
	    init_sgf(gameinfo);
	    writesgf(sgftree.root, tmpstring);
	    printf("You may resume the game");
	    printf(" with -l %s --mode ascii\n", tmpstring);
	    printf("or load %s\n", tmpstring);
	  }
	  else
	    printf("Please specify filename\n");
	  break;

	case CMD_LOAD:
	  strtok(command, " ");
	  tmpstring = strtok(NULL, " ");
	  if (tmpstring) {
	    /* discard newline */
	    tmpstring[strlen(tmpstring) - 1] = 0;
	    if (!sgftree_readfile(&sgftree, tmpstring)) {
	      fprintf(stderr, "Cannot open or parse '%s'\n", tmpstring);
	      break;
	    }
            /* to avoid changing handicap etc. */
	    if (gameinfo_play_sgftree(gameinfo, &sgftree, NULL) == EMPTY)
	      fprintf(stderr, "Cannot load '%s'\n", tmpstring);
	    else {
	      sgf_initialized = 1;
	      sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
	    }
	  }
	  else
	    printf("Please specify a filename\n");
	  break;

	case CMD_LISTDRAGONS:
	  silent_examine_position(EXAMINE_DRAGONS);
	  show_dragons();
	  break;

	default:
	  printf("\nInvalid command: %s", command);
	  break;
	}

	if (passes >= 2)
	  state = ascii_endgame(gameinfo, 0);
      }
#if READLINE
      free(line_ptr);
#endif
    }

    sgffile_output(&sgftree);
    passes = 0;
    
    /* Play a different game next time. */
    update_random_seed();

    /* Free the sgf tree and prepare for a new game. */
    sgfFreeNode(sgftree.root);
    sgftree_clear(&sgftree);
    sgftreeCreateHeaderNode(&sgftree, board_size, komi, gameinfo->handicap);
    sgf_initialized = 0;

    gameinfo_clear(gameinfo);
  }
}