def __best_building_site_farm(self, ai_stat: AI_GameStatus) -> BuildOption:
        """building sites get scored by how many buildable fields there are next to it"""
        best_score = -1
        best_site = (-1, -1)
        best_cd: Optional[List[CardinalDirection]] = None
        best_tl = None
        fields = []
        p = Priority.P_NO
        is_next_to_res = False  # just for printing
        if ai_stat.me.resources >= ai_stat.cost_building_construction[BuildingType.FARM]:
            for ai_t in ai_stat.map.buildable_tiles:
                tmp = False  # just for printing
                possible_fields = []
                score = 0
                for n in essentials.get_neighbours_on_set(ai_t, ai_stat.map.buildable_tiles):
                    if basic.num_resources_on_adjacent(n) == 0:
                        possible_fields.append(n)
                    if essentials.is_obj_in_list(n, ai_stat.map.scoutable_tiles):
                        score += 1
                score += len(possible_fields)
                amount_of_fields = min(3, len(possible_fields))
                sampled = random.sample(possible_fields, amount_of_fields)
                score += len(essentials.get_neighbours_on_set(ai_t, ai_stat.map.scoutable_tiles)) / 2
                # if build site is next to a resource --> reduce value by 1 for each resource field
                score = score - basic.num_resources_on_adjacent(ai_t)
                # make the score dependent on safety level of region
                #score = score - self.compass.get_threat_level(ai_t).value * 2
                if ai_t in self.danger_zone:
                    score += - 10

                if best_score < score:
                    best_score = score
                    is_next_to_res = tmp
                    best_site = ai_t.offset_coordinates
                    best_cd = self.compass.get_cardinal_direction_obj(ai_t, self.compass.center_tile)
                    best_tl = self.compass.get_threat_level(ai_t)
                    fields.clear()
                    for s in sampled:
                        fields.append(s.offset_coordinates)

        if is_next_to_res:
            debug("The farm will be next to a resource (apparently there is no better spot)")

        # translate score to priority (normalization step)
        if len(fields) >= 3:
            p = Priority.P_HIGH
        elif len(fields) >= 2:
            p = Priority.P_MEDIUM
        elif len(fields) >= 1:
            p = Priority.P_LOW
        # hint(f"                            type eval: {type(p)}")
        return BuildOption(BuildingType.FARM, best_site, fields, p, cardinal_direction=best_cd, threat_level=best_tl)
    def evaluate_move_upgrading(self, ai_stat: AI_GameStatus) -> List[UpgradeOption]:
        """ find best option for an upgradable building
        Idea: reduce score if there are still adjacent resource fields or if the hut is in the danger zone
        Increase score if number of inactive huts is high and if located in save zone"""
        def normalize(s: float) -> Priority:
            if s < 0:
                return Priority.P_NO
            elif 0 <= s < 3:
                return Priority.P_MEDIUM
            elif s >= 3:
                return Priority.P_HIGH

        options: List[UpgradeOption] = []
        if ai_stat.me.resources < ai_stat.cost_building_construction[BuildingType.VILLA]:
            return options

        huts = [x for x in ai_stat.map.building_list if x.type is BuildingType.HUT]
        best_score: float = -100
        best_option: Optional[UpgradeOption] = None
        for hut in huts:
            score = - basic.num_resources_on_adjacent(hut)
            score += self.inactive_huts
            if hut.base_tile in self.claimed_tiles:
                score = score + 1
            if hut.base_tile in self.danger_zone:
                score = score - 2
            if score > best_score:
                best_score = score
                best_option = UpgradeOption(BuildingType.VILLA, hut.offset_coordinates, normalize(score))
        return [best_option]
    def __best_building_site_barracks(self, ai_stat: AI_GameStatus) -> Tuple[Priority, Tuple[int, int]]:
        """building sites should be a claimed tile and not next to a resource"""
        if ai_stat.me.resources >= ai_stat.cost_building_construction[BuildingType.BARRACKS]:
            candidates = []
            for c in self.claimed_tiles:
                if not c.is_buildable:  # if tile is not buildable, forget it
                    continue
                res_next_to_can = basic.num_resources_on_adjacent(c)

                if res_next_to_can == 0:
                    # very hard constraint (go by value would be better)
                    #if self.compass.get_threat_level(c).value <= ThreatLevel.LOW_RISK.value:
                        # build barracks only in safe zone
                    if c not in self.danger_zone:
                        candidates.append(c)
            if DETAILED_DEBUG:
                debug(f"possible candidates for a barracks: {len(candidates)}")
            if len(candidates) > 0:
                idx = random.randint(0, len(candidates) - 1)
                c = 0
                for e in candidates:
                    if idx == c:
                        return Priority.P_MEDIUM, e.offset_coordinates
                    c = c + 1
        return Priority.P_NO, (-1, -1)
 def __best_building_site_hut(self, ai_stat: AI_GameStatus) -> Tuple[int, Tuple[int, int]]:
     """building sites get scored by their number of resource fields next to them"""
     best_score = -1
     best_site = (-1, -1)
     if ai_stat.me.resources >= ai_stat.cost_building_construction[BuildingType.HUT]:
         for ai_t in ai_stat.map.buildable_tiles:
             score = basic.num_resources_on_adjacent(ai_t)
             if best_score < score:
                 best_score = score
                 best_site = ai_t.offset_coordinates
     return best_score, best_site