def minimax(board, depth, alpha, beta, maximizingPlayer): if depth == 0 or endgame(board): return eval_func(board) if maximizingPlayer: max_eval = -infinity all_moves = board.get_legal_moves(Team.WHITE) random.shuffle(all_moves) for current_move in all_moves: new_board = board.copy_state() new_board.play_command(Command(current_move[0], current_move[1])) eval = minimax(new_board, depth - 1, alpha, beta, False) max_eval = max(max_eval, eval) alpha = max(alpha, eval) if beta <= alpha: break return max_eval else: min_eval = +infinity all_moves = board.get_legal_moves(Team.BLACK) random.shuffle(all_moves) for current_move in all_moves: new_board = board.copy_state() new_board.play_command(Command(current_move[0], current_move[1])) eval = minimax(new_board, depth - 1, alpha, beta, True) min_eval = min(min_eval, eval) beta = min(beta, eval) if beta <= alpha: break return min_eval
def min_max(board, depth, team): if depth >= MAX_DEPTH: h = heuristic(board, team) return [h, None] moves = [] for move in remove_bad_moves(board): # changer de player une fois sur deux current_board = board.copy_state() current_board.play_command(Command(move[0], move[1])) if current_board.get_winner() is None: pass elif current_board.get_winner() == team: return [1000, move] else: return [-10000, move] m = min_max(current_board, depth + 1, team) m[1] = move moves.append(m) if depth % 2 == 0: move1 = [test[0] for test in moves] selection = [] for i, e in enumerate(move1): if e == max(move1): selection.append(i) move = moves[random.choice(selection)] else: move1 = [test[0] for test in moves] selection = [] for i, e in enumerate(move1): if e == min(move1): selection.append(i) move = moves[random.choice(selection)] return move
def get_command(board): while True: time.sleep(0.05) if board.game_over(): break # Thread closes once the game is over team_to_play = board.get_turn() print('{} to play...'.format('White' if team_to_play == Team.WHITE else 'Black')) move_from_str = input('Move from: ') move_to_str = input('Move to: ') letters = string.ascii_lowercase move_from_ls = list(move_from_str) move_to_ls = list(move_to_str) try: move_from_ls[0] = letters.index(move_from_ls[0].lower()) move_to_ls[0] = letters.index(move_to_ls[0].lower()) move_from = Vec2I(int(move_from_ls[0]), int(move_from_ls[1])) move_to = Vec2I(int(move_to_ls[0]), int(move_to_ls[1])) except ValueError: print('Please specify a letter then a number with no space between them. Example: d0 and d3') continue command = Command(move_from, move_to) return command
def read_game_file(path): """ Reads a JSON game file and returns a board with a list of command to interpret. Example of a very low rating game file: { "date": "24/02/2021 11:45:20", "cols": 8, "rows": 8, "stack": 8, "white_queen": "4, 1", "black_queen": "5, 8", "moves": ["4, 1 -> 4, 8", "5, 8 -> 4, 8"] } :param path: The path to the file :return: A dictionary containing the date, width, height, stack, white_queen, black_queen and moves positions encoded in the game's classes """ data_formatted = {} with open(path, 'r') as infile: data = json.load(infile) data_formatted['cols'] = data['cols'] data_formatted['rows'] = data['rows'] data_formatted['stack'] = data['stack'] white_queen = data['white_queen'].split(', ') black_queen = data['black_queen'].split(', ') data_formatted['white_queen'] = Vec2I.parse_from_list(white_queen) data_formatted['black_queen'] = Vec2I.parse_from_list(black_queen) date_str = data.get('date') if date_str is not None: date = datetime.datetime.strptime(date_str, '%d/%m/%Y %H:%M:%S') data_formatted['date'] = date command_list = [] moves_str = data['moves'] for move in moves_str: move_split = move.split(' -> ') move_from_str = move_split[0].split(', ') move_to_str = move_split[1].split(', ') move_from = Vec2I.parse_from_list(move_from_str) move_to = Vec2I.parse_from_list(move_to_str) command = Command(move_from, move_to) command_list.append(command) data_formatted['moves'] = command_list return data_formatted
def make_play(board, your_team, last_move): """ Example of a very stupid AI. Don't do this at home. """ global DP_white, DP_black all_moves = board.get_legal_moves(your_team) queen_ennemy_pos = board.search_queen( get_ennemy_team(your_team)).get_position() values = -1e10 poss_move = [] leafs_explored = [0] for possible_move in all_moves: f, to = possible_move x = to.x y = to.y if x == queen_ennemy_pos.x and y == queen_ennemy_pos.y: # print('CAPTURE') return possible_move else: current_board = board.copy_state() current_board.play_command(Command(f, to)) v = minimax_alpha_beta(convert_board( current_board), your_team, your_team, 1, leafs_explored, alpha=-1e9, beta=1e9) # print(v) if v > values: poss_move = [possible_move] values = v elif v == values: poss_move.append(possible_move) # print(len(DP_white)) choice = random.choice(poss_move) print('SCORE : ', values) print(your_team, 'MOVE', choice, 'LEAFS = ', leafs_explored[0]) return choice
def make_play(board, your_team, last_move): global turn all_moves = board.get_legal_moves(your_team) all_final_positions = [move[1] for move in all_moves] all_double_moves = [] random.shuffle(all_moves) for final_position in all_final_positions: if all_final_positions.count(final_position) >= 2: all_double_moves.append(final_position) enemy_positions, enemy_moves = [], [] for move in board.get_legal_moves(enemy_moves): enemy_positions.append(move[0]) enemy_moves.append(move[1]) enemy_team = Team.WHITE if your_team == Team.BLACK else Team.BLACK queen_in_danger = False for move in board.get_legal_moves(enemy_team): if move[1] == board.search_queen(your_team).get_position(): queen_in_danger = True break queen_moves = [] for move in all_moves: # lists all queen moves that don't immediately put her in danger if move[0] == board.search_queen(your_team).get_position(): if move[1] in enemy_moves: # removes all moves putting the queen in the line of fire all_moves.pop(all_moves.index(move)) else: queen_moves.append(move) if turn < 2: for move in all_moves: # checks all moves in the outer center circle if move[1] in tier_2: all_moves.insert(0, all_moves.pop(all_moves.index(move))) for move in all_moves: # checks all moves in the inner center circle if move[1] in tier_1: all_moves.insert(0, all_moves.pop(all_moves.index(move))) if queen_in_danger: # if queen is in danger, checks all possible queen moves first for move in queen_moves: all_moves.insert(0, all_moves.pop(all_moves.index(move))) for move in all_moves: if move[1] in all_double_moves: all_moves.insert(0, all_moves.pop(all_moves.index(move))) for move in all_moves: # checks all moves capable of capturing enemy monkeys if move[1] in enemy_positions: all_moves.insert(0, all_moves.pop(all_moves.index(move))) for move in all_moves: # checks all moves on an enemy path LAST if move[1] in enemy_moves: all_moves.append(all_moves.pop(all_moves.index(move))) best_move = all_moves[0] init_time = time.time() if your_team == Team.WHITE: best_val = -infinity for current_move in all_moves: new_board = board.copy_state() new_board.play_command(Command(current_move[0], current_move[1])) val = minimax(new_board, depth, alpha, beta, False) if val > best_val: best_val = val best_move = current_move curr_time = time.time() print(curr_time - init_time) if curr_time - init_time > time_limit: break else: best_val = +infinity for current_move in all_moves: new_board = board.copy_state() new_board.play_command(Command(current_move[0], current_move[1])) val = minimax(new_board, depth, alpha, beta, True) if val < best_val: best_val = val best_move = current_move curr_time = time.time() print(curr_time - init_time) if curr_time - init_time > time_limit: break turn += 1 return best_move
def list_plays(self, player): legal_commands = [] legal_moves = self._game.get_legal_moves(player) for move_pair in legal_moves: legal_commands.append(Command(move_pair[0], move_pair[1])) return legal_commands
def make_play(board, your_team, last_move): current_board1 = board.copy_state() enemy_team = Team.WHITE if your_team == Team.BLACK else Team.BLACK print(enemy_team) enemy_queen = board.search_queen(enemy_team) noeud1 = 0 score1 = [] all_moves = board.get_legal_moves(your_team) for move in all_moves: board = current_board1.copy_state() enemy_queen = board.search_queen(enemy_team) if move[1] == enemy_queen.get_position(): print("sortie1") return move move_command = Command(move[0], move[1]) board.play_command(move_command) current_board2 = board.copy_state() noeud2 = 0 score2 = [] opponent_possible_responses = board.get_legal_moves() try: for opponent_possible_move in opponent_possible_responses: board = current_board2.copy_state() opponent_possible_move_command = Command( opponent_possible_move[0], opponent_possible_move[1]) board.play_command(opponent_possible_move_command) if opponent_possible_move[1] == enemy_queen.get_position(): print("ko") break current_board3 = board.copy_state() noeud3 = 0 enemy_queen = board.search_queen(enemy_team) responses = board.get_legal_moves() for response_move in responses: board = current_board3 enemy_queen = board.search_queen(enemy_team) try: response_move_command = Command( response_move[0], response_move[1]) board.play_command(response_move_command) if board.game_over: return move score3 = 100 - 10 * getdistance( response_move[1], enemy_queen) noeud3 = score3 if score3 >= noeud3 else noeud3 except Exception: pass score2.append(noeud3) noeud2 = min(score2) except Exception: pass score1.append(noeud2) if len(score1) == len(all_moves): noeud1 = max(score1) selected_move = all_moves[score1.index(noeud1)] return selected_move else: print(" y a un pépin kekpart :( ")
def make_play(board, your_team, last_move): """ Your AI entry point. This function gets called every time your AI is asked to make a play. The parameters contains all the information you need to picture the game state. The given lists of entities, queen information, etc... are a deep copy of the current game state, so don't try changing values there as this won't impact the game :p The execution time of this function is taken into account at each move, and a time limit is given to each team. :param board: the whole game state :param your_team: your team. Either Team.WHITE or Team.BLACK :param last_move: a tuple of two Vec2I (Vec2I(x_from, y_from), Vec2I(x_to, y_to)) of your opponent's last move. None if you are doing the first game move. :return: two objects Vec2I, Vec2I. The first object is the position of the piece you want to move, the second """ # a list containing all the entities from all the teams (either Monkeys or Queens) entities = board.get_entities() # just like entities, but into a map (dictionary). The key is a Vec2I object containing the position where you # want to get the entity. Use entity_map.get(Vec2I(x, y)) instead of entity_map[Vec2I(x, y)] if you want to avoid # raising a KeyError. Vec2I is used for the positions entity_map = board.get_entity_map() # List all the possible legal moves all_possible_moves = board.get_legal_moves(your_team) # You can iterate over all the entities like so: for entity in entities: position = entity.get_position() team = entity.get_team() print('Entity at position {}, is from team {}'.format(position, team)) # You can get other information from the board functions. your_queen = board.search_queen(your_team) # There are only two teams, either Team.WHITE or Team.BLACK enemy_team = None if your_team == Team.WHITE: enemy_team = Team.BLACK else: enemy_team = Team.WHITE # you can do the same with this one liner enemy_team = Team.WHITE if your_team == Team.BLACK else Team.BLACK # get the enemy queen info from the board enemy_queen = board.search_queen(enemy_team) # Get the position of an entity, for example, with this queen # This can also work with Monkeys your_queen_position = enemy_queen.get_position() # Get the queen stack (number of remaining monkeys) your_queen_stack = your_queen.get_stack() # Print the position information, positions use the object Vec2I, defined in the file src/game/geo.py print(your_queen_position.x, your_queen_position.y) # Get all the possible moves for your queen possible_moves = your_queen.get_legal_moves() # We want to move our queen one cell down your_queen_x = your_queen_position.x your_queen_y = your_queen_position.y # Again, the game uses the Vec2I object for the positions new_position = Vec2I(your_queen_x, your_queen_y + 1) # As the board is a DEEP COPY of the real board, you can use it to forecast the future, for example, if you # want to list all your enemy moves after the move you want to select # As said, you have to return a tuple of Vec2I from this function, but to make a play you have to put those # two Vec2I in a Command object move_command = Command(your_queen_position, new_position) # Make a copy of the current game state current_board = board.copy_state() # Plays the command, now the board is just like you have played your decised move board.make_play(move_command) # Forecast all the legal moves from your opponent opponent_possible_responses = board.get_legal_moves() # We check if the new position is a legal move if new_position in possible_moves: # We make this play by returning the new_position return your_queen_position, new_position else: new_position = random.choice(possible_moves) return your_queen_position, new_position
from src.game.command import Command from src.game.geo import Vec2I ROWS = 8 COLS = 8 white_queen = Queen(Vec2I(3, 0), Team.WHITE, monkey_stack=8) black_queen = Queen(Vec2I(4, 7), Team.BLACK, monkey_stack=8) board = Board(cols=COLS, rows=ROWS) board.add_entity(white_queen) board.add_entity(black_queen) board.draw() while True: str_from = input('Piece from (x, y): ') str_from = str_from.split(',') pos_from = Vec2I.parse_from_list(str_from) str_to = input('Piece to (x, y): ') str_to = str_to.split(', ') pos_to = Vec2I.parse_from_list(str_to) command = Command(pos_from, pos_to) try: board.play_command(command) except GameException as exc: print(exc)
def play_match(white_team, black_team, white_team_path, black_team_path): print('\033[1;36;40m Starting match {} vs {} \033[1;33;40m'.format( white_team, black_team)) date = datetime.datetime.now() dict = {} dict['date'] = date.strftime('%d/%m/%Y %H:%M:%S') dict['white_team'] = white_team dict['black_team'] = black_team dict['stack'] = 12 dict['cols'] = 8 dict['rows'] = 8 dict['white_queen'] = '3, 0' dict['black_queen'] = '4, 7' moves = [] last_move = None winner = None reason = 'None' white_remaining_time_ms = 4 * 60 * 1000 # 3 minutes black_remaining_time_ms = 4 * 60 * 1000 # 3 minutes white_team_function = load_function(white_team_path) black_team_function = load_function(black_team_path) board = load_game() signal.signal(signal.SIGALRM, timeout_handler) while board.get_winner() is None: if len(board.get_legal_moves()) == 0: winner = Team.WHITE if board.get_turn( ) == Team.BLACK else Team.BLACK reason = 'out of legal moves' print( '\033[1;31;40m Game over. {} is out of legal moves.\033[1;37;40m' .format('black' if winner == Team.WHITE else 'white')) break board_copy = board.copy_state() start = datetime.datetime.now() if board.get_turn() == Team.WHITE: try: print('\033[1;32;40m White to play \033[1;37;40m') signal.alarm(int(white_remaining_time_ms / 1000)) play = white_team_function(board_copy, Team.WHITE, last_move) signal.alarm(0) last_move = play end = datetime.datetime.now() diff = int((end - start).seconds * 1000) white_remaining_time_ms -= diff command = Command(play[0], play[1]) board.play_command(command) moves.append('({}, {} -> {}, {})'.format( play[0].x, play[0].y, play[1].x, play[1].y)) except TimeOutException as tout: print( '\033[1;31;40m Team {} timed out, dropping the game.\033[1;37;40m' .format(white_team)) reason = 'timeout' winner = Team.BLACK break except Exception as e: print( '\033[1;31;40m Team: {} got exception: {}, dropping the game\033[1;37;40m' .format(white_team, e)) reason = 'exception' winner = Team.BLACK break else: try: print('\033[1;32;40m Black to play \033[1;37;40m') signal.alarm(int(black_remaining_time_ms / 1000)) play = black_team_function(board_copy, Team.BLACK, last_move) signal.alarm(0) last_move = play end = datetime.datetime.now() diff = int((end - start).seconds * 1000) black_remaining_time_ms -= diff command = Command(play[0], play[1]) board.play_command(command) moves.append('({}, {} -> {}, {})'.format( play[0].x, play[0].y, play[1].x, play[1].y)) except TimeOutException as tout: print( '\033[1;31;40m Team {} timed out, dropping the game.\033[1;37;40m' .format(black_team)) reason = 'timeout' winner = Team.WHITE break except Exception as e: print( '\033[1;31;40m Team: {} got exception: {}, dropping the game\033[1;37;40m' .format(black_team, e)) reason = 'exception' winner = Team.WHITE break print('Move player: {} from team {}. White time: {} Black time: {}'. format(last_move, 'white' if board.get_turn() == Team.BLACK else 'black', white_remaining_time_ms, black_remaining_time_ms)) if winner is None: print("\033[1;31;40mQueen captured!\033[1;37;40m") winner = board.get_winner() reason = 'queen captured' print('\033[1;31;40m Match {} vs {}, team {} wins\033[1;37;40m'.format( white_team, black_team, white_team if winner == Team.WHITE else black_team)) dict['winner'] = 'white' if winner == Team.WHITE else 'black' dict['white_remaining_time'] = white_remaining_time_ms dict['black_remaining_time'] = black_remaining_time_ms dict['moves'] = moves dict['reason'] = reason return dict
def minimax(board, your_team, enemy_team, max_depth, part, cut, root_move=None, score=0, depth=0, alpha=(-math.inf, None), beta=(math.inf, None), maximizingPlayer=True): if depth == max_depth: answer = (score, root_move) elif maximizingPlayer: maxEval = (-math.inf, root_move) pruning = False moves = board.get_legal_moves(your_team) if depth == 0: moves = moves[round(len(moves) / cut * part):round(len(moves) / cut * (part + 1))] i = 0 while i < len(moves) and not pruning: if depth == 0: root_move = moves[i] map = board.get_entity_map() sourceMove = Vec2I(moves[i][0].x, moves[i][0].y) targetMove = Vec2I(moves[i][1].x, moves[i][1].y) sourcePawn = map.get(sourceMove) targetPawn = map.get(targetMove) value = 0 if targetPawn: if targetPawn.is_queen(): return (math.inf, root_move) else: value += 1 if sourcePawn: if sourcePawn.is_queen(): if not targetPawn: value += 0.6 new_move = Command(moves[i][0], moves[i][1]) new_board = board.copy_state() new_board.play_command(new_move) evaluation = minimax(new_board, your_team, enemy_team, max_depth, part, cut, root_move, score + value, depth + 1, alpha, beta, False) if maxEval[0] != evaluation[0]: maxEval = max(maxEval, evaluation) if alpha[0] != evaluation[0]: alpha = max(alpha, evaluation) if beta[0] <= alpha[0]: pruning = True i = i + 1 answer = maxEval else: minEval = (math.inf, root_move) pruning = False moves = board.get_legal_moves(enemy_team) i = 0 while i < len(moves) and not pruning: map = board.get_entity_map() sourceMove = Vec2I(moves[i][0].x, moves[i][0].y) targetMove = Vec2I(moves[i][1].x, moves[i][1].y) sourcePawn = map.get(sourceMove) targetPawn = map.get(targetMove) value = 0 if targetPawn: if targetPawn.is_queen(): return (-math.inf, root_move) else: value -= 1 if sourcePawn: if sourcePawn.is_queen(): if not targetPawn: value -= 0.6 new_move = Command(moves[i][0], moves[i][1]) new_board = board.copy_state() new_board.play_command(new_move) evaluation = minimax(new_board, your_team, enemy_team, max_depth, part, cut, root_move, score + value, depth + 1, alpha, beta, True) if minEval[0] != evaluation[0]: minEval = min(minEval, evaluation) if beta[0] != evaluation[0]: beta = min(beta, evaluation) if beta[0] <= alpha[0]: pruning = True i = i + 1 answer = minEval return answer