스타크래프트2 봇

스타크래프트2 인공지능 봇을 만들어보자 (#4)

오잎 클로버 2021. 8. 6. 12:00
728x90

정찰 코드를 만들고 나서 생각을 해보니 딱히 필요하진않겠지만, 응용할 수는 있을 것이라 생각하였다.

그래서 정찰 코드를 사용은 하지않지만

남겨는 둘 예정이다.

해당 코드는 scout으로 옮기기로 하고, 

서플라이 디폿과 배럭을 짓는 코드를 구현하고자한다.

 

저그를 제외한 종족들은 일꾼이 건물을 짓지만 사라지지는 않기에

가만히 있는 IDLE 상태가 된다.

해당 IDLE상태인 일꾼을 다시 일하도록하여야하지만

저자의 실력이 좋지않아 다시 일하도록 하지 못하였다.

 

다시 서플라이디폿에 대한 로직을 간단히 세워보자면

1) 서플라이 디폿을 건설 가능한가

2) 최대 보급량 - 현재 사용된 보급량 > 4 가 충족됐는가

3) 현재 서플라이 디폿을 건설 중일 때에 또 건설할 필요는 없다.

4) 미네랄 캐고 있던 일꾼 하나를 선택하여 건설하도록한다.

 

먼저 위 로직을 도와주는 메소드를 구현하였다.

def can_do(obs, action_id):
    return action_id in obs.observation.available_actions


def selected_units_is_idle(obs):
    selected_units = [x for x in obs.observation.feature_units
                      if x.is_selected == 1]
    if len(selected_units) == 0:
        print("놀고 있는 유닛 없음")
        return True
    else:
        selected_unit = [x.order_length for x in selected_units]
        if sum(selected_unit) > 0:
            return False
        return True


def food_check(obs):
    food_enough = (obs.observation.player.food_cap - obs.observation.player.food_used)
    if food_enough > 4:
        print("충분함")
        return False
    print("충분하지않음")
    return True


def build_building_now(obs, building_id):
    units = [unit.build_progress for unit in obs.observation.feature_units
             if unit.unit_type == building_id]
    if len(units) > 0:
        return True
    else:
        return False

can_do는 현재 사용가능한 기능인지 확인하는 메소드이고

selected_units_is_idle는 놀고 있는 유닛이 있는 지 확인하는 메소드이고

food_check는 인구수가 충분한지 부족한지 확인하는 메소드이고

build_building_now는 현재 해당 종류의 건물을 건설 중인지 확인하는 메소드이다.

 

config에 아래 변수를 추가해서 사용하도록한다,

# 건물 코드들
BUILD_SUPPLYDEPOT = 91
BUILD_BARRACKS = 42
HARVEST_GATHER_SCV_UNIT = 359

 

추가된 코드는 아래와 같으며, 총 코드는 필자의 깃허브를 확인하길 바란다.

elif can_do(obs, config.BUILD_SUPPLYDEPOT) and \
     food_check(obs) and (not build_building_now(obs, units.Terran.SupplyDepot)) \
     and [x.order_id_0 for x in obs.observation.feature_units if x.is_selected == 1][0] == config.HARVEST_GATHER_SCV_UNIT:
     x, y = random.randint(0, config.SCREEN_SIZE), random.randint(0, config.SCREEN_SIZE)
     return actions.FunctionCall(config.BUILD_SUPPLYDEPOT, [config.NOT_QUEUED, [x, y]])
elif can_do(obs, config.BUILD_BARRACKS) and \
     (not build_building_now(obs, units.Terran.Barracks)) and \
     (len([x for x in obs.observation.feature_units
           if x.unit_type == units.Terran.Barracks]) == 0) and \
     selected_units_is_idle(obs):
     x, y = random.randint(0, config.SCREEN_SIZE), random.randint(0, config.SCREEN_SIZE)
     return actions.FunctionCall(config.BUILD_BARRACKS, [config.NOT_QUEUED, [x, y]])

다음번에는 마린 생산하는 것을 구현하고자한다.