Move AIPlayer::alpha_beta(GameBoard* game, int lookahead, int alpha, int beta, int player) { vector<Move> all_moves = get_all_moves(game, player); //cout << "Moves are: " << endl; //cout << m.x +1 << ", " << m.y + 1 << " Score: " << m.score << endl; if (all_moves.empty()) return Move(-1, -1, maximizing_player(player) * 35); if (lookahead == 0) { //return heuristic value of previous player if (!is_maximizing(player)) { Move temp = *(std::max_element(all_moves.begin(), all_moves.end(), [](Move m1, Move m2){return m1.score < m2.score;})); //cout << "return: "<< temp.x +1 << ", " << temp.y + 1 << " Score: " << temp.score << endl; return temp; } else { Move temp = *(min_element(all_moves.begin(), all_moves.end(), [](Move m1, Move m2){return m1.score < m2.score;})); //cout << "return: "<< temp.x +1 << ", " << temp.y + 1 << " Score: " << temp.score << endl; return temp; } } Move return_move; if (is_maximizing(player)) { for (auto m : all_moves) { GameBoard temp_board(game); temp_board.make_move(m.x, m.y, player); Move temp_move = alpha_beta(&temp_board, lookahead - 1, alpha, beta, other_player(player)); if (temp_move.score > alpha) { return_move = m; alpha = temp_move.score; } if (alpha >= beta) { break; } } return return_move; } else { for (auto m : all_moves) { GameBoard temp_board(game); temp_board.make_move(m.x, m.y, player); Move temp_move = alpha_beta(&temp_board, lookahead - 1, alpha, beta, other_player(player)); if (temp_move.score < beta) { beta = temp_move.score; return_move = m; } if (alpha >= beta) { break; } } return return_move; } }
AIMoves *ai_priority(const Board *b) { AIMoves *moves; int i, j, stage[2] = {1, 1}, mask, bits; moves = ai_threats(b); /* Do not prioritize if we've won */ if (threat_counts[connect_k - place_p + 1][b->turn - 1]) { moves->utility = AIW_WIN; return moves; } /* Find the largest supported threat for each player */ for (i = 2; i < connect_k; i++) { if (threat_number(0, i - 1) >= place_p && threat_number(0, i) > place_p) stage[0] = i; if (threat_number(1, i - 1) >= place_p && threat_number(1, i) > place_p) stage[1] = i; } if (opt_debug_stage) g_debug("Stages %d/%d", stage[0], stage[1]); /* Do not prioritize if we're losing */ if (stage[b->turn - 1] <= stage[other_player(b->turn) - 1]) { moves->utility = -stage[other_player(b->turn) - 1]; return moves; } /* Threats above the player's stage are no more valuable than the stage */ bits = 1 << (stage[b->turn - 1] * BITS_PER_THREAT); mask = bits - 1; for (i = 0; i < moves->len; i++) { AIWEIGHT w = moves->data[i].weight, w2; if (w < AIW_THREAT_MAX && w >= bits) { w2 = w & mask; w = w & ~mask; for (j = stage[b->turn - 1]; w && j < connect_k - place_p + 1; j++) { w = w >> BITS_PER_THREAT; w2 += w & mask; } moves->data[i].weight = w2; } }
void move(board_type board, char player, int move_num, bool humans_only, char computer) { int square; if(humans_only) { do { printf("What is your move?: "); fflush(stdin); scanf("%d", &square); square--; } while(board[square] != empty); play(board, square, player); } else { if(player == computer) { total_nodes = 0; //describe(best_move(board, computer, &square, move_num, -infinity, infinity), computer); best_move(board, computer, &square, move_num, -infinity, infinity); //printf("Analyzed %d nodes\n", total_nodes); //getchar(); getchar(); play(board, square, computer); } else { do { printf("What is your move?: "); fflush(stdin); scanf("%d", &square); square--; } while(board[square] != empty); play(board, square, other_player(computer)); } } }
moves pawn_moves(settings * set, cord curr, int color) { moves piece_simple_moves; piece_simple_moves.len = 0; cord dest; move * single_move; moves promotions; int dest_color; int y_dir = (color == WHITE) ? 1 : -1; dest.y = curr.y + y_dir; for (int x = -1; x <= 1; x++) { single_move = malloc(sizeof(move)); if (single_move == NULL) { free_list(&piece_simple_moves, &free); return error_moves; } single_move->start = curr; single_move->promotion = FALSE; single_move->is_castle = FALSE; dest.x = curr.x + x; if (is_valid_cord(dest)) { dest_color = which_color(board_piece(set->board, dest)); //logical XOR: check if pawn can eat XOR move up if (color == dest_color) { free(single_move); continue; } if ((x == 0) != (dest_color == other_player(color))) { single_move->end = dest; board_copy(set->board, single_move->board); move_from_to(single_move->board, curr, dest); // check if psaudo-legal move is legal if (is_king_checked(color, single_move->board)) { free(single_move); continue; } if (dest.y == promotion_row(color)) { promotions = promote(single_move); if (promotions.len == -1){ free(single_move); free_list(&piece_simple_moves, &free); return promotions; } concat(&piece_simple_moves, promotions); } else if (!add_node(&piece_simple_moves, single_move, sizeof(move))) { //could not add node to linked list free(single_move); free_list(&piece_simple_moves, &free); return error_moves; } free(single_move); } } } return piece_simple_moves; }
/* minimax algorithm with alpha-beta prunning. * the function returns score (int) according to the minimax algorithm * and the score() function. returns ERROR_SCORE in case of an error. */ int minimax(settings set, int alpha, int beta, int is_maxi_player, int depth, int is_best_difficulty){ int player = set.next; if (depth == 0) { int scorrer = is_maxi_player ? player : other_player(player); int board_score = score(&set, scorrer, player, is_best_difficulty); //return score according to maximizing player return board_score; } moves possible_moves = make_all_moves(&set); // create all possible moves for player if (possible_moves.len == -1) { //there was an error, return an error score return SCORE_ERROR; } else if (possible_moves.len == 0){ // reached a "leaf" at the minimax tree (no more possible moves from here) if (is_king_checked(player, set.board)) return is_maxi_player ? INT_MIN : INT_MAX; else // tie return TIE_SCORE; } int minimax_score = is_maxi_player ? INT_MIN : INT_MAX; move_node* curr = possible_moves.first; while (curr != NULL){ // continue recursively for each possible move move * cur_move = curr->data; settings next_set; memcpy(&next_set, &set, sizeof(settings)); next_set.next = other_player(player); int cur_score = minimax(next_set, alpha, beta, !is_maxi_player, depth - 1, is_best_difficulty); if (cur_score == SCORE_ERROR) { //there was an error, return an error score free_list(&possible_moves, &free); return SCORE_ERROR; } // get maximum\minimum v_score according to is_maxi_player minimax_score = is_maxi_player ? maxi(minimax_score, cur_score) : mini(minimax_score, cur_score); if (is_maxi_player) alpha = maxi(alpha, minimax_score); else beta = mini(beta, minimax_score); if (beta <= alpha) break; //pruning curr = curr->next; } free_list(&possible_moves, &free); return minimax_score; }
Token Board::play_random_game(Token next_player) { Token winner=NOT_PLAYED; Token player=next_player; while (this->play_random_move(player)) { winner=this->check_for_win(); if (winner) break; player=other_player(player); } return winner; }
/* find and return the best computer's next move acording to minimax algorithm. * in case of an error - return a move with .steps_len = -1 * (envelope function that calls minimax()) */ moves best_next_moves(settings set, int maximizer) { // minimax function moves best_moves = { 0 }; move * temp_best_move; moves possible_moves = make_all_moves(&set); int best_score = INT_MIN; int curr_alpha = INT_MIN; if (possible_moves.len == -1) { //error return possible_moves; } int is_best_difficulty = (set.minimax_depth == BEST_DIFFICULTY); int depth = (!is_best_difficulty) ? set.minimax_depth : get_best_depth(&set, maximizer); move_node * curr = possible_moves.first; while (curr != NULL) { //get the score of each next possible moves, according to minimax algorithm settings next_set; memcpy(&next_set, &set, sizeof(settings)); next_set.next = other_player(set.next); board_copy(((move*)curr->data)->board, next_set.board); int curr_score = minimax(next_set, curr_alpha, INT_MAX, FALSE, depth - 1, is_best_difficulty); if (curr_score == SCORE_ERROR) { free_list(&possible_moves, &free); free_list(&best_moves, &free); return error_moves; } if (curr_score > curr_alpha) curr_alpha = curr_score; temp_best_move = curr->data; if (curr_score > best_score) { // if new score is higher - free previous best moves free_list(&best_moves, &free); best_score = curr_score; } if (!(curr_score < best_score)) { if (!add_node(&best_moves, temp_best_move, sizeof(move))) { free_list(&best_moves, &free); free_list(&possible_moves, &free); return error_moves; } } curr = curr->next; } free_list(&possible_moves, &free); if (DEBUG) printf("CHOSEN SCORE: %d\n", best_score); return best_moves; }
void player_vs_player(void) { char x_name[STRING_LENGTH]; char o_name[STRING_LENGTH]; board_type board; int move_num = 1; char player = 'X'; system("cls"); memset(x_name, '\0', STRING_LENGTH); memset(o_name, '\0', STRING_LENGTH); init(board); printf("Enter the name of player 'X': "); fflush(stdin); scanf("%32s", &x_name); printf("Enter the name of player 'O': "); fflush(stdin); scanf("%32s", &o_name); while(winner(board) == empty) { system("cls"); printf("Match: Player vs. Player\n\n"); print_board(board); if(player == 'X') printf("It is turn for %s!\n", x_name); else printf("It is turn for %s!\n", o_name); move(board, player, move_num, true, '\0'); player = other_player(player); move_num++; } system("cls"); printf("Match: Player vs. Player\n\n"); print_board(board); if(winner(board) != 'T') printf("Winner is %s!\n", winner(board) == 'X' ? x_name : o_name); else printf("Draw!\n"); }
double efg_solve::Game::GameValue(const std::array<std::vector<double>, 2> &strategy_profile, std::vector<double> *utility, Player player) const { UtilityVector(strategy_profile[player_id(other_player(player))], utility, player); for (int infoset = num_infosets(player)-1; infoset >= 0; --infoset) { int first = infoset_first_sequence(player, infoset); int last = infoset_last_sequence(player, infoset); int parent = infoset_parent_sequence(player, infoset); for (int i = first; i <= last; ++i) { double sequence_probability = strategy_profile[player_id(player)][i]; double expected_payoff = (*utility)[i]; (*utility)[parent] += sequence_probability * expected_payoff; } } if (player == Player::P1) { return (*utility)[0]; } else { return -(*utility)[0]; } }
// return the heuristic value used to determine the order // in which the children of a node are searched. // this increases speed and efficiency int evaluate(board_type board, char player) { int i; int heuristic = 0; for(i=0; i<POSSIBLE_WINS; i++) { int j; int players = 0, other_players = 0; for(j=0; j<3; j++) { char piece = board[three_in_a_row[i][j]]; if(piece == player) players++; else if(piece == other_player(player)) other_players++; } heuristic += heuristic_array[players][other_players]; } return heuristic; }
void player_vs_computer(void) { // for now, ignore choosing different players char player = 'X'; char ans; board_type board; int move_num = 1; // first move char computer; system("cls"); // initialize board init(board); // who will move first? printf("Do you want to move first? (y/n): "); fflush(stdin); scanf("%c", &ans); if(toupper(ans) == 'Y') computer = 'O'; else computer = 'X'; // while !finished while(winner(board) == empty) { system("cls"); printf("Match: Computer vs. Player\n\n"); print_board(board); move(board, player, move_num, false, computer); player = other_player(player); move_num++; } system("cls"); printf("Match: Computer vs. Player\n\n"); print_board(board); if(winner(board) != 'T') printf("Winner is %c!\n", winner(board)); else printf("Draw!\n"); }
void debug_counts(void) { int i, sum = 0; if (!b) return; g_debug("Threat counts (black, white):"); for (i = 1; i < connect_k; i++) { g_debug("%d: %3d %3d", i, threat_counts[i][0], threat_counts[i][1]); sum += threat_counts[i][0] * threat_bits(i, b->turn) - threat_counts[i][1] * threat_bits(i, other_player(b->turn)); } if (sum > 0) g_debug("Threat sum: %d (10^%.2f)", sum, log10((double)sum)); else if (sum < 0) g_debug("Threat sum: %d (-10^%.2f)", sum, log10((double)-sum)); else g_debug("Threat sum: 0"); }
int main() { struct timeval tv; struct timezone tz; t_util *util; char *str; gettimeofday(&tv, &tz); if (!(util = malloc(sizeof(t_util)))) return (err_msg(": malloc fail")); if ((str = getenv("PWD")) == NULL) return (err_msg(": getenv fail")); srand(tv.tv_usec); if (!(util->key = ftok(str, 0)) == -1) return (err_msg(": ftok fail")); util->shm_id = shmget(util->key, (sizeof(char) * (MAP_X * MAP_Y)), SHM_R | SHM_W); if (util->shm_id == -1) first_step(util); else other_player(util); return (0); }
void move_cords(char board[BOARD_SIZE][BOARD_SIZE], cord curr, int max_move, int color, int move_x, int move_y, cord end_cords[32]) { cord dest; int dest_color; // initialize end_cords if (DEBUG1){ if (curr.x < -42) { printf("%s\n", "NO KING!"); } } int i; for (i = 0; i < 32; i++){ end_cords[i] = error_cord; } i = 0; for (int x_direction = (-move_x); x_direction <= move_x; x_direction += 2){ for (int y_directrion = (-move_y); y_directrion <= move_y; y_directrion += 2) { for (int k = 1; k <= max_move; k++) { dest.x = curr.x + (k*x_direction); dest.y = curr.y + (k*y_directrion); // check if piece can walk to this destination if (!is_valid_cord(dest)) break; dest_color = which_color(board_piece(board, dest)); if (dest_color == color) //if destination is same color piece - cannot move this waty break; else end_cords[i++] = dest; if (dest_color == other_player(color)) //if ate - cannot continue moving in the same direction break; } } } }
/* * compute computer's next move and play. * return move in case of success, in case of lose/tie - return LOSE_CODE / TIE_CODE. * in case of an error - exit */ move computer_turn(settings * game_settings) { moves best_moves = best_next_moves(*game_settings, game_settings->next); //find next move move_node * random_best_move; move best_move; if (best_moves.len == -1) { // there was an error return error_move; } if (best_moves.len == 0) { // no possible moves - player wins best_move.promotion = NO_MOVE_CODE; return best_move; } else { // play best_move int r = rand() % best_moves.len; random_best_move = best_moves.first; for (int i = 0; i < r; i++) { random_best_move = random_best_move->next; }; best_move = *(move*)random_best_move->data; board_copy(best_move.board, game_settings->board); free_list(&best_moves, &free); game_settings->is_next_checked = (is_king_checked(other_player(game_settings->next), game_settings->board)); return best_move; } }
/* calculates the board's score. * scoring_player = color of the minimax-maximizer player * current_player = color of the player whose turn it is now. * * the function returns: * WIN_SCORE if scoring_player wins this board * LOSE_SCORE if scoring_player loses this board * scoring_player's total pieces value minus other player's total pieces value otherwise * ERROR_SCORE in case of an error */ int score(settings * set, int scoring_player, int current_player, int is_best){ int total_score; cord piece; moves possible_moves; int no_more_moves = TRUE; int no_scoring_king = TRUE; int no_other_king = TRUE; int num_of_moves; int player_score = 0; int other_player_score = 0; int is_scoring_piece; int is_scoring_checked = is_king_checked(current_player, set->board); int is_other_checked = is_king_checked(other_player(current_player), set->board); for (int i = 0; i < BOARD_SIZE; i++){ for (int j = 0; j < BOARD_SIZE; j++){ piece.x = i; piece.y = j; char cur_piece = board_piece(set->board, piece); if (cur_piece == EMPTY) continue; int piece_color = which_color(cur_piece); is_scoring_piece = (piece_color == scoring_player); int piece_score = get_piece_score(cur_piece); if (piece_score == KING_SCORE) { no_scoring_king = (no_scoring_king && !is_scoring_piece); no_other_king = (no_other_king && is_scoring_piece); } if (is_scoring_piece) player_score += piece_score; else //piece_color is other player's color other_player_score += piece_score; // we have to check that current_player has at least one piece that // can move, otherwise current_player loses or it's a tie. if (no_more_moves && (piece_color == current_player)) { // check walking move for piece. checking move of distance 1 takes only O(1) time if // player cannot move and O(n) if player can move (creating new board. occurs at most once) // is enough for both king & man (if king cannot move 1 he cannot move 2) possible_moves = get_simple_moves(set, piece); num_of_moves = possible_moves.len; free_list(&possible_moves, &free); if (num_of_moves == -1) //there was an error, return an error score return SCORE_ERROR; // once one of the current_player can move, they do not lose, // no need to preform this check again. if (num_of_moves > 0) { no_more_moves = FALSE; } } } } // current_player cannot play. if (no_more_moves) { if (is_scoring_checked) // checkmate total_score = (scoring_player == current_player) ? LOSE_SCORE : WIN_SCORE; else // tie total_score = is_best ? 0 : TIE_SCORE; // in best difficulty: 0, otherwise: better only than LOSE_SCORE } // scoring_player's king has ceased to be else if (no_scoring_king) total_score = LOSE_SCORE; // other player's king is pushing up the daisies else if (no_other_king) total_score = WIN_SCORE; //RELEVANT ONLY FOR best DIFFICULTY! else if (is_best && is_scoring_checked) { if (is_scoring_checked) return LOSE_SCORE + 42; else if (is_other_checked) return WIN_SCORE - 42; } // both players' kings are alive and pining for the fjords else total_score = player_score - other_player_score; return total_score; }
// return the score of the best move found for a board // the best square is stored in *square // note - recursive function, searches nodes and childs int best_move(board_type board, char player, int *square, int move_num, int alpha, int beta) { int best_square = -1; int moves = 0; int i; move_heuristic_type move_heuristic[SQUARES]; // an array of 9 heuristc structs total_nodes++; // times we call best_move // we find calculate the heuristic value of each move // and sort the structs in descending order // this way, we speed things up a bit for(i=0; i<SQUARES; i++) { // if the square is available for play if(board[i] == empty) { int heuristic; int j; play(board, i, player); // we play the empty square heuristic = evaluate(board, player); // we get the heuristic value play(board, i, empty); // we reverse the play // now we must sort the picked up structs in descending order for(j = moves-1; j>=0 && move_heuristic[j].heuristic < heuristic; j--) { move_heuristic[j+1].heuristic = move_heuristic[j].heuristic; move_heuristic[j+1].square = move_heuristic[j].square; } move_heuristic[j+1].heuristic = heuristic; move_heuristic[j+1].square = i; moves++; } // we can store the structs and use qsort here instead. } for(i=0; i<moves; i++) { int score; int sq = move_heuristic[i].square; char w; // we make a move and get the score play(board, sq, player); w = winner(board); if(w == 'X') score = (max_moves + 1) - move_num; else if(w == 'O') score = move_num - (max_moves + 1); else if(w == 'T') score = 0; else // haven't finished board score = best_move(board, other_player(player), square, move_num + 1, alpha, beta); // we recurse // reverse the play play(board, sq, empty); // now we prune alpha-beta if(player == 'X') { if(score >= beta) { // cut off *square = sq; return score; } else if(score > alpha) { // we found a better alpha (alpha only increases) alpha = score; best_square = sq; } } else { if(score <= alpha) { // cut off *square = sq; return score; } else if(score < beta) { // we found that oponent has a best worse beta (beta only decreases) beta = score; best_square = sq; } } } *square = best_square; if(player == 'X') return alpha; else return beta; }
Move AIPlayer_fork::alpha_beta(GameBoard* game, int lookahead, int alpha, int beta, int player) { concurrent_vector<Move> all_moves = concurrent_get_all_moves(game, player); //cout << "Moves are: " << endl; //cout << m.x +1 << ", " << m.y + 1 << " Score: " << m.score << endl; if (all_moves.empty()) return Move(-1, -1, maximizing_player(player) * 35); if (lookahead == 0) { //return heuristic value of previous player if (!is_maximizing(player)) { Move temp = *(std::max_element(all_moves.begin(), all_moves.end(), [](Move m1, Move m2) { return m1.score < m2.score; })); //cout << "return: "<< temp.x +1 << ", " << temp.y + 1 << " Score: " << temp.score << endl; return temp; } else { Move temp = *(std::min_element(all_moves.begin(), all_moves.end(), [](Move m1, Move m2) { return m1.score < m2.score; })); //cout << "return: "<< temp.x +1 << ", " << temp.y + 1 << " Score: " << temp.score << endl; return temp; } } Move return_move; if (is_maximizing(player)) { task_group g; for (unsigned int i = 0; i < all_moves.size(); i++) { g.run([=, &all_moves, &return_move, &alpha, & beta] { GameBoard temp_board(game); temp_board.make_move(all_moves[i].x, all_moves[i].y, player); Move temp_move; temp_move = alpha_beta(&temp_board, lookahead - 1, alpha, beta, other_player(player)); if (temp_move.score > alpha) { return_move = all_moves[i]; alpha = temp_move.score; } if (alpha >= beta) { //g.cancel(); } }); } g.wait(); return return_move; } else { task_group g; for (unsigned int i = 0; i < all_moves.size(); i++) { g.run([=, &all_moves, &return_move, &alpha, &beta] { GameBoard temp_board(game); temp_board.make_move(all_moves[i].x, all_moves[i].y, player); Move temp_move; temp_move = alpha_beta(&temp_board, lookahead - 1, alpha, beta, other_player(player)); if (temp_move.score < beta) { beta = temp_move.score; return_move = all_moves[i]; } if (alpha >= beta) { //g.cancel(); } }); } g.wait(); return return_move; } }