def get_move(self, game_state, possible_moves): self.clock = time.clock() if len(possible_moves) == 1: return 0 current_depth = 1 prev_alpha = -INFINITY # Choosing an arbitrary move: best_move = possible_moves[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_per_move - (time.clock() - self.clock), prev_alpha, best_move)) minimax = MiniMaxWithAlphaBetaPruning(self.utility, self.color, self.no_more_time) alpha, move = minimax.search(game_state, current_depth, -INFINITY, INFINITY, True) 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 current_depth += 1 return possible_moves.index(best_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: 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 = MiniMaxWithAlphaBetaPruning(self.utility, self.color, self.no_more_time, None) depth = 1 while self.no_more_time() is False: min_max_val = min_max.search(game_state, depth, -INFINITY, INFINITY, True)[1] best_move = min_max_val if min_max_val is not None else best_move 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): alpha_beta = MiniMaxWithAlphaBetaPruning(self.utility, self.color, self.no_more_time, False) depth = 1 optimal_move = None while True: _, move = alpha_beta.search(state, depth, -INFINITY, INFINITY, True) if move is None: break optimal_move = move depth += 1 return optimal_move
def get_move(self, game_state, possible_moves): if len(possible_moves) == 1: return possible_moves[0] self.clock = time.time() self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - self.time_per_k_turns * 0.05 minimaxObject = MiniMaxWithAlphaBetaPruning( self.utility, self.color, self.no_more_time, self.selective_deepening_criterion) D = 1 (value, move) = (0, possible_moves[0]) while not self.no_more_time(): (value, move1) = minimaxObject.search(game_state, D, -INFINITY, INFINITY, True) if not self.no_more_time(): move = move1 D = D + 1 return 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: 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 = MiniMaxWithAlphaBetaPruning( self.utility, self.color, self.no_more_time, self.selective_deepening_criterion) i = 1 alpha = -INFINITY max = -INFINITY # print("search time is ", self.time_for_current_move) # start_time = time.time() depth = 0 while not self.no_more_time(): # print("clock ", time.time() - start_time) curr_best_util, curr_best_move = min_max.search( game_state, i, alpha, INFINITY, True) depth += 1 if curr_best_util > best_util: best_move = curr_best_move best_util = curr_best_util if curr_best_util > max: alpha = curr_best_util max = curr_best_util i += 1 # print("clock ", time.time() - start_time) 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("alpha_beta depth : ",depth) return best_move
def get_move(self, board_state, possible_moves): self.clock = time.process_time() self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round -0.5 if len(possible_moves) == 1: return possible_moves[0] current_depth = 1 prev_alpha = -INFINITY # Choosing an arbitrary move: best_move = possible_moves[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)) minimax = MiniMaxWithAlphaBetaPruning(self.utility, self.color, self.no_more_time) alpha, move = minimax.search(board_state, current_depth, -INFINITY, INFINITY, True) 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 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
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() 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.algorithm = MiniMaxWithAlphaBetaPruning( utility=self.utility, my_color=self.color, no_more_time=self.no_more_time, selective_deepening=self.selective_deeping) self.opening_book = create_better_opening_book(b_create_file=False) self.last_board = [] for i in range(BOARD_COLS): self.last_board.append([EM] * BOARD_ROWS) for x in range(BOARD_COLS): for y in range(BOARD_ROWS): self.last_board[x][y] = EM # Starting pieces: self.last_board[3][3] = X_PLAYER self.last_board[3][4] = O_PLAYER self.last_board[4][3] = O_PLAYER self.last_board[4][4] = X_PLAYER self.moves = "" def __repr__(self): return '{} {}'.format(abstract.AbstractPlayer.__repr__(self), '- competition_player') def no_more_time(self): time_passed = (time.time() - self.clock) self.time_for_current_move -= time_passed self.time_remaining_in_round -= time_passed self.clock = time.time() 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 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 reached_leaves = False while not self.no_more_time() and not reached_leaves: depth += 1 [value, move, reached_leaves] = self.algorithm.search(game_state, depth, -INFINITY, INFINITY, True) if best_move is None or value > max_value: max_value = value best_move = move 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] def find_opposite_move(self, game_state): for i in range(BOARD_COLS): for j in range(BOARD_ROWS): if self.last_board[i][j] == EM and game_state.board[i][j] != EM: return i, j return None def opening_move(self, game_state): if len(self.moves) / 2 > NUM_OF_MOVES_IN_OPENING_BOOK: return None other_player_move = self.find_opposite_move(game_state) if other_player_move is None: other_player_move_as_str = "" else: other_player_move_as_str = xy_to_a1(other_player_move) self.moves += other_player_move_as_str return a1_to_xy(self.opening_book[ self.moves]) if self.moves in self.opening_book else None 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 utility(self, state): if len(state.get_possible_moves()) == 0: winner = state.get_winner() if winner == self.color: return INFINITY elif winner == TIE: return 0 else: return -INFINITY my_in_corner = 0 opp_in_corner = 0 my_front = 0 opp_front = 0 my = 0 opp = 0 d = 0 my_close_to_corner = 0 opp_close_to_corner = 0 opp_state = copy.deepcopy(state) X = [-1, -1, 0, 1, 1, 1, 0, -1] Y = [0, 1, 1, 1, 0, -1, -1, -1] piece_diff = [[0] * BOARD_ROWS] * BOARD_COLS piece_diff[0] = [20, -3, 11, 8, 8, 11, -3, 20] piece_diff[1] = [-3, -7, -4, 1, 1, -4, -7, -3] piece_diff[2] = [11, -4, 2, 2, 2, 2, -4, 11] piece_diff[3] = [8, 1, 2, -3, -3, 2, 1, 8] piece_diff[4] = [8, 1, 2, -3, -3, 2, 1, 8] piece_diff[5] = [11, -4, 2, 2, 2, 2, -4, 11] piece_diff[6] = [-3, -7, -4, 1, 1, -4, -7, -3] piece_diff[7] = [20, -3, 11, 8, 8, 11, -3, 20] if state.curr_player == X_PLAYER: opp_state.curr_player = O_PLAYER else: opp_state.curr_player = X_PLAYER grid = state.board for x in range(BOARD_COLS): for y in range(BOARD_ROWS): if grid[x][y] == self.color: my += 1 d += piece_diff[x][y] elif grid[x][y] == OPPONENT_COLOR[self.color]: opp += 1 d -= piece_diff[x][y] if grid[x][y] != ' ': for k in range(BOARD_ROWS): i = x + X[k] j = y + Y[k] if i >= 0 and i < BOARD_ROWS and j >= 0 and j < BOARD_ROWS and grid[ i][j] == EM: if grid[x][y] == self.color: my_front += 1 elif grid[x][y] == OPPONENT_COLOR[self.color]: opp_front += 1 break if my_front > opp_front: front = -(100.0 * my_front) / (my_front + opp_front) elif my_front < opp_front: front = (100.0 * opp_front) / (my_front + opp_front) else: front = 0 if my > opp: tiles = (100.0 * my) / (my + opp) elif my < opp: tiles = -(100.0 * opp) / (my + opp) else: tiles = 0 if grid[0][0] == self.color: my_in_corner += 1 elif grid[0][0] == OPPONENT_COLOR[self.color]: opp_in_corner += 1 if grid[0][BOARD_ROWS - 1] == self.color: my_in_corner += 1 elif grid[0][BOARD_ROWS - 1] == OPPONENT_COLOR[self.color]: opp_in_corner += 1 if grid[BOARD_COLS - 1][0] == self.color: my_in_corner += 1 elif grid[BOARD_COLS - 1][0] == OPPONENT_COLOR[self.color]: opp_in_corner += 1 if grid[BOARD_COLS - 1][BOARD_ROWS - 1] == self.color: my_in_corner += 1 elif grid[BOARD_COLS - 1][BOARD_ROWS - 1] == OPPONENT_COLOR[self.color]: opp_in_corner += 1 corners = 25 * (my_in_corner - opp_in_corner) my_options = len(state.get_possible_moves()) opp_options = len(opp_state.get_possible_moves()) if my_options > opp_options: options = (100.0 * my_options) / (my_options + opp_options) elif opp_options > my_options: options = -(100.0 * opp_options) / (my_options + opp_options) else: options = 0 if grid[0][0] == EM: if grid[0][1] == self.color: my_close_to_corner += 1 elif grid[0][1] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[1][1] == self.color: my_close_to_corner += 1 elif grid[1][1] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[1][0] == self.color: my_close_to_corner += 1 elif grid[1][0] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[0][BOARD_COLS - 1] == EM: if grid[0][BOARD_COLS - 2] == self.color: my_close_to_corner += 1 elif grid[0][BOARD_COLS - 2] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[1][BOARD_COLS - 2] == self.color: my_close_to_corner += 1 elif grid[1][BOARD_COLS - 2] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[1][BOARD_COLS - 1] == self.color: my_close_to_corner += 1 elif grid[1][BOARD_COLS - 1] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[BOARD_ROWS - 1][0] == EM: if grid[BOARD_ROWS - 1][1] == self.color: my_close_to_corner += 1 elif grid[BOARD_ROWS - 1][1] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[BOARD_ROWS - 2][1] == self.color: my_close_to_corner += 1 elif grid[BOARD_ROWS - 2][1] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[BOARD_ROWS - 2][0] == self.color: my_close_to_corner += 1 elif grid[BOARD_ROWS - 2][0] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[BOARD_ROWS - 1][BOARD_COLS - 1] == EM: if grid[BOARD_ROWS - 2][BOARD_COLS - 1] == self.color: my_close_to_corner += 1 elif grid[BOARD_ROWS - 2][BOARD_COLS - 1] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[BOARD_ROWS - 2][BOARD_COLS - 2] == self.color: my_close_to_corner += 1 elif grid[BOARD_ROWS - 2][BOARD_COLS - 2] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 if grid[BOARD_ROWS - 1][BOARD_COLS - 2] == self.color: my_close_to_corner += 1 elif grid[BOARD_ROWS - 1][BOARD_COLS - 2] == OPPONENT_COLOR[self.color]: opp_close_to_corner += 1 close_to_corner = -12.5 * (my_close_to_corner - opp_close_to_corner) return (10 * tiles) + (801.724 * corners) + (382.026 * close_to_corner) + (78.922 * options) + (74.396 * front) \ + (10 * d)
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 # 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 self.alpha_beta_algorithm = MiniMaxWithAlphaBetaPruning(self.utility, \ self.color, self.no_more_time, None) # 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) # 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 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 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), 'old_competition')
asssert(res5[0] == 13) asssert(res6[0] == 10) no_more_time2.time = 38 res5 = mma.search(root2, 10, True) no_more_time2.time = 38 res6 = mma.search(root2, 10, False) asssert(res5[0] == 13) asssert(res6[0] == 10) # check alpha betta abp = MiniMaxWithAlphaBetaPruning(utility, 'X', no_more_time2, None) no_more_time2.time = 38 res7 = abp.search(root, 10, -INFINITY, INFINITY, True) no_more_time2.time = 38 res8 = abp.search(root, 10, -INFINITY, INFINITY, False) no_more_time2.time = 38 res9 = abp.search(root, 2, -INFINITY, INFINITY, True) no_more_time2.time = 38 res10 = abp.search(root, 2, -INFINITY, INFINITY, False) asssert(res7[0] == 13) asssert(res8[0] == 10) asssert(res9[0] == 6) asssert(res10[0] == 5)
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.alpha_beta_algorithm = MiniMaxWithAlphaBetaPruning(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.alpha_beta_algorithm.search( \ game_state, curr_depth, -INFINITY, INFINITY, 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), 'alpha_beta')
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 = MiniMaxWithAlphaBetaPruning( 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), '- alpha_beta_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 reached_leaves = False while not self.no_more_time() and not reached_leaves: depth += 1 [value, move, reached_leaves] = self.algorithm.search(game_state, depth, -INFINITY, INFINITY, True) if best_move is None or value > max_value: max_value = value best_move = move 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]