void GTPArchiving_saveSGF( GauGoEngine* engine, int argc, char** argv ) { // Must have exactly 1 argument if( argc != 2 ){ GauGoEngine_sayError( UNKOWN_COMMAND ); return; } char* filename = argv[1]; SGFTree tree; tree.root = NULL; tree.lastnode = NULL; sgftreeCreateHeaderNode(&tree, engine->board->size, 6.5f, 0); Color turn = BLACK; for( int m=0; m<engine->historyLength-1; m++ ) { INTERSECTION ints = engine->historyMoves[m]; sgftreeAddPlay( &tree, turn, Board_intersectionY(engine->board, ints), Board_intersectionX(engine->board, ints) ); turn = turn==BLACK?WHITE:BLACK; } writesgf(tree.root, argv[1]); GauGoEngine_saySuccess(""); }
/* --------------------------------------------------------------*/ 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); } }
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); }
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); }
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); } }