def dijkstra(tiles, adversary_color, player): """Medium AI, makes a move that minimizes the other player's mobility""" # mobility is defined as the other player's possible moves print("{} is thinking...".format( othello.color(adversary_color, "Edsger Dijkstra"))) time.sleep(2) potential_moves = [] for index in range(64): if othello.is_valid_move(index, player, adversary=True, b=tiles) and tiles[index] == 0: potential_moves.append(index) best_move = 0 worst_mobility = sys.maxsize for move in potential_moves: copy = [tile for tile in tiles] board = othello.propogate_flips(move, player, adversary=True, b=copy) other_player = 2 if player == 1 else 1 mobility = len([ index for index in range(64) if othello.is_valid_move(index, other_player, adversary=True, b=board) and board[index] == 0 ]) if mobility < worst_mobility: worst_mobility = mobility best_move = move print("{} moved to {}!".format( othello.color(adversary_color, "Edsger Dijkstra"), othello.get_coordinate_from_index(best_move))) time.sleep(2) return best_move
def lovelace(tiles, adversary_color, player): """Easy AI, makes a move that maximizes its number of pieces on the board""" print("{} is thinking...".format( othello.color(adversary_color, "Ada Lovelace"))) time.sleep(2) potential_moves = [] for index in range(64): if othello.is_valid_move(index, player, adversary=True, b=tiles) and tiles[index] == 0: potential_moves.append(index) best_move = 0 best_total = 0 for move in potential_moves: copy = [tile for tile in tiles] board = othello.propogate_flips(move, player, adversary=True, b=copy) number_of_tiles = len([tile for tile in board if tile == 2]) if number_of_tiles > best_total: best_total = number_of_tiles best_move = move print("{} moved to {}!".format( othello.color(adversary_color, "Ada Lovelace"), othello.get_coordinate_from_index(best_move))) time.sleep(2) return best_move
def calculate_your_mobility(board, player): mobility = len([ index for index in range(64) if othello.is_valid_move( index, player if player == 2 else 1, adversary=True, b=board) and board[index] == 0 ]) return mobility
def euclid(tiles, adversary_color, player): """Simple AI, makes a random move from its potential moves""" print("{} is thinking...".format(othello.color(adversary_color, "Euclid"))) time.sleep(2) potential_moves = [] for index in range(64): if othello.is_valid_move(index, player, adversary=True, b=tiles) and tiles[index] == 0: potential_moves.append(index) print( [othello.get_coordinate_from_index(move) for move in potential_moves]) input() move = random.choice(potential_moves) print("{} moved to {}!".format(othello.color(adversary_color, "Euclid"), othello.get_coordinate_from_index(move))) time.sleep(2) return move
def turing(tiles, adversary_color, player): """Hard AI, makes a move that minimizes the other player's mobility, maximizes its own mobility, and avoids giving the other user corners""" # Priorities: # 1. If corner is available, take it # 2. If a move gives opponent a corner, don't consider it (unless necessary) # 3. Don't play in C Squares (unless necessary) # 4. Maximize our mobility # 5. Minimize opponent's mobility # 6. Control the sweet 16 # If you wanted to improve this more, here are other, not currently, explicitly implemented considerations: # - consider interior vs. frontior disks # - consider A- and B-squares (prioritize taking wall moves more) # - consider power moves/attacks for taking corners print("{} is thinking...".format( othello.color(adversary_color, "Alan Turing"))) time.sleep(2) potential_moves = [] for index in range(64): if othello.is_valid_move(index, player, adversary=True, b=tiles) and tiles[index] == 0: potential_moves.append(index) # STEP 1 # determine if moves could give opponent a corner bad_corner_moves = [] for move in potential_moves: copy = [tile for tile in tiles] board = othello.propogate_flips(move, player, adversary=True, b=copy) other_player = 2 if player == 1 else 1 if not len([ index for index in range(64) if othello.is_valid_move( index, other_player, adversary=True, b=board) and board[index] == 0 and index in CORNERS ]) == 0: bad_corner_moves.append(move) # determine if can get a corner right now good_corner_moves = [] for move in potential_moves: if move in CORNERS: good_corner_moves.append(move) # STEP 2 # begin evaluating move candidates to find best move best_move = -1 if not len(good_corner_moves) == 0: # we can take a corner most_tiles = 0 best_move = good_corner_moves[0] for corner_move in good_corner_moves: copy = [tile for tile in tiles] board = othello.propogate_flips(move, player, adversary=True, b=copy) number_of_tiles = len([tile for tile in board if tile == player]) if number_of_tiles > most_tiles: most_tiles = number_of_tiles best_move = corner_move else: # we can't take a corner good_moves = [ move for move in potential_moves if not move in bad_corner_moves and not move in X_SQUARES and not move in C_SQUARES ] if len(good_moves) == 0: good_moves = [ move for move in potential_moves if not move in bad_corner_moves and not move in X_SQUARES ] if len(good_moves) == 0: good_moves = [ move for move in potential_moves if not move in bad_corner_moves ] if len(good_moves) == 0: good_moves = potential_moves # begin mobility score calculation temp_mobility_scores = {} max_my_mobility = 0 min_your_mobility = sys.maxsize max_sweet_score = 0 # go through all moves and calculate increases in my mobility and decreases in your mobility for move in good_moves: copy = [tile for tile in tiles] board = othello.propogate_flips(move, player, adversary=True, b=copy) temp_my_mobility = calculate_my_mobility(board, player) max_my_mobility = temp_my_mobility if temp_my_mobility > max_my_mobility else max_my_mobility temp_your_mobility = calculate_your_mobility(board, other_player) min_your_mobility = temp_your_mobility if temp_your_mobility < min_your_mobility else min_your_mobility temp_sweet_score = calculate_sweet_16_score(board, player) max_sweet_score = temp_sweet_score if temp_sweet_score > max_sweet_score else max_sweet_score temp_mobility_scores[move] = (temp_my_mobility, temp_your_mobility, temp_sweet_score) # bound mobility scores between 0 and 1 mobility_scores = {} for move, scores in temp_mobility_scores.items(): if max_my_mobility == 0: my_mobility_score = 0 else: my_mobility_score = (scores[0] / max_my_mobility) if min_your_mobility == sys.maxsize: your_mobility_score = 0 else: your_mobility_score = (scores[1] / min_your_mobility) if max_sweet_score == 0: max_sweet = 0 else: max_sweet = (scores[2] / max_sweet_score) mobility_scores[move] = (my_mobility_score, your_mobility_score, max_sweet) # give each move a final mobility score to rank them best_move = 0 best_mobility_score = 0 for move, scores in mobility_scores.items(): # weighted sum: 50% my increased mobility, 25% your decreased mobility, 25% sweet 16 control increase mobility_score = (0.5 * scores[0]) + (0.25 * scores[1]) + ( 0.25 * scores[2]) if mobility_score > best_mobility_score: best_move = move best_mobility_score = mobility_score if best_move == -1: print("ERROR: Alan Turing couldn't find a move!") sys.exit(0) print("{} moved to {}!".format( othello.color(adversary_color, "Alan Turing"), othello.get_coordinate_from_index(best_move))) time.sleep(2) return best_move