int get_shallow_move(int *board, int side) { /* Return the move that gives the best position immediately after */ int i; int move = 0; int score; int flips[20]; int old_board[100]; int best_score = MIN_SCORE; // backup the existing board copy_board(board, old_board); for (i=11; i<89; ++i) { if (legal_move(board,i,side,flips) == 1) { make_move(board,i,side,flips); score = evaluate_board(board, side, 0); if (score > best_score) { best_score = score; move = i; } // reset the board before each iteration copy_board(old_board, board); } } return move; }
/* * This is the main loop of the connect four game. It first prints a * welcome message, allocates the board, and then begins the game loop */ int main() { puts("Welcome to Connect Four\n"); int* board = new_board(); while (1) { print_board(board); int column = -1; // Get human input until they enter a valid choice... while (1) { printf("Enter your move (column number): "); scanf("%d", &column); if (column < 0 || column >= WIDTH) { printf("Input a valid choice (0 - 6).\n"); } else if (place(board, column, 1) == 0) { printf("That column is full.\n"); } else { break; } } // Did the human input make him or her win? if (check_win(board, 1) != 0) { print_board(board); printf("Player 1 wins!\n"); break; } // Do the AI's move... int ai_column = get_next_move(evaluate_board(board)); place(board,ai_column, 2); // Did the AI's move cause it to win? if (check_win(board, 2) != 0) { print_board(board); printf("Player 2 wins!\n"); break; } } free(board); exit(EXIT_SUCCESS); }
int minimize(int *board, int side, int unplayed, int ply) { /* Search to depth ply with mutual recursion * Side should be the opponent of currently playing side * Return the lowest score found */ int old_board[100]; int flips[20]; int score = MAX_SCORE; if (ply == 0 || test_end(board, unplayed) == 1) return evaluate_board(board, side, unplayed); copy_board(board, old_board); for (int i=11; i<89; ++i) { if (legal_move(board, i, side, flips) == 0) continue; make_move(board, i, side, flips); score = MIN(score, maximize(board, -side, 0, ply-1)); copy_board(old_board, board); } return score; }
int ab_minimize(int *board, int side, int unplayed, int ply,int a, int b) { /* Search to depth ply with mutual recursion * Return minimum score possible as opponent of current player * Cut off with a and b when possible */ int old_board[100]; int flips[20]; if (ply == 0 || test_end(board, unplayed) == 1) return evaluate_board(board, side, unplayed); copy_board(board, old_board); for (int i=11; i<89; ++i) { if (legal_move(board, i, side, flips) == 0) continue; make_move(board, i, side, flips); b = MIN(b, ab_maximize(board, -side, 0, ply-1, a, b)); copy_board(old_board, board); if (b <= a) break; } return b; }
int ab_maximize(int *board, int side, int unplayed, int ply, int a,int b) { /* Search to depth ply with mutual recursion * Return maximum score possible for current side * Cuts off search using a and b parameters if possible */ int old_board[100]; int flips[20]; if (ply == 0 || test_end(board, unplayed) == 1) return evaluate_board(board, side, unplayed); copy_board(board, old_board); for (int i=11; i<89; ++i) { if (legal_move(board, i, side, flips) == 0) continue; make_move(board, i, side, flips); a = MAX(a, ab_minimize(board, -side, 0, ply-1, a, b)); copy_board(old_board, board); if (b <= a) // that's a cutoff, no point further pursuing this position break; } return a; }
// Blasphemous! maximize instead of maximise?! int maximize(int *board, int side, int unplayed, int ply) { /* The max portion of minimax * Return maximum score available from position * Used with currently playing side's turn * Search with mutual recursion to depth ply */ int old_board[100]; int flips[20]; int score = MIN_SCORE; if (ply == 0 || test_end(board, unplayed) == 1) // either reached end of search or game is over, so return return evaluate_board(board, side, unplayed); // backup the current playing board copy_board(board, old_board); for (int i=11; i<89; ++i) { if (legal_move(board, i, side, flips) == 0) continue; make_move(board, i, side, flips); score = MAX(score, minimize(board, -side, 0, ply-1)); // reset the board after computing the score copy_board(old_board, board); } return score; }
int main(void) { Color computer_player = -1; // not WHITE or BLACK if we don't play either (e.g. -1) int game_on = 0; Bitboard *board = malloc(sizeof(Bitboard)); Undo *u = NULL; char* input = malloc(sizeof(char) * max_input_length); Move last_move = 0; int got_move = 0; freopen("/dev/tty", "w", stderr); setbuf(stderr, NULL); setbuf(stdout, NULL); srandom(time(NULL)); while (1) { if (game_on && got_move) { u = malloc(sizeof(Undo)); board_do_move(board, last_move, u); got_move = 0; } if (game_on && computer_player == board->to_move) { last_move = search_find_move(board); move_srcdest_form(last_move, input); printf("move %s\n", input); u = malloc(sizeof(Undo)); board_do_move(board, last_move, u); } fgets(input, max_input_length, stdin); fprintf(stderr, "%s", input); if (!strcmp("xboard\n", input)) printf("feature colors=0 setboard=1 time=0 sigint=0 sigterm=0 variants=\"normal\" done=1\n"); else if (!strcmp("new\n", input)) { board_free_undos(u); board_init(board); computer_player = BLACK; game_on = 1; } else if (!strcmp("quit\n", input)) break; else if (!strcmp("force\n", input)) computer_player = -1; else if (!strcmp("go\n", input)) computer_player = board->to_move; else if (!strncmp("setboard ", input, 9)) board_init_with_fen(board, input + 9); else if (!strncmp("result", input, 6)) { computer_player = -1; game_on = 0; } else if (!strncmp("level ", input, 6)) timer_init(input); else if (!strcmp("_print\n", input)) { board_print(board); printf("Evaluation: %i\n", evaluate_board(board)); puts("Pseudolegal moves: "); Movelist all_moves; move_generate_movelist(board, &all_moves); Moveiter it; moveiter_init(&it, &all_moves, MOVEITER_SORT_NONE, MOVE_NULL); char srcdest_form[6]; while (moveiter_has_next(&it)) { Move m = moveiter_next(&it); move_srcdest_form(m, srcdest_form); printf("%s ", srcdest_form); } puts("\n"); } else if (input[0] >= 'a' && input[0] <= 'h' && input[1] >= '1' && input[1] <= '8' && input[2] >= 'a' && input[2] <= 'h' && input[3] >= '1' && input[3] <= '8') { last_move = parse_move(board, input); if (!last_move) printf("Illegal move: %s", input); else got_move = 1; } else printf("Error (unknown command): %s", input); } free(board); free(input); return 0; }