def get_move(self, game_state, possible_moves): self.clock = time.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] # best_move = possible_moves[0] # next_state = copy.deepcopy(game_state) # next_state.perform_move(best_move[0], best_move[1]) # # Choosing an arbitrary move # # Get the best move according the utility function # for move in possible_moves: # new_state = copy.deepcopy(game_state) # new_state.perform_move(move[0], move[1]) # if self.utility(new_state) > self.utility(next_state): # next_state = new_state # best_move = move best_move = possible_moves[0] min_max = MiniMaxAlgorithm(self.utility, self.color, self.no_more_time, None) self.depth = 1 while self.no_more_time() is False: min_max_val = min_max.search(game_state, self.depth, True)[1] best_move = min_max_val if min_max_val is not None else best_move self.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.time() - self.clock) return best_move
def iterative_deepening(self, state): mini_max = MiniMaxAlgorithm(self.utility, self.color, self.no_more_time, False) depth = 1 optimal_move = None while True: _, move = mini_max.search(state, depth, True) if move is None: break optimal_move = move depth += 1 return optimal_move
def get_move(self, game_state, possible_moves): self.clock = time.time() self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05 if len(possible_moves) == 1: print("min max : only one choice") return possible_moves[0] best_move = possible_moves[0] next_state = copy.deepcopy(game_state) next_state.perform_move(best_move[0], best_move[1]) best_util = self.utility(next_state) min_max = MiniMaxAlgorithm(self.utility, self.color, self.no_more_time, self.selective_deepening_criterion) i = 1 depth = 0 while not self.no_more_time(): curr_best_util, curr_best_move = min_max.search( game_state, i, True) depth += 1 if curr_best_util > best_util: best_move = curr_best_move best_util = curr_best_util i += 1 # Not sure if we need these lines,compied them from simple_player, code works with / without them - does not # understand their propose # TODO: check if needed or not 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.time() - self.clock) #print("min_max depth : ", depth) return best_move
class Player(AbstractPlayer): def __init__(self, setup_time, player_color, time_per_k_turns, k): AbstractPlayer.__init__(self, setup_time, player_color, time_per_k_turns, k) self.clock = time.time() # We are simply providing (remaining time / remaining turns) for each turn in round. # Taking a spare time of 0.05 seconds. self.turns_remaining_in_round = self.k self.time_remaining_in_round = self.time_per_k_turns self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05 self.simple = simplePlayer(setup_time, player_color, time_per_k_turns, k) self.algorithm = MiniMaxAlgorithm(utility=self.simple.utility, my_color=self.color, no_more_time=self.no_more_time, selective_deepening=self.selective_deeping) def __repr__(self): return '{} {}'.format(abstract.AbstractPlayer.__repr__(self), '- min_max_player') def no_more_time(self): time_passed = (time.time() - self.clock) self.clock = time.time() self.time_for_current_move -= time_passed self.time_remaining_in_round -= time_passed if self.time_for_current_move <= 0.05 or self.time_remaining_in_round <= 0.05: return True return False def time_for_step(self): return (self.split_time_equally(PERCENTAGE_OF_TIME_TO_SPLIT_EQUALLY * self.time_remaining_in_round) + \ self.split_time_not_equally(PERCENTAGE_OF_TIME_TO_SPLIT_NOT_EQUALLY * self.time_remaining_in_round))*0.97 def split_time_equally(self, time_remaining): return time_remaining/self.turns_remaining_in_round def split_time_not_equally(self, time_remaining): sum_of_remaining_turns = sum(range(self.turns_remaining_in_round + 1)) return time_remaining * (self.turns_remaining_in_round / sum_of_remaining_turns) def selective_deeping(self, state): sensitive_spots = [(0, 1), (1, 0), (1, 1), (0, 6), (1, 6), (1, 7), (6, 0), (6, 1), (7, 1), (7, 6), (6, 7), (6, 6)] corners = [(0, 0), (0, 7), (7, 0), (7, 7)] for move in state.get_possible_moves(): if move in sensitive_spots: return True if move in corners: return True return False def get_move(self, game_state, possible_moves): depth = 0 self.time_for_current_move = self.time_for_step() self.clock = time.time() best_move = None max_value = 0 searched_all_tree = False while not self.no_more_time() and not searched_all_tree: depth += 1 [value, move, searched_all_tree] = self.algorithm.search(game_state, depth, True) if best_move is None or value > max_value: max_value = value best_move = move if searched_all_tree: break 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 return best_move if best_move is not None else possible_moves[0]
class Player(abstract.AbstractPlayer): def __init__(self, setup_time, player_color, time_per_k_turns, k): abstract.AbstractPlayer.__init__(self, setup_time, player_color, \ time_per_k_turns, k) self.clock = time.time() # We are simply providing (remaining time / remaining turns) for each \ # turn in round. # Taking a spare time of 0.05 seconds. self.turns_remaining_in_round = self.k self.time_remaining_in_round = self.time_per_k_turns self.time_for_current_move = self.time_remaining_in_round / \ self.turns_remaining_in_round - 0.05 # chose get_move function according to time_per_k_turns: # time_per_k_turns < 3 --> get_move_min_max # time_per_k_turns > 3 --> get_move_alpha_beta if time_per_k_turns < 3: self.get_move_chosen = self.get_move_min_max self.min_max_algorithm = MiniMaxAlgorithm(self.utility, \ self.color, self.no_more_time, None) else: self.get_move_chosen = self.get_move_alpha_beta self.alpha_beta_algorithm = MiniMaxWithAlphaBetaPruning(self.utility, \ self.color, self.no_more_time, None) # keep the game-moves as a string self.moves = '' self.last_state = GameState() # chose board configuration if self.color == O_PLAYER: # will be set after opponent first move self.book2reality = None self.reality2book = None else: self.book2reality = self.book2reality1 self.reality2book = self.reality2book1 # for performence self.max_steps_left = 62 # create opening book opening_book = {} f = open("best_70_opens.gam", 'r') # FIXME: remove error check before submmision if not f: print("cannot open file") sys.exit(1) # assume we play first and update otherwise first_move_index = 0 if self.color == O_PLAYER: first_move_index = 1 for line in f: tmp = line.split(' ')[1] tmp = re.split(r'[+-]', tmp) moves = ''.join(tmp) for i in range(first_move_index, 10, 2): tmp = re.split('r[+-]', moves) key = moves[0:2 * i] if key not in opening_book: opening_book[key] = moves[2 * i:2 * i + 2] f.close() self.opening_book = opening_book def get_move(self, game_state, possible_moves): self.clock = time.time() self.time_for_current_move = self.time_remaining_in_round / \ self.turns_remaining_in_round - 0.05 self.max_steps_left -= 2 # discover last move done by opponent opponent_move_str_format = '' for x in range(BOARD_COLS): for y in range(BOARD_ROWS): if self.last_state.board[x][ y] == EM and game_state.board[x][y] != EM: opponent_move_str_format = TO_LETTER[str(x + 1)] + str(y + 1) # chose the board_configuration - firs opponent move became 'd3' in # oppening book if self.book2reality == None: if opponent_move_str_format == 'd6': self.book2reality = self.book2reality1 self.reality2book = self.reality2book1 elif opponent_move_str_format == 'e3': self.book2reality = self.book2reality2 self.reality2book = self.reality2book2 elif opponent_move_str_format == 'c5': self.book2reality = self.book2reality3 self.reality2book = self.reality2book3 elif opponent_move_str_format == 'f4': self.book2reality = self.book2reality4 self.reality2book = self.reality2book4 else: raise ImpossibleBoardTransform # append opponent move to self.moves - this will represent the key. # if we play first we will append '' to '' (nothing will hapen) self.moves += self.reality2book(opponent_move_str_format) # this case is handled in run_game.py assert (len(possible_moves) != 0) best_move = self.get_move_chosen(game_state, possible_moves) to_be_append = TO_LETTER[str(best_move[0] + 1)] + str(best_move[1] + 1) self.moves += self.reality2book(to_be_append) 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.time() - self.clock) return best_move def get_move_alpha_beta(self, game_state, possible_moves): # find the best move if len(possible_moves) == 1: best_move = possible_moves[0] else: # check if next move can be determined from oppening book oppening_book_res = self.opening_move() if oppening_book_res != None: best_move = oppening_book_res else: curr_depth = 1 # there is maximum max_steps_left steps in the game last_move = None while curr_depth < self.max_steps_left: try: _, best_move = self.alpha_beta_algorithm.search( \ game_state, curr_depth, -INFINITY*2, INFINITY*2, True) if last_move != best_move: game_state_copy = copy.deepcopy(game_state) game_state_copy.perform_move( best_move[0], best_move[1]) self.last_state = game_state_copy last_move = best_move curr_depth += 1 except ExceededTimeError: break return best_move def get_move_min_max(self, game_state, possible_moves): # find the best move if len(possible_moves) == 1: best_move = possible_moves[0] else: # check if next move can be determined from oppening book oppening_book_res = self.opening_move() if oppening_book_res != None: best_move = oppening_book_res else: curr_depth = 1 # there is maximum max_steps_left steps in the game last_move = None while curr_depth < self.max_steps_left: try: _, best_move = self.min_max_algorithm.search( \ game_state, curr_depth, True) if last_move != best_move: game_state_copy = copy.deepcopy(game_state) game_state_copy.perform_move( best_move[0], best_move[1]) self.last_state = game_state_copy last_move = best_move curr_depth += 1 except ExceededTimeError: break return best_move def opening_move(self): # check if we can find the next move in the oppening book if self.moves not in self.opening_book: return None res = self.book2reality(self.opening_book[self.moves]) return [int(TO_DIGIT[res[0]]) - 1, int(res[1]) - 1] def book2reality1(self, str_move): old_digit = str_move[1] old_letter = str_move[0] new_digit = str(BOARD_ROWS - int(old_digit) + 1) new_letter = old_letter return new_letter + new_digit def reality2book1(self, str_move): if str_move == '': return '' return self.book2reality1(str_move) def book2reality2(self, str_move): old_digit = str_move[1] old_letter = str_move[0] new_digit = old_digit new_letter = REVERSE_LETTER[old_letter] return new_letter + new_digit def reality2book2(self, str_move): if str_move == '': return '' return self.book2reality2(str_move) def book2reality3(self, str_move): old_digit = str_move[1] old_letter = str_move[0] new_digit = TO_LETTER[old_digit] new_letter = TO_DIGIT[REVERSE_LETTER[old_letter]] return new_digit + new_letter def reality2book3(self, str_move): if str_move == '': return '' return self.book2reality4(str_move) def book2reality4(self, str_move): old_digit = str_move[1] old_letter = str_move[0] new_digit = REVERSE_LETTER[TO_LETTER[old_digit]] new_letter = TO_DIGIT[old_letter] return new_digit + new_letter def reality2book4(self, str_move): if str_move == '': return '' return self.book2reality3(str_move) #------------------------------------------------------------------------------ def __is_stable(self, state, J, I): # a corner is always stable if (I == 0 or I == BOARD_ROWS) and (J == 0 or J == BOARD_COLS): return True elif I == 0 or I == BOARD_ROWS - 1: res1 = True res2 = True for j in range(J): if state.board[j][I] == OPPONENT_COLOR[self.color]: res1 = False break for j in range(J, BOARD_COLS): if state.board[j][I] == OPPONENT_COLOR[self.color]: res2 = False break return res1 or res2 elif J == 0 or J == BOARD_COLS - 1: res1 = True res2 = True for i in range(I): if state.board[J][i] == OPPONENT_COLOR[self.color]: res1 = False break for i in range(I, BOARD_ROWS): if state.board[J][i] == OPPONENT_COLOR[self.color]: res2 = False break return res1 or res2 # don't let this method be applied on a non-edge index else: raise NonEdgeIndex def __score_utility(self, state): CORNER_FAC = 100 STABLE_EDGE_FAC = 20 EDGE_FAC = 5 INTER_FAC = 1 my_u = 0 op_u = 0 for x in range(BOARD_COLS): for y in range(BOARD_ROWS): # is a corner if (x == 0 or x == BOARD_COLS - 1) and (y == 0 or y == BOARD_ROWS - 1): if state.board[x][y] == self.color: my_u += CORNER_FAC elif state.board[x][y] == OPPONENT_COLOR[self.color]: op_u += CORNER_FAC # is an edge elif x == 0 or x == BOARD_COLS - 1 or y == 0 or y == BOARD_ROWS - 1: # is stable if self.__is_stable(state, x, y): if state.board[x][y] == self.color: my_u += STABLE_EDGE_FAC elif state.board[x][y] == OPPONENT_COLOR[self.color]: op_u += STABLE_EDGE_FAC # is not stable else: if state.board[x][y] == self.color: my_u += EDGE_FAC elif state.board[x][y] == OPPONENT_COLOR[self.color]: op_u -= EDGE_FAC # is internal else: if state.board[x][y] == self.color: my_u += INTER_FAC elif state.board[x][y] == OPPONENT_COLOR[self.color]: op_u -= INTER_FAC if my_u == 0: # I have no tools left return -INFINITY elif op_u == 0: # The opponent has no tools left return INFINITY else: return my_u - op_u def __mobility_utility(self, state): MOBILITY_FAC = 1 # when this function is called the current player is already the # opponent so we will change it to our player, check the value and # return it as it was op_moves = len(state.get_possible_moves()) state.curr_player = OPPONENT_COLOR[state.curr_player] my_moves = len(state.get_possible_moves()) state.curr_player = OPPONENT_COLOR[state.curr_player] return (my_moves - op_moves) * MOBILITY_FAC def utility(self, state): assert (len(state.get_possible_moves()) != 0) mobility_fac = 1 score_fac = 1 mobility_res = self.__mobility_utility(state) score_res = self.__score_utility(state) return mobility_res * mobility_fac + score_res * score_fac #------------------------------------------------------------------------------ def selective_deepening_criterion(self, state): # Simple player does not selectively deepen into certain nodes. return False def no_more_time(self): return (time.time() - self.clock) >= self.time_for_current_move def __repr__(self): return '{} {}'.format(abstract.AbstractPlayer.__repr__(self), 'competition')
root2.left.set_left(5) root2.left.set_right(4) root2.right.set_left(7) root2.right.set_right(6) root2.left.left.set_left(9) root2.left.left.set_right(8) root2.left.right.set_left(11) root2.left.right.set_right(10) root2.right.left.set_left(13) root2.right.left.set_right(12) root2.right.right.set_left(15) root2.right.right.set_right(14) # chek min-max without time consideration mma = MiniMaxAlgorithm(utility, 'X', no_more_time, None) res1 = mma.search(root, 10, True) res2 = mma.search(root, 10, False) res3 = mma.search(root, 2, True) res4 = mma.search(root, 2, False) asssert(res1[0] == 13) asssert(res2[0] == 10) asssert(res3[0] == 6) asssert(res4[0] == 5) res1 = mma.search(root2, 10, True) res2 = mma.search(root2, 10, False) res3 = mma.search(root2, 2, True) res4 = mma.search(root2, 2, False) asssert(res1[0] == 13)
class Player(abstract.AbstractPlayer): def __init__(self, setup_time, player_color, time_per_k_turns, k): abstract.AbstractPlayer.__init__(self, setup_time, player_color, \ time_per_k_turns, k) self.clock = time.time() # We are simply providing (remaining time / remaining turns) for each \ # turn in round. # Taking a spare time of 0.05 seconds. self.turns_remaining_in_round = self.k self.time_remaining_in_round = self.time_per_k_turns self.time_for_current_move = self.time_remaining_in_round / \ self.turns_remaining_in_round - 0.05 self.min_max_algorithm = MiniMaxAlgorithm(self.utility, \ self.color, self.no_more_time, None) # for performence self.max_steps_left = 62 def get_move(self, game_state, possible_moves): self.clock = time.time() self.time_for_current_move = self.time_remaining_in_round / \ self.turns_remaining_in_round - 0.05 self.max_steps_left -= 2 if len(possible_moves) == 1: best_move = possible_moves[0] else: curr_depth = 1 # there is maximum max_steps_left steps in the game while curr_depth < self.max_steps_left: try: _, best_move = self.min_max_algorithm.search( \ game_state, curr_depth, True) curr_depth += 1 except ExceededTimeError: break 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.time() - self.clock) return best_move def utility(self, state): if len(state.get_possible_moves()) == 0: return INFINITY if state.curr_player != self.color else -INFINITY my_u = 0 op_u = 0 for x in range(BOARD_COLS): for y in range(BOARD_ROWS): if state.board[x][y] == self.color: my_u += 1 if state.board[x][y] == OPPONENT_COLOR[self.color]: op_u += 1 if my_u == 0: # I have no tools left return -INFINITY elif op_u == 0: # The opponent has no tools left return INFINITY else: return my_u - op_u def selective_deepening_criterion(self, state): # Simple player does not selectively deepen into certain nodes. return False def no_more_time(self): return (time.time() - self.clock) >= self.time_for_current_move def __repr__(self): return '{} {}'.format(abstract.AbstractPlayer.__repr__(self), 'min_max')