def get_move(self, game_state, possible_moves): self.clock = time.process_time() self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05 if len(possible_moves) == 1: return possible_moves[0] current_depth = 1 prev_alpha = -INFINITY # Choosing an arbitrary move in case Minimax does not return an answer: best_move = possible_moves[0] # Initialize Minimax algorithm, still not running anything minimax = MiniMaxWithAlphaBetaPruning( self.utility, self.color, self.no_more_time, self.selective_deepening_criterion) # Iterative deepening until the time runs out. while True: print( 'going to depth: {}, remaining time: {}, prev_alpha: {}, best_move: {}' .format( current_depth, self.time_for_current_move - (time.process_time() - self.clock), prev_alpha, best_move)) try: (alpha, move), run_time = run_with_limited_time( minimax.search, (game_state, current_depth, -INFINITY, INFINITY, True), {}, self.time_for_current_move - (time.process_time() - self.clock)) except (ExceededTimeError, MemoryError): print('no more time, achieved depth {}'.format(current_depth)) break if self.no_more_time(): print('no more time') break prev_alpha = alpha best_move = move if alpha == INFINITY: print('the move: {} will guarantee victory.'.format(best_move)) break if alpha == -INFINITY: print('all is lost') break current_depth += 1 if self.turns_remaining_in_round == 1: self.turns_remaining_in_round = self.k self.time_remaining_in_round = self.time_per_k_turns else: self.turns_remaining_in_round -= 1 self.time_remaining_in_round -= (time.process_time() - self.clock) return best_move
def run(self): """The main loop. :return: The winner. """ white_player_exceeded = self.setup_player(sys.modules[self.white_player].Player, WHITE_PLAYER) black_player_exceeded = self.setup_player(sys.modules[self.black_player].Player, BLACK_PLAYER) winner = self.handle_time_expired(white_player_exceeded, black_player_exceeded) if winner: return winner game_state = gameutils.GameState() curr_player_idx = 0 remaining_run_times = self.remaining_times[:] k_count = 0 turns_elapsed = 0 # Running the actual game loop. The game ends if someone is left out of moves, # exceeds his time or maximum turns limit was reached. while True: gameutils.draw(game_state, self.verbose) player = self.players[curr_player_idx] remaining_run_time = remaining_run_times[curr_player_idx] try: possible_moves = game_state.get_possible_moves() self.print_if_verbose('Possible moves: {}'.format(possible_moves)) if not possible_moves: winner = self.make_winner_result(0 if curr_player_idx == 1 else 1) break move_idx, run_time = utils.run_with_limited_time( player.get_move, (copy.deepcopy(game_state), possible_moves), {}, remaining_run_time) remaining_run_times[curr_player_idx] -= run_time if remaining_run_times[curr_player_idx] < 0: raise utils.ExceededTimeError except (utils.ExceededTimeError, MemoryError): self.print_if_verbose('Player {} exceeded resources.'.format(player)) winner = self.make_winner_result(0 if curr_player_idx == 1 else 1) break game_state.perform_move(possible_moves[move_idx]) self.print_if_verbose('Player ' + repr(player) + ' performed the move: ' + repr(possible_moves[move_idx])) curr_player_idx = (curr_player_idx + 1) % 2 if curr_player_idx == 0: # White and black played. k_count = (k_count + 1) % self.k if k_count == 0: # K rounds completed. Resetting timers. remaining_run_times = self.remaining_times[:] turns_elapsed += 1 if turns_elapsed == self.maximum_turns_allowed: winner = self.make_winner_result(-1) break self.end_game(winner, turns_elapsed) return winner
def run(self): """The main loop. :return: The winner. """ # Setup each player x_player_exceeded = self.setup_player( sys.modules[self.x_player].Player, X_PLAYER) o_player_exceeded = self.setup_player( sys.modules[self.o_player].Player, O_PLAYER) winner = self.handle_time_expired(x_player_exceeded, o_player_exceeded) if winner: # One of the players exceeded the setup time return winner board_state = GameState() remaining_run_times = copy.deepcopy(self.player_move_times) k_count = 0 # Running the actual game loop. The game ends if someone is left out of moves, # or exceeds his time. while True: if self.verbose == 'y': board_state.draw_board() player = self.players[board_state.curr_player] remaining_run_time = remaining_run_times[board_state.curr_player] try: possible_moves = board_state.get_possible_moves() if not possible_moves: winner = self.make_winner_result(board_state.get_winner()) break # Get move from player move, run_time = utils.run_with_limited_time( player.get_move, (copy.deepcopy(board_state), possible_moves), {}, remaining_run_time * 1.5) remaining_run_times[board_state.curr_player] -= run_time if remaining_run_times[board_state.curr_player] < 0: raise utils.ExceededTimeError except (utils.ExceededTimeError, MemoryError): print('Player {} exceeded resources.'.format(player)) winner = self.make_winner_result( OPPONENT_COLOR[board_state.curr_player]) break board_state.perform_move(move[0], move[1]) if self.verbose == 'y': print('Player ' + repr(player) + ' performed the move: [' + str(move[0]) + ', ' + str(move[1]) + ']') if board_state.curr_player == X_PLAYER: k_count = (k_count + 1) % self.k if k_count == 0: # K rounds completed. Resetting timers. remaining_run_times = copy.deepcopy(self.player_move_times) self.end_game(winner) return winner
def run(self): """The main loop. :return: The winner. """ white_player_exceeded = self.setup_player(sys.modules[self.white_player].Player, WHITE_PLAYER) black_player_exceeded = self.setup_player(sys.modules[self.black_player].Player, BLACK_PLAYER) winner = self.handle_time_expired(white_player_exceeded, black_player_exceeded) if winner: return winner board_state = amazons_board.amazonsBoard() curr_player_idx = 0 remaining_run_times = self.remaining_times[:] k_count = 0 # Running the actual game loop. The game ends if someone is left out of moves, # or exceeds his time. while True: if self.printPref == 'y': board_state.printBoard() player = self.players[curr_player_idx] remaining_run_time = remaining_run_times[curr_player_idx] try: possible_moves = board_state.legalMoves() if not possible_moves: winner = self.make_winner_result(0 if curr_player_idx == 1 else 1) break move, run_time = utils.run_with_limited_time( player.get_move, (copy.deepcopy(board_state), possible_moves), {}, remaining_run_time*1.5) remaining_run_times[curr_player_idx] -= run_time if remaining_run_times[curr_player_idx] < 0: raise utils.ExceededTimeError except (utils.ExceededTimeError, MemoryError): print('Player {} exceeded resources.'.format(player)) winner = self.make_winner_result(0 if curr_player_idx == 1 else 1) break board_state.doMove(move) if self.printPref == 'y': print('Player ' + repr(player) + ' performed the move: ' + repr(move)) curr_player_idx = (curr_player_idx + 1) % 2 if curr_player_idx == 0: # White and black played. k_count = (k_count + 1) % self.k if k_count == 0: # K rounds completed. Resetting timers. remaining_run_times = self.remaining_times[:] self.end_game(winner) return winner
def get_move(self, board_state, possible_moves): self.move_index += 2 self.clock = time.process_time() self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05 if len(possible_moves) == 1: return possible_moves[0] current_depth = 1 prev_alpha = -INFINITY # Choosing an arbitrary move: best_move = possible_moves[0] minimax = SelectiveMiniMaxWithAlphaBetaPruning(self.utility, self.color, self.no_more_time, self.w) # Iterative deepening until the time runs out. while True: if self.no_more_time(): print('no more time') break print('going to depth: {}, remaining time: {}, prev_alpha: {}, best_move: {}'.format( current_depth, self.time_for_current_move - (time.process_time() - self.clock), prev_alpha, best_move)) try: (alpha, move), run_time = run_with_limited_time( minimax.search, (board_state, current_depth, -INFINITY, INFINITY, True), {}, self.time_for_current_move - (time.process_time() - self.clock)) except (ExceededTimeError, MemoryError): print('no more time') break prev_alpha = alpha best_move = move if alpha == INFINITY: print('the move: {} will guarantee victory.'.format(best_move)) break if alpha == -INFINITY: print('all is lost') break current_depth += 1 if self.turns_remaining_in_round == 1: self.turns_remaining_in_round = self.k self.time_remaining_in_round = self.time_per_k_turns else: self.turns_remaining_in_round -= 1 self.time_remaining_in_round -= (time.process_time() - self.clock) return best_move
def setup_player(self, player_class, player_type): """ An auxiliary function to populate the players list, and measure setup times on the go. :param player_class: The player class that should be initialized, measured and put into the list. :param player_type: Player type, passed as an argument to the player. :return: A boolean. True if the player exceeded the given time. False otherwise. """ try: player, measured_time = utils.run_with_limited_time( player_class, (self.setup_time, player_type, self.time_per_k_turns, self.k), {}, self.setup_time*1.5) except MemoryError: return True self.players[player_type] = player return measured_time > self.setup_time
def setup_player(self, player_class, player_color): """ An auxiliary function to populate the players list, and measure setup times on the go. :param player_class: The player class that should be initialized, measured and put into the list. :param player_color: Player color, passed as an argument to the player. :return: A boolean. True if the player exceeded the given time. False otherwise. """ try: player, measured_time = utils.run_with_limited_time( player_class, (self.setup_time, player_color, self.time_per_k_turns, self.k), {}, self.setup_time*1.5) except MemoryError: return True self.players.append(player) return measured_time > self.setup_time
def get_move(self, game_state, possible_moves): """ This method is the same as the get_move method of the simple_player, but with a fix of the time management bug found in simple_player that is not counting a move in case this move is the only possible move, thus makes a mis-synchronization between the internal time calculation of the class and the external time calculation which ultimately results in a timeout. """ self.clock = time.process_time() self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05 if len(possible_moves) == 1: # If this was the last turn in current round. if self.turns_remaining_in_round == 1: self.turns_remaining_in_round = self.k # Reset turns count. self.time_remaining_in_round = self.time_per_k_turns # Reset time count. else: self.turns_remaining_in_round -= 1 # Decrease turns amount by 1. self.time_remaining_in_round -= (time.process_time() - self.clock) # Update remaining time. return possible_moves[0] current_depth = 1 prev_alpha = -INFINITY # Choosing an arbitrary move in case Minimax does not return an answer. best_move = possible_moves[0] # Initialize Minimax algorithm, still not running anything. minimax = MiniMaxWithAlphaBetaPruning(self.utility, self.color, self.no_more_time, self.selective_deepening_criterion) # Iterative deepening until the time runs out. while True: print('going to depth: {}, remaining time: {}, prev_alpha: {}, best_move: {}'.format( current_depth, self.time_for_current_move - (time.process_time() - self.clock), prev_alpha, best_move)) try: (alpha, move), run_time = run_with_limited_time( minimax.search, (game_state, current_depth, -INFINITY, INFINITY, True), {}, self.time_for_current_move - (time.process_time() - self.clock)) except (ExceededTimeError, MemoryError): print('no more time, achieved depth {}'.format(current_depth)) break if self.no_more_time(): print('no more time') break prev_alpha = alpha best_move = move if alpha == INFINITY: print('the move: {} will guarantee victory.'.format(best_move)) break if alpha == -INFINITY: print('all is lost') break current_depth += 1 # If this was the last turn in current round. if self.turns_remaining_in_round == 1: self.turns_remaining_in_round = self.k self.time_remaining_in_round = self.time_per_k_turns else: self.turns_remaining_in_round -= 1 self.time_remaining_in_round -= (time.process_time() - self.clock) return best_move
def get_move(self, game_state, possible_moves): self.clock = time.process_time() self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05 if len(possible_moves) == 1: # update time and turns if self.turns_remaining_in_round == 1: self.turns_remaining_in_round = self.k self.time_remaining_in_round = self.time_per_k_turns else: self.turns_remaining_in_round -= 1 self.time_remaining_in_round -= (time.process_time() - self.clock) self.curr_board = game_state.board # save game board return possible_moves[0] current_depth = 1 prev_alpha = -INFINITY # Choosing an arbitrary move in case Minimax does not return an answer: best_move = possible_moves[0] # Initialize Minimax algorithm, still not running anything minimax = MiniMaxWithAlphaBetaPruning( self.utility, self.color, self.no_more_time, self.selective_deepening_criterion) # Iterative deepening until the time runs out. while True: time_for_current_depth: float print( 'going to depth: {}, remaining time: {}, prev_alpha: {}, best_move: {}' .format( current_depth, current_depth, self.time_for_current_move - (time.process_time() - self.clock), prev_alpha, best_move)) # The array is init for 6 depth (the average depth) if he succeeded more than that give the remain time if current_depth - 1 > 5: time_for_current_depth = self.time_for_current_move - ( time.process_time() - self.clock) else: # Deeper in the tree get more time (see array values) time_for_current_depth = self.time_for_current_move * self.split_time_array[ current_depth - 1] try: (alpha, move), run_time = run_with_limited_time( minimax.search, (game_state, current_depth, -INFINITY, INFINITY, True), {}, time_for_current_depth) except (ExceededTimeError, MemoryError): print('no more time, achieved depth {}'.format(current_depth)) break if self.no_more_time(): print('no more time') break prev_alpha = alpha best_move = move if alpha == INFINITY: print('the move: {} will guarantee victory.'.format(best_move)) break if alpha == -INFINITY: print('all is lost') break current_depth += 1 if self.turns_remaining_in_round == 1: self.turns_remaining_in_round = self.k self.time_remaining_in_round = self.time_per_k_turns else: self.turns_remaining_in_round -= 1 self.time_remaining_in_round -= (time.process_time() - self.clock) self.curr_board = game_state.board # save game board return best_move
def run(self): """The main loop. :return: The winner. """ # Setup each player red_player_exceeded = self.setup_player( sys.modules[self.red_player].Player, RED_PLAYER) black_player_exceeded = self.setup_player( sys.modules[self.black_player].Player, BLACK_PLAYER) winner = self.handle_time_expired(red_player_exceeded, black_player_exceeded) if winner: # One of the players exceeded the setup time return winner board_state = GameState() remaining_run_times = copy.deepcopy(self.player_move_times) k_count = 0 # Running the actual game loop. The game ends if someone is left out of moves, # or exceeds his time. while True: if self.verbose == 'y': board_state.draw_board() player = self.players[board_state.curr_player] remaining_run_time = remaining_run_times[board_state.curr_player] try: possible_moves = board_state.get_possible_moves() if not possible_moves: winner = self.make_winner_result( OPPONENT_COLOR[board_state.curr_player]) break # Get move from player move, run_time = utils.run_with_limited_time( player.get_move, (copy.deepcopy(board_state), possible_moves), {}, remaining_run_time * 1.5) ### remaining_run_times[board_state.curr_player] -= run_time if remaining_run_times[board_state.curr_player] < 0: raise utils.ExceededTimeError except (utils.ExceededTimeError, MemoryError): print('Player {} exceeded resources.'.format(player)) winner = self.make_winner_result( OPPONENT_COLOR[board_state.curr_player]) break board_state.perform_move(move) if self.verbose == 'y': print('Player ' + repr(player) + ' performed the move: ' + str(move)) if board_state.turns_since_last_jump >= MAX_TURNS_NO_JUMP: print('Number of turns without jumps exceeded {}'.format( MAX_TURNS_NO_JUMP)) winner = self.make_winner_result(TIE) break if board_state.curr_player == RED_PLAYER: # red and black played. k_count = (k_count + 1) % self.k if k_count == 0: # K rounds completed. Resetting timers. remaining_run_times = copy.deepcopy(self.player_move_times) self.end_game(winner) return winner
def get_move(self, game_state, possible_moves): """ This method returns the next move of the player by using a minimax search with Alpha-Beta pruning. In this method we apply a smart time management mechanism. The method performs a minimax search layer by layer, but in case the alpha value and best next move have not been changed in 3 layer cycles (Starting from 5 layer) we stop the search and the best move so far is returned, thus saving time for future moves. In the last turn of the cycle, we exhaust all the remaining time. """ self.clock = time.process_time() self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05 # If there is only one possible move. if len(possible_moves) == 1: # If this was the last turn in current round. if self.turns_remaining_in_round == 1: self.turns_remaining_in_round = self.k # Reset turns count. self.time_remaining_in_round = self.time_per_k_turns # Reset time count. else: self.turns_remaining_in_round -= 1 # Decrease turns amount by 1. self.time_remaining_in_round -= ( time.process_time() - self.clock) # Update remaining time. return possible_moves[0] current_depth = 1 prev_alpha = -INFINITY # Choosing an arbitrary move in case Minimax does not return an answer. best_move = possible_moves[0] # Initialize Minimax algorithm, still not running anything. minimax = MiniMaxWithAlphaBetaPruning( self.utility, self.color, self.no_more_time, self.selective_deepening_criterion) roundsNotChanged = 0 # Iterative deepening until the time runs out. while True: print( 'going to depth: {}, remaining time: {}, prev_alpha: {}, best_move: {}' .format( current_depth, self.time_for_current_move - (time.process_time() - self.clock), prev_alpha, best_move)) try: (alpha, move), run_time = run_with_limited_time( minimax.search, (game_state, current_depth, -INFINITY, INFINITY, True), {}, self.time_for_current_move - (time.process_time() - self.clock)) except (ExceededTimeError, MemoryError): print('no more time, achieved depth {}'.format(current_depth)) break if self.no_more_time(): print('no more time') break # Check if both alpha and next best move according to the last search has not been changed. if prev_alpha == alpha and move.origin_loc == best_move.origin_loc \ and move.target_loc == best_move.target_loc and current_depth > MIN_DEEPENING_DEPTH: # If so, then increment the counter. roundsNotChanged += 1 else: # alpha or next best move were changed - Reset counter. roundsNotChanged = 0 # If alpha and best move have not been changed in 3 cycles, stop searching and save time for future moves. if roundsNotChanged == 3 and self.turns_remaining_in_round > 1: print( 'Best move and alpha has not changed for {} rounds, depth is {}.' .format(roundsNotChanged, current_depth)) break prev_alpha = alpha best_move = move if alpha == INFINITY: print('the move: {} will guarantee victory.'.format(best_move)) break if alpha == -INFINITY: print('all is lost') break current_depth += 1 # If this was the last turn in current round. if self.turns_remaining_in_round == 1: self.turns_remaining_in_round = self.k # Reset turns count. self.time_remaining_in_round = self.time_per_k_turns # Reset time count. else: self.turns_remaining_in_round -= 1 # Decrease turns amount by 1. self.time_remaining_in_round -= (time.process_time() - self.clock ) # Update remaining time. return best_move
def run(self): """The main loop. :return: The winner. """ white_player_exceeded = self.setup_player( sys.modules[self.white_player].Player, WHITE_PLAYER) black_player_exceeded = self.setup_player( sys.modules[self.black_player].Player, BLACK_PLAYER) winner = self.handle_time_expired(white_player_exceeded, black_player_exceeded) if winner: return winner game_state = gameutils.GameState() curr_player_idx = 0 remaining_run_times = self.remaining_times[:] k_count = 0 turns_elapsed = 0 # Running the actual game loop. The game ends if someone is left out of moves, # exceeds his time or maximum turns limit was reached. while True: gameutils.draw(game_state, self.verbose) player = self.players[curr_player_idx] remaining_run_time = remaining_run_times[curr_player_idx] try: possible_moves = game_state.get_possible_moves() self.print_if_verbose( 'Possible moves: {}'.format(possible_moves)) if not possible_moves: winner = self.make_winner_result(0 if curr_player_idx == 1 else 1) break move_idx, run_time = utils.run_with_limited_time( player.get_move, (copy.deepcopy(game_state), possible_moves), {}, remaining_run_time) remaining_run_times[curr_player_idx] -= run_time if remaining_run_times[curr_player_idx] < 0: raise utils.ExceededTimeError except (utils.ExceededTimeError, MemoryError): self.print_if_verbose( 'Player {} exceeded resources.'.format(player)) winner = self.make_winner_result(0 if curr_player_idx == 1 else 1) break game_state.perform_move(possible_moves[move_idx]) self.print_if_verbose('Player ' + repr(player) + ' performed the move: ' + repr(possible_moves[move_idx])) curr_player_idx = (curr_player_idx + 1) % 2 if curr_player_idx == 0: # White and black played. k_count = (k_count + 1) % self.k if k_count == 0: # K rounds completed. Resetting timers. remaining_run_times = self.remaining_times[:] turns_elapsed += 1 if turns_elapsed == self.maximum_turns_allowed: winner = self.make_winner_result(-1) break self.end_game(winner, turns_elapsed) return winner