// There are two types of command interfaces in the world of computing: good // interfaces and user interfaces. -- Daniel J. Bernstein //------------------------------------------------------------------------------ void repl() { Position *position = NULL; char command[128] = ""; printf("Donna Vista v%s Copyright (c) 2014-2015 by Michael Dvorkin. All Rights Reserved.\nType ? for help.\n\n", VERSION); while (true) { printf("donna_vista> "); if (fgets(command, sizeof(command), stdin)) { // Strip trailing newline returned by fgets(). int len = strlen(command); if (len > 0 && command[len - 1] == '\n') { command[len - 1] = '\0'; } if (strlen(command)) { if (!strncmp(command, "bench", 5)) { repl_bench(strtok(&command[5], " ")); } else if (!strncmp(command, "book", 4)) { repl_book(strtok(&command[4], " ")); } else if (!strncmp(command, "perft", 5)) { repl_perft(strtok(&command[5], " ")); } else if (!strcmp(command, "go")) { position = repl_think(repl_setup(position)); } else if (!strcmp(command, "help") || !strcmp(command, "?")) { repl_help(); } else if (!strcmp(command, "new")) { position = repl_setup(NULL); } else if (!strcmp(command, "undo")) { position = repl_undo(position); } else if (!strcmp(command, "exit") || !strcmp(command, "quit")) { break; } else { Move move = new_move_from_string(position, command); if (move) { position = repl_think(make_move(repl_setup(position), move)); } else { char buffer[256]; MoveGen *gen = new_move_gen(position); valid_only(generate_all_moves(gen)); printf("%s appears to be an invalid move; valid moves are %s\n", command, all_moves(gen, buffer)); } } } } else { break; // Exit if fgets() errors out. } } }
// Before returning the move make sure it is valid in current position. //------------------------------------------------------------------------------ Move validate(Position *self, Move move) { if (move) { MoveGen *gen = new_move_gen(self); valid_only(generate_all_moves(gen)); if (!among_valid(gen, move)) { return (Move)0; } } return move; }
/* Function returns 1 if opponent's king is checked * c = 1 (white) or -1 (black) */ int is_check(board * brd, int c) { move * t = malloc(sizeof(move)); init_move(&t); generate_all_moves(c, brd, &t); move * t_ = t; while(t_->next != NULL) { if( t_->x * c == -6) { free_moves(&t); return 1; } t_=t_->next; } free_moves(&t); return 0; }
/* Returns 1 if player c has valid moves left. * c = 1 (white) or -1 (black) * If king is in check and no valid moves left, that implies checkmate */ int has_moves(board * brd, int c) { move * t = malloc(sizeof(move)); init_move(&t); generate_all_moves(c, brd, &t); move * t_ = t; while(t_->next != NULL) { if(apply_move(brd, &t_, c)) { undo_move(brd, &t_); free_moves(&t); return 1; } t_ = t_->next; } free_moves(&t); return 0; }
int generate_valid_moves(GAME *game, MOVE *moves) { DECKP hand = game->players[game->current_player].hand; int i; int num = 0; MOVE all_moves[MAX_MOVES]; int num_moves; num_moves = generate_all_moves(hand, all_moves); /* Special case: put highest move first, just in case it helps pruning. */ if (num_moves >= 1 && is_valid_move(game, all_moves[num_moves-1])) moves[num++] = all_moves[num_moves-1]; for (i = 0; i < num_moves-1; i++) if (is_valid_move(game, all_moves[i])) moves[num++] = all_moves[i]; return num; }
void test(void) { GAME game; MOVE moves[MAX_MOVES]; int vector[MAX_PLAYERS]; int num_moves; int i; MOVE chosen_move; clock_t start_time, end_time; int centiseconds, rate; printf("Rankoids AI test\n"); clear_transposition_table(); init_stack(&game_stack, 100*sizeof(GAME)); initialise_game(&game); game.num_players = 3; game.players[0].hand[0] = 1; game.players[0].hand[1] = 3; game.players[0].hand[3] = 2; game.players[1].hand[4] = 1; game.players[0].hand[6] = 4; game.players[0].hand[7] = 3; game.players[0].hand[10] = 2; game.players[0].hand[JOKER_VALUE] = 1; game.players[1].hand[1] = 1; game.players[1].hand[2] = 3; game.players[1].hand[3] = 1; game.players[1].hand[4] = 1; game.players[1].hand[5] = 1; game.players[1].hand[9] = 3; game.players[1].hand[12] = 1; game.players[1].hand[5] = 2; game.players[2].hand[0] = 3; game.players[2].hand[2] = 1; game.players[2].hand[3] = 1; game.players[1].hand[4] = 2; game.players[2].hand[5] = 2; game.players[2].hand[9] = 1; game.players[2].hand[11] = 4; game.current_player = 0; game.pile_owner = 0; printf("Current game:\n"); print_game(&game); printf("All moves for player 1:\n"); num_moves = generate_all_moves(game.players[0].hand, moves); for (i = 0; i < num_moves; i++) print_move(moves[i]); printf("\n"); evaluate_game_immediate(&game, vector); printf("Game vector is: [%d,%d,%d]\n", vector[0], vector[1], vector[2]); printf("All valid moves for player 1:\n"); num_moves = generate_valid_moves(&game, moves); for (i = 0; i < num_moves; i++) print_move(moves[i]); printf("\n"); chosen_move = MAKE_MOVE(3, 2); printf("Apply move "); print_move(chosen_move); printf(", game is:\n"); apply_move(&game, chosen_move); print_game(&game); evaluate_game_immediate(&game, vector); printf("Game vector is: [%d,%d,%d]\n", vector[0], vector[1], vector[2]); printf("All valid moves for player 2:\n"); num_moves = generate_valid_moves(&game, moves); for (i = 0; i < num_moves; i++) { print_move(moves[i]); clear_transposition_table(); evaluate_move(&game, moves[i], vector, parameters.depth); printf(", with vector [%d,%d,%d]\n", vector[0], vector[1], vector[2]); } node_count = 0; clear_transposition_table(); start_time = clock(); chosen_move = choose_move(&game, vector, parameters.depth+5); end_time = clock(); centiseconds = (end_time - start_time)*100 / CLOCKS_PER_SEC; if (centiseconds != 0) { rate = (int) (100.0*node_count/centiseconds); } else { rate = 0; } printf("%d nodes examined (%d hits), time was: %0.2f seconds, rate is: %d nodes/sec\n", node_count, hit_count, centiseconds/100.0, rate); printf("Chosen move was:"); print_move(chosen_move); printf(", with vector [%d,%d,%d]\n", vector[0], vector[1], vector[2]); free_stack(&game_stack); }