def get_relevant_food(my_snake: Snake, snakes: List[Snake],
                          all_food: List[Position], height: int,
                          width: int) -> List[Position]:
        my_head = my_snake.get_head()

        enemy_heads = [
            snake.get_head() for snake in snakes
            if snake.get_head() is not my_head
        ]
        my_close_food = []

        for food in all_food:

            if food.x == 0 or food.y == 0 or food.x == width - 1 or food.y == height - 1:
                enemy_dist_to_me = min([
                    Distance.manhattan_dist(head, my_head)
                    for head in enemy_heads
                ])
                enemy_dist_to_food = min([
                    Distance.manhattan_dist(head, food) for head in enemy_heads
                ])
                if len(all_food) > 5 and my_snake.health > 50:
                    continue
                if my_snake.health > 25 and enemy_dist_to_food < 2:
                    continue
                if my_snake.health > 70 and enemy_dist_to_food < 2 and enemy_dist_to_me < 2:
                    continue

            my_close_food.append(food)

        if not my_close_food:
            my_close_food = all_food

        return my_close_food
    def update_enemy_state(self, longest_snake: int) -> None:
        # get path to food or head that fits best the performed actions
        most_prob_food_path = 99999
        most_prob_head_path = 99999

        if self.move_profile_predictions["food"]:
            most_prob_food_path = min([
                Distance.path_similarity(f_profile, self.previous_positions)
                for f_profile in self.move_profile_predictions["food"]
            ])

        if self.move_profile_predictions["head"]:
            most_prob_head_path = min([
                Distance.path_similarity(h_profile, self.previous_positions)
                for h_profile in self.move_profile_predictions["head"]
            ])

        hungry = 0
        agressive = 0
        length_diff = self.length_history[0] - self.length_history[-1]
        head_dist_avg = sum(self.distance_to_enemy_heads) / len(
            self.distance_to_enemy_heads)

        # estimate correct state of Snake from assigning points to behaviour or snake_parameters
        if most_prob_food_path < most_prob_head_path:
            hungry += 1

        if most_prob_head_path < most_prob_food_path:
            agressive += 1

        if self.snake.health < 20:
            hungry += 1

        if self.snake.get_length() == longest_snake:
            agressive += 1

        if length_diff > 1:
            hungry += 1
        elif length_diff == 0:
            agressive += 1

        if self.state == States.AGRESSIVE:
            agressive += 1
        elif self.state == States.HUNGRY:
            hungry += 1

        if head_dist_avg < 4:
            agressive += 1
        elif head_dist_avg > 5:
            hungry += 1
Exemple #3
0
    def find_next_food(snake: Snake, board: BoardState) -> Optional[Tuple[int, Position]]:

        head = snake.get_head()
        health = snake.get_health()
        all_food = board.food
        if len(all_food) == 0:
            print("KEIN FOOD")
            return None
        best_dist = 99999
        best_food = None
        for food in all_food:
            food_dist = Distance.manhattan_dist(head, food)
            if food_dist > health:
                continue
            #print("food_dist: ",food_dist, "health", health)
            if food_dist == health:
            #    print("1: ", food_dist, food)
                return food_dist, food
            else:
                diff = (health - food_dist)
                #print("diff: ",diff)
                if (best_dist > diff) and diff > 0:
                    best_dist = diff
                    best_food = food
        #print("2: ", best_dist, best_food)
        return best_dist, best_food
Exemple #4
0
    def _update_automats(self, board: BoardState, kill_board: np.ndarray,
                         grid_map: GridMap) -> None:

        snake_heads = [snake.get_head() for snake in board.snakes]
        # longest_snake = max([snake.get_length() for snake in board.snakes])

        for index, snake in enumerate(board.snakes):
            automat = self.automats[snake.snake_id]

            automat.update_snake(snake)
            automat.add_position(snake.get_head())
            automat.monitor_dist_to_enemies(
                Distance.dist_to_closest_enemy_head(board.snakes, snake))
            automat.monitor_food(len(board.food))
            self.states[snake.snake_id] = self.automats[snake.snake_id].state

            if self.game_round % self.update_frequency == 0 and snake.snake_id != self.my_snake_id:
                automat.monitor_length(snake.get_length())

                enemy_snakes = board.snakes.copy()
                enemy_snakes.pop(index)

                enemy_heads = snake_heads.copy()
                enemy_heads.pop(index)

                if self.game_round != 0:
                    pass
                    # automat.update_enemy_state(longest_snake)
                # automat.make_movement_profile_prediction(enemy_snakes, enemy_heads, board, grid_map)
                # automat.update_behaviour()

        # update my snake state
        self.automats[self.my_snake_id].update_my_state(
            board, kill_board, grid_map)
Exemple #5
0
    def decide(self, you: Snake, board: BoardState,
               grid_map: GridMap) -> Direction:

        #########################
        # SoloSurvival
        snakes = board.snakes
        if len(snakes) == 1 and snakes[0].snake_id == you.snake_id:
            return SoloSurvival.next_step(you, board, grid_map)
        # SoloSurvival
        ########################

        if len(self.automats) != len(board.snakes):
            self._delete_dead_snake(board.dead_snakes)

        # init ValidActions object and get basic board for action_plan from multi_level
        valid_action = ValidActions(board, grid_map, you,
                                    self.states[self.my_snake_id])
        valid_actions, self.action_board, direction_depth, kill_board = valid_action.multi_level_valid_actions(
        )

        # decide if we focus on monitoring enemies or on calculating our next move
        dist_to_closest_head = Distance.dist_to_closest_enemy_head(
            board.snakes, you)
        if dist_to_closest_head < Params_Decision.CLOSEST_HEAD_BOUNDARY:
            self.monitoring_time = Params_Decision.REDUCED_MONITORING_TIME

        self._update_automats(board, kill_board, grid_map)

        next_action = self._call_strategy(you, board, grid_map, valid_actions,
                                          direction_depth)

        print("MyState:", self.automats[self.my_snake_id].get_state())

        return next_action
Exemple #6
0
    def a_star_search_wofood(
            start_field: Position, search_field: Position, board: BoardState,
            grid_map: GridMap) -> Tuple[int, List[Tuple[Position, Direction]]]:

        queue = KLPriorityQueue()
        came_from = {}  # current node ist key parent ist value
        cost_so_far = {str(start_field): 0}  # summierte Kosten

        current_position = start_field

        first = True

        while not queue.empty() or first:
            first = False
            # Check if Current Position is goal state
            if current_position == search_field:
                break

            # append cost for each unvisited valid direction
            for direction in Direction:
                next_position = current_position.advanced(direction)
                if grid_map.is_valid_at(next_position.x, next_position.y) \
                        and grid_map.grid_cache[next_position.x][next_position.y] != Occupant.Snake\
                        and (not board.is_occupied_by_food(next_position) or (next_position == search_field)):

                    # check if state wasnt visited or cost of visited state is lower
                    if (str(next_position) not in cost_so_far.keys()) \
                            or (cost_so_far[str(current_position)] < cost_so_far[str(next_position)]):

                        cost_so_far[str(next_position)] = cost_so_far[str(
                            current_position)] + 1
                        cost = Distance.euclidean_distance(
                            search_field, next_position)
                        queue.put(cost, (next_position, direction))

            # Get best position from Priority Queue
            pos_dir_tuple = queue.get()
            best_position = pos_dir_tuple[0]
            best_direction = pos_dir_tuple[1]

            # reverse direction to get poistion where we came from
            opposite_direction = AStar.reverse_direction(best_direction)

            # only use undiscovered nodes
            if best_position not in came_from:
                came_from[best_position] = (
                    best_position.advanced(opposite_direction), best_direction)
            current_position = best_position

        # Berechnung des Pfades anhand von came_from
        cost = cost_so_far[str(current_position)]
        path: List[Tuple[Position, Direction]] = []
        while not current_position == start_field:
            path.append(came_from[current_position])
            current_position = came_from[current_position][0]
        path = path[::-1]

        return cost, path
    def get_food_profiles(
            head: Position, board: BoardState,
            grid_map: GridMap) -> List[List[Tuple[Position, Direction]]]:
        profiles = []

        for food in board.food:
            if Distance.manhattan_dist(head, food) < 10:
                cost, path = AStar.a_star_search(head, food, board, grid_map)
                profiles.append(path)

        return profiles
    def get_head_profiles(head: Position, enemy_heads: List[Position], board: BoardState, grid_map: GridMap) -> \
            List[List[Tuple[Position, Direction]]]:

        profiles = []

        for enemy_head in enemy_heads:
            if Distance.manhattan_dist(head, enemy_head) < 15:
                cost, path = AStar.a_star_search(head, enemy_head, board,
                                                 grid_map)
                profiles.append(path)

        return profiles
Exemple #9
0
    def tail_gate(snake: Snake, board: BoardState, grid_map : GridMap) -> Direction:

        head = snake.get_head()
        tail = snake.get_tail()
        body = snake.get_body()
        distance = Distance.manhattan_dist(head, tail)
        if distance == 1:
            for direction in Direction:
                if head.advanced(direction) == tail:
                    return direction
        else:
            dist = 9999
            next_direction = None
            for direction in Direction:
                advanced_head = head.advanced(direction)
                d = Distance.manhattan_dist(advanced_head, tail)
                if advanced_head not in body:
                    if d < dist:
                        dist = d
                        next_direction = direction

            return next_direction
Exemple #10
0
    def flood_kill(enemy: Snake, my_snake: Snake, kill_board: np.ndarray,
                   board: BoardState, grid_map: GridMap):
        # TODO: Parameter snake_dead_in_rounds um mehr valide actions zu erhalten
        #  - breite des PFades auf 1 begrenzen
        my_head = my_snake.get_head()
        enemy_head = enemy.get_head()
        kill_actions = []
        search = False

        for part in enemy.body:
            kill_board[part.x][part.y] -= 1000
        kill_board[my_head.x][my_head.y] -= 1000

        x, y = np.unravel_index(kill_board.argmax(), kill_board.shape)

        print(kill_board)
        print(Position(x, y))
        for (pos_x, pos_y) in get_valid_neigbours(x, y, kill_board):
            if 0 > kill_board[pos_x][pos_y] > -800:
                x, y = pos_x, pos_y
                search = True
                break

        enemy_dist = Distance.manhattan_dist(enemy_head, Position(x, y))
        my_dist = Distance.manhattan_dist(my_head, Position(x, y))

        if enemy_dist > my_dist and search:
            cost, path = AStar.a_star_search(my_head, Position(x, y), board,
                                             grid_map)

            count = 0
            for pos, dir in path:
                if kill_board[pos.x][pos.y] >= 0:
                    return []

                kill_actions.append(dir)
                count += 1

        return kill_actions
Exemple #11
0
    def _find_invalid_actions(self) -> List[Direction]:
        help_board = np.zeros((self.board.width, self.board.height))
        head = self.my_snake.get_head()

        # mark snakes on the board
        self._mark_snakes(help_board)
        old_board = self.valid_board.copy()
        # print(self.valid_board)

        # calculate new wave for each depth level from queue
        for direction in self.valid_actions:
            next_position = head.advanced(direction)
            flood_queue = [(next_position.x, next_position.y)]
            visited = [(head.x, head.y)]

            for step in range(1, self.depth + 1):
                flood_queue, visited, _ = self._action_flood_fill(flood_queue,
                                                                  step,
                                                                  visited,
                                                                  None,
                                                                  enemy=False)

            if self.state != States.HUNGRY and self.my_snake.get_length() > 5:
                for food_pos in self.board.food:
                    if Distance.manhattan_dist(head, food_pos) > 3:
                        self.valid_board[food_pos.x][food_pos.y] = 1

            # expand for each direction
            depth = self.expand(next_position, direction)
            print(self.valid_board)

            self.direction_depth[direction] = depth
            self.kill_board = np.add(self.kill_board, self.valid_board)
            self.valid_board = old_board.copy()

        self.kill_board = np.subtract(
            self.kill_board, old_board * (len(self.valid_actions) - 1))

        invalid_actions = self._order_directions()

        return invalid_actions
Exemple #12
0
    def follow_food(snake: Snake, board: BoardState, grid_map: GridMap, reachable_food: List[Position]) \
            -> List[Tuple[Position, Direction]]:
        my_head = snake.get_head()
        food = None

        relevant_foods = RelevantFood.get_relevant_food(snake, board.snakes, reachable_food, board.width, board.height)
        if not relevant_foods:
            return []

        start_distance = 99
        # get food that is nearest to my head
        for relevant_food in relevant_foods:
            distance = Distance.manhattan_dist(my_head, relevant_food)
            if distance < start_distance:
                food = relevant_food
                start_distance = distance
        print("best food:", food)
        if not food or start_distance > 15:
            return []
        cost, path = AStar.a_star_search(my_head, food, board, grid_map)
        path_array = path

        return path_array
Exemple #13
0
    def avoid_enemy(my_snake: Snake, board: BoardState, grid_map: GridMap,
                    valid_actions: List[Direction], action_plan: ActionPlan,
                    direction_depth: Dict) -> Direction:

        if not valid_actions:
            possible_actions = my_snake.possible_actions()
            valid_actions = ValidActions.get_valid_actions(board,
                                                           possible_actions,
                                                           board.snakes,
                                                           my_snake,
                                                           grid_map,
                                                           avoid_food=False)

        num_snakes = 4 - len(board.snakes)
        flood_dist = 6 if len(board.snakes) > 2 else 99

        my_head = my_snake.get_head()
        enemy_heads = [
            snake.get_head() for snake in board.snakes
            if snake.snake_id != my_snake.snake_id
        ]

        middle = Position(int(board.height / 2), int(board.width / 2))
        corners = [
            Position(0, 0),
            Position(0, board.width),
            Position(board.height, 0),
            Position(board.height, board.width)
        ]

        escape_cost_dict = action_plan.escape_lane(my_head, valid_actions)

        # TODO: Unterscheidung der Params in Late game und early game abhängig von anzahl der Schlangen
        p_head = Params_Anxious.ALPHA_DISTANCE_ENEMY_HEAD[num_snakes] * (-1)
        p_corner = Params_Anxious.BETA_DISTANCE_CORNERS[num_snakes]
        p_mid = Params_Anxious.THETA_DISTANCE_MID[num_snakes] * (-1)
        p_border = Params_Anxious.EPSILON_NO_BORDER[num_snakes]

        p_food = (Params_Anxious.GAMMA_DISTANCE_FOOD[num_snakes] * 20 /
                  my_snake.health)
        p_flood_min = Params_Anxious.OMEGA_FLOOD_FILL_MIN[num_snakes] * (-1)
        p_flood_max = Params_Anxious.OMEGA_FLOOD_FILL_MAX[num_snakes]
        p_flood_dead = Params_Anxious.OMEGA_FLOOD_DEAD[num_snakes]

        p_corridor = Params_Anxious.RHO_ESCAPE_CORRIDOR[num_snakes] * (-1)
        p_length = Params_Anxious.TAU_PATH_LENGTH[num_snakes]

        total_cost = np.array([], dtype=np.float64)
        direction_cost = np.zeros(10)

        for action in valid_actions:

            next_position = my_head.advanced(action)

            # calculate flood fill
            flood_fill_value, relevant_food = FloodFill.get_fill_stats(
                board, next_position, my_snake.snake_id, new_pos=True)
            enemy_flood = sum([
                flood_fill_value[snake.snake_id] for snake in board.snakes
                if snake.snake_id != my_snake.snake_id and
                Distance.manhattan_dist(snake.get_head(), my_head) < flood_dist
            ])

            # calculate all costs for heuristics
            direction_cost[0] = direction_depth[action] * p_length

            direction_cost[1] = escape_cost_dict[action] * p_corridor

            direction_cost[2] = ActionPlan.punish_border_fields(
                next_position, my_head, grid_map.width,
                grid_map.height) * p_border

            direction_cost[3] = sum([
                Distance.manhattan_dist(next_position, enemy_head)
                for enemy_head in enemy_heads
            ]) * p_head

            direction_cost[4] = sum([
                Distance.manhattan_dist(next_position, corner)
                for corner in corners
                if Distance.manhattan_dist(next_position, corner) < 9
            ]) * p_corner

            direction_cost[5] = Distance.manhattan_dist(next_position,
                                                        middle) * p_mid

            direction_cost[6] = flood_fill_value[
                my_snake.snake_id] * p_flood_max
            direction_cost[7] = enemy_flood * p_flood_min

            direction_cost[8] = len(relevant_food) * p_food

            # extra points for killing enemy snake
            if num_snakes == 1:

                enemy_id = [
                    snake.snake_id for snake in board.snakes
                    if snake.snake_id != my_snake.snake_id
                ][0]
                if flood_fill_value[enemy_id] < 20:
                    flood_kill_value = (20 - flood_fill_value[enemy_id]) * 1000
                    direction_cost[9] = flood_kill_value * p_flood_dead

            total_cost = np.append(total_cost, direction_cost.sum())
            direction_cost = np.zeros(10)

        if valid_actions:
            best_action = valid_actions[int(np.argmax(total_cost))]
            print(best_action)
        else:
            best_action = None

        return best_action