Beispiel #1
0
def pieces_threatened(game_state, player):
    other = game.other_player(player)

    home_b = count_pieces(game_state[player])
    pieces = 0

    for enemy in game_state[other]:
        xy = enemy[1], enemy[2]

        for move in tokens.available_moves(other):
            if move == "Boom":
                continue
            for dist in range(enemy[0]):
                dist = enemy[0] - dist
                xy2 = game.dir_to_xy(xy, move, dist)
                temp_game = game.Game(game_state)

                if tokens.out_of_board(
                        xy2) or not temp_game.board.is_cell_empty(xy2):
                    continue

                temp_game.move_token(1, xy, move, dist, other)
                temp_game.boom(xy2, other)
                home_a = count_pieces(temp_game.get_game_state()[player])

                pieces += home_b - home_a

    return pieces
Beispiel #2
0
    def action(self):
        """
        This method is called at the beginning of each of your turns to request 
        a choice of action from your program.

        Based on the current state of the game, your player should select and 
        return an allowed action to play on this turn. The action must be
        represented based on the spec's instructions for representing actions.
        """
        # TODO: Decide what action to take, and return it

        self.past_states.append(self.game_state[self.colour])

        self.home_tokens = sum([x[0] for x in self.game_state[self.colour]])
        self.away_tokens = sum(
            [x[0] for x in self.game_state[game.other_player(self.colour)]])

        simulations = 14 * len(self.game_state[self.colour])
        search_depth = 3

        action = None

        if self.opening_book.check_early_game():
            action = self.opening_book.next_move()
            if action:
                return action

        if self.away_tokens == 1 and self.home_tokens >= 1:
            strategy = self.agent.one_enemy_endgame(self.game_state,
                                                    simulations, search_depth,
                                                    1)
        elif self.away_tokens == 2 and self.home_tokens >= 2:
            strategy = self.agent.two_enemy_endgame(self.game_state,
                                                    simulations, search_depth,
                                                    1)
        elif self.away_tokens <= self.trading_prop and self.away_tokens < self.home_tokens:
            strategy = self.agent.trade_tokens(self.game_state, simulations,
                                               search_depth, 1)
        else:
            strategy = self.agent.monte_carlo(self.game_state, simulations,
                                              search_depth)

        n, xy, move, distance = strategy
        if move == "Boom":

            return "BOOM", xy

        else:
            x_a, y_a = xy
            x_b, y_b = game.dir_to_xy(xy, move, distance)

            return "MOVE", n, (x_a, y_a), (x_b, y_b)
Beispiel #3
0
    def two_enemy_endgame(self, game_state, simulations, search_depth,
                          trade_threshold):
        enemy_stacks = len(game_state[self.other])

        # Check if enemy can kill us or draw
        for piece in game_state[self.other]:
            temp_game = game.Game(game_state)
            temp_game.boom((piece[1], piece[2]), self.other)
            home_a = features.count_pieces(
                temp_game.get_game_state()[self.player])
            away_a = features.count_pieces(
                temp_game.get_game_state()[self.other])

            if not temp_game.get_game_state()[
                    self.player] or home_a - away_a < trade_threshold:
                strategy = self.monte_carlo(game_state, simulations,
                                            search_depth)
                return strategy

        # One stack
        if enemy_stacks == 1:
            enemy = game_state[self.other][0]
            enemy_xy = enemy[1], enemy[2]

            for piece in game_state[self.player]:
                temp_game = game.Game(game_state)
                temp_game.boom((piece[1], piece[2]), self.player)

                if temp_game.get_game_state(
                )[self.player] and not temp_game.get_game_state()[self.other]:
                    return None, (piece[1], piece[2]), "Boom", None

            ally = self.closest_npiece(game_state, 2, self.player, enemy_xy)
            if ally is None:
                return self.make_stack(game_state)

            ally_xy = ally[1], ally[2]

            width = enemy_xy[0] - ally_xy[0]
            height = enemy_xy[1] - ally_xy[1]

            if width == 0 and abs(height) <= ally[0]:
                return self.go_there(
                    2, ally, (enemy_xy[0], enemy_xy[1] - np.sign(height)))
            if height == 0 and abs(width) <= ally[0]:
                return self.go_there(
                    2, ally, (enemy_xy[0] - np.sign(width), enemy_xy[1]))

            enemy_corner_xy = self.get_nearest_corner(ally_xy, enemy_xy)
            move = self.go_there(2, ally, enemy_corner_xy)

            if tokens.is_valid_move(self.game.board, move[1],
                                    game.dir_to_xy(move[1], move[2], move[3])):
                return move
            else:
                return self.monte_carlo(game_state, simulations, search_depth)

        # Two seperate stacks
        else:
            return self.trade_tokens(game_state, simulations, search_depth,
                                     trade_threshold)
Beispiel #4
0
    def available_states(self, game_state, player):
        available = []
        all_available = []

        home_b, away_b = features.count_all(game_state, player)

        for piece in game_state[player]:
            xy = piece[1], piece[2]
            available_moves = tokens.available_moves(player)

            for move in available_moves:
                if move == "Boom":
                    temp_game = game.Game(game_state)

                    if not temp_game.has_surrounding(xy):
                        continue

                    temp_game.boom(xy, player)
                    temp_game_state = temp_game.get_game_state()

                    all_available.append([(None, xy, move, None),
                                          temp_game_state])

                    home_a, away_a = features.count_all(
                        temp_game_state, player)

                    # If suicide for nothing
                    if away_a == away_b or self.is_bad_boom(
                            game_state, temp_game_state, player):
                        continue

                    available.append([(None, xy, move, None),
                                      temp_game.get_game_state()])

                else:
                    if piece[0] == 1:
                        amounts = [1]
                    elif piece[0] == 2:
                        amounts = [1, 2]
                    else:
                        amount = min(piece[0], 8)
                        # Move whole stack or leave one or move one
                        amounts = [1, amount, amount - 1]

                    for n in amounts:
                        for distance in range(piece[0]):
                            distance = piece[0] - distance
                            temp_game = game.Game(game_state)
                            if temp_game.is_valid_move(xy, move, distance,
                                                       player):
                                temp_game.move_token(n, xy, move, distance,
                                                     player)
                                xy2 = game.dir_to_xy(xy, move, distance)

                                # Don't break stack if not moving to attack
                                if piece[
                                        0] != 1 and n == 1 and not self.has_potential_threat(
                                            xy2, self.other):
                                    continue

                                if not self.has_potential_threat(
                                        xy, self.other):
                                    #  Don't break stack if not running away and leaving
                                    if piece[0] > 2 and n == piece[0] - 1:
                                        continue

                                    # We don't like a v pattern (inefficient move)
                                    if self.creates_v(temp_game, xy2):
                                        continue
                                    if move in [
                                            "Up", "Down"
                                    ] and (self.creates_v(
                                            temp_game,
                                        (xy[0] + 1, xy[1])) or self.creates_v(
                                            temp_game, (xy[0] - 1, xy[1]))):
                                        continue
                                    if move in [
                                            "Left", "Right"
                                    ] and (self.creates_v(
                                            temp_game,
                                        (xy[0], xy[1] + 1)) or self.creates_v(
                                            temp_game, (xy[0], xy[1] - 1))):
                                        continue

                                available.append([(n, xy, move, distance),
                                                  temp_game.get_game_state()])

        if player != self.player or len(available) == 0:
            return all_available

        return available
Beispiel #5
0
    def best_child(self, root, all_simulated=True):
        from math import sqrt

        game_state = root.data
        uct_sim = float("-inf")

        can_boom = False
        best_boom_diff = float("-inf")
        best_strategy = None
        best_boom = None
        potential_threat = False
        run_aways = []
        offensive = []

        home_c = features.count_pieces(game_state[self.player])
        away_c = features.count_pieces(game_state[self.other])
        diff_c = self.value_diff(game_state, self.player)

        potential_threat1 = self.has_potential_threat(
            self.away_recently_moved_to, self.player)
        potential_threat2 = self.has_potential_threat(
            self.away_recently_moved_from, self.player)

        # If there is a threat
        if potential_threat1 and potential_threat2:
            potential_threat = True

            temp_game1 = game.Game(game_state)
            temp_game1.boom(self.away_recently_moved_to, self.other)
            temp_game_state1 = temp_game1.get_game_state()
            potential_diff1 = self.value_diff(temp_game_state1, self.player)

            temp_game2 = game.Game(game_state)
            temp_game2.boom(self.away_recently_moved_from, self.other)
            temp_game_state2 = temp_game2.get_game_state()
            potential_diff2 = self.value_diff(temp_game_state2, self.player)

            potential_diff = min(potential_diff1, potential_diff2)
            if potential_diff1 <= potential_diff2:
                away_recently_moved = self.away_recently_moved_to
                # If is bad boom for the other player
                if potential_diff1 >= diff_c or self.is_bad_boom(
                        game_state, temp_game_state1, self.other):
                    potential_threat = False
            else:
                away_recently_moved = self.away_recently_moved_from
                # If is bad boom for the other player
                if potential_diff2 >= diff_c or self.is_bad_boom(
                        game_state, temp_game_state2, self.other):
                    potential_threat = False
        else:
            if potential_threat1:
                potential_threat = True
                away_recently_moved = self.away_recently_moved_to

                temp_game = game.Game(game_state)
                temp_game.boom(away_recently_moved, self.other)
                temp_game_state = temp_game.get_game_state()
                potential_diff = self.value_diff(temp_game_state, self.player)

                if potential_diff >= diff_c or self.is_bad_boom(
                        game_state, temp_game_state, self.other):
                    potential_threat = False

            if potential_threat2:
                potential_threat = True
                away_recently_moved = self.away_recently_moved_from

                temp_game = game.Game(game_state)
                temp_game.boom(away_recently_moved, self.other)
                temp_game_state = temp_game.get_game_state()
                potential_diff = self.value_diff(temp_game_state, self.player)

                if potential_diff >= diff_c or self.is_bad_boom(
                        game_state, temp_game_state, self.other):
                    potential_threat = False

        for child in root.seen:
            strategy = child.move
            next_state = child.data

            if next_state[self.player] in self.past_states:
                continue

            # If won
            if not next_state[self.other] and next_state[self.player]:
                return strategy

            if strategy[2] != "Boom":
                xy = game.dir_to_xy(xy=strategy[1],
                                    direction=strategy[2],
                                    distance=strategy[3])

                damage = sqrt(features.pieces_per_boom(next_state, self.other))
                if damage == features.count_pieces(next_state[self.player]):
                    continue

                # If no threat and can go on the offensive
                if not potential_threat and self.has_potential_threat(
                        xy, self.other):
                    temp_game = game.Game(next_state)
                    temp_game.boom(xy, self.player)
                    temp_game_state = temp_game.get_game_state()

                    if self.is_bad_boom(next_state, temp_game_state,
                                        self.player):
                        continue

                    offensive.append(
                        (self.value_diff(temp_game_state,
                                         self.player), child.uct, strategy))

                # React to threat
                if potential_threat:
                    # Losses from moving
                    temp_game = game.Game(next_state)
                    temp_game.boom(away_recently_moved, self.other)
                    temp_game_state = temp_game.get_game_state()
                    loss = self.value_diff(temp_game_state, self.player)

                    if self.has_potential_threat(xy, self.other):
                        # Potential gains from moving
                        temp_game = game.Game(next_state)
                        temp_game.boom(xy, self.player)
                        temp_game_state = temp_game.get_game_state()
                        gain = self.value_diff(temp_game_state, self.player)

                        # Same Cluster boomed or Moving to trade is not worth it
                        if gain > loss:
                            trade_game = temp_game
                            trade_game.boom(away_recently_moved, self.other)
                            trade_game_state = trade_game.get_game_state()
                            outcome = self.value_diff(trade_game_state,
                                                      self.player)

                            # Minimise Losses by trading
                            run_aways.append((outcome, child.uct, strategy))

                    else:
                        # Minimise Losses by Running
                        if loss > potential_diff:
                            run_aways.append((loss, child.uct, strategy))
                        else:
                            continue

            # If can trade for more
            if strategy[2] == "Boom":

                temp_game = game.Game(next_state)

                # React to threat
                if potential_threat and not temp_game.board.is_cell_empty(
                        away_recently_moved):
                    temp_game.boom(away_recently_moved, self.other)
                    temp_game_state = temp_game.get_game_state()
                else:
                    temp_game_state = temp_game.get_game_state()
                    if self.is_bad_boom(game_state, temp_game_state,
                                        self.player):
                        continue

                diff = self.value_diff(temp_game_state, self.player)

                if diff > best_boom_diff and \
                        ((home_c < away_c and diff > diff_c) or (home_c >= away_c and diff >= diff_c)):
                    best_boom_diff = diff
                    best_boom = strategy
                    can_boom = True

            # Chose best child
            if child.uct > uct_sim:
                uct_sim = child.uct
                best_strategy = strategy

        if potential_threat:

            best_move = None
            best_move_diff = float("-inf")

            # Run away
            if len(run_aways) != 0:
                run_aways = sorted(run_aways, reverse=True)
                best_move = run_aways[0][2]
                best_move_diff = run_aways[0][0]

            if best_boom_diff >= best_move_diff:
                # Trade first
                if best_boom_diff > potential_diff and can_boom:
                    return best_boom
            else:
                # Run away or Run away to Trade
                if best_move is not None and best_move_diff > potential_diff:
                    return best_move

        if can_boom:
            return best_boom

        if len(offensive) != 0:
            offensive = sorted(offensive, reverse=True)
            return offensive[0][2]

        if not all_simulated:
            return None

        # If nothing is good
        if best_strategy is None:
            return self.random_valid_move(game_state, self.player)[0]

        return best_strategy