示例#1
0
    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
示例#2
0
    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)
示例#3
0
    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)
示例#4
0
    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 = ""
示例#5
0
    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
示例#6
0
    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
示例#7
0
    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
示例#8
0
 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
示例#9
0
    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
示例#10
0
    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
示例#11
0
    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)
示例#12
0
文件: __init__.py 项目: itaicaspi/AI
    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
示例#13
0
    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
        alphaBeta = MiniMaxWithAlphaBetaPruning(self.utilityBetter,
                                                player_color,
                                                self.no_more_time, False)
        self.search = alphaBeta.search

        # divide the board into 5 categories and score them from best to worst
        cells1Type = [2, 3, 4, 5]
        cells2TypeA = [1, 6]
        cells2TypeB = [2, 3, 4, 5]
        cells3TypeA = [0, 7]
        cells3TypeB = [2, 3, 4, 5]
        cells4Type = [0, 1, 6]
        cells5Type = [0, 7]
        # initiate the scoring matrix
        self.scoreMat = np.zeros((8, 8))
        for i in cells2TypeA:
            for j in cells2TypeB:
                self.scoreMat[i][j] = Player.SCORE_PERIMETER_BORDER
                self.scoreMat[j][i] = Player.SCORE_PERIMETER_BORDER
        for i in cells3TypeA:
            for j in cells3TypeB:
                self.scoreMat[i][j] = Player.SCORE_BORDER
                self.scoreMat[j][i] = Player.SCORE_BORDER
        for i in cells4Type:
            for j in cells4Type:
                self.scoreMat[i][j] = Player.SCORE_PERIMETER_CORNER
        for i in cells5Type:
            for j in cells5Type:
                self.scoreMat[i][j] = Player.SCORE_CORNER
示例#14
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
        # 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')
示例#15
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()
        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)
示例#16
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

        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')
示例#17
0
    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
示例#18
0
    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
res5 = mma.search(root, 10, True)
no_more_time2.time = 38
res6 = mma.search(root, 10, False)
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)
示例#20
0
    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
示例#21
0
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]