스타봇

스타크래프트 봇 동아리, 내전용 봇 개발 (#14)

오잎 클로버 2021. 7. 25. 12:00
728x90

이번 글은 내전용 봇 개발의 마지막 글이다.

구현하고자하는 기능은 반드시 필요한 일꾼과 인구수를 계속 보충하는 기능을 구현하고자한다.

// 일꾼 계속 추가 생산
public void executeWorkerTraining() {

	// InitialBuildOrder 진행중에는 아무것도 하지 않습니다
	if (!isInitialBuildOrderFinished) {
		return;
	}

	if (MyBotModule.Broodwar.self().minerals() >= 50) {
		// workerCount = 현재 일꾼 수 + 생산중인 일꾼 수
		int workerCount = MyBotModule.Broodwar.self().allUnitCount(InformationManager.Instance().getWorkerType());

		if (MyBotModule.Broodwar.self().getRace() == Race.Zerg) {
			for (Unit unit : MyBotModule.Broodwar.self().getUnits()) {
				if (unit.getType() == UnitType.Zerg_Egg) {
					// Zerg_Egg 에게 morph 명령을 내리면 isMorphing = true,
					// isBeingConstructed = true, isConstructing = true 가 된다
					// Zerg_Egg 가 다른 유닛으로 바뀌면서 새로 만들어진 유닛은 잠시
					// isBeingConstructed = true, isConstructing = true 가
					// 되었다가,
					if (unit.isMorphing() && unit.getBuildType() == UnitType.Zerg_Drone) {
						workerCount++;
					}
				}
			}
		}
        else {
			for (Unit unit : MyBotModule.Broodwar.self().getUnits()) {
				if (unit.getType().isResourceDepot()) {
					if (unit.isTraining()) {
						workerCount += unit.getTrainingQueue().size();
					}
				}
			}
		}

		// 최소 12마리, 최대 40마리
		if (workerCount <= 12 * InformationManager.mapSelfMainBuilding.size() && workerCount <= 40) {
			for (Unit unit : MyBotModule.Broodwar.self().getUnits()) {
				if (unit.getType().isResourceDepot()) {
					if (!unit.isTraining() || unit.getLarva().size() > 0) {
						// 빌드큐에 일꾼 생산이 1개는 있도록 한다
						if (BuildManager.Instance().buildQueue.getItemCount(InformationManager.Instance().getWorkerType(), null) == 0) {
							// std.cout + "worker enqueue" + std.endl;
							BuildManager.Instance().buildQueue.queueAsLowestPriority(new MetaType(InformationManager.Instance().getWorkerType()), false);
						}
					}
				}
			}
		}
	}
}

코드 해석은 주석으로도 충분히 해석이 가능하나, 설명을 하자면

빌드큐에 반드시 일꾼을 생성하도록하였다.

위 코드는 저그이기에 최대 값을 40으로 하였으나, 프로토스나 테란일 때에는 최대 60으로 하는 것이 좋으며, 동시에

위 코드와 달리 작성해가면서 여러 테스트를 거쳐 최적의 코드를 찾으시길 바란다.

 

// 인구수 자동 생산
private void supplyManagement() {
	if (!isInitialBuildOrderFinished)
		return;

	if (MyBotModule.Broodwar.self().supplyTotal() <= 400) {
		// 서플라이가 다 꽉찼을때 새 서플라이를 지으면 지연이 많이 일어나므로, supplyMargin (게임에서의 서플라이 마진 값의 2배)만큼
		// 부족해지면 새 서플라이를 짓도록 한다
		// 이렇게 값을 정해놓으면, 게임 초반부에는 서플라이를 너무 일찍 짓고, 게임 후반부에는 서플라이를 너무 늦게 짓게 된다
		int supplyMargin = 12;

		// currentSupplyShortage 를 계산한다
		int currentSupplyShortage = MyBotModule.Broodwar.self().supplyUsed() + supplyMargin - MyBotModule.Broodwar.self().supplyTotal();

		if (currentSupplyShortage > 0) {
			// 생산 / 건설 중인 supply를 센다
			int onBuildingSupplyCount = 0;

			// 저그 종족인 경우, 생산중인 Zerg_Overlord (Zerg_Egg) 를 센다. Hatchery 등 건물은 세지 않는다
			if (MyBotModule.Broodwar.self().getRace() == Race.Zerg) {
				for (Unit unit : MyBotModule.Broodwar.self().getUnits()) {
					if (unit.getType() == UnitType.Zerg_Egg && unit.getBuildType() == UnitType.Zerg_Overlord) {
						onBuildingSupplyCount += UnitType.Zerg_Overlord.supplyProvided();
					}
					// 갓태어난 Overlord 는 아직 SupplyTotal 에 반영안되어서, 추가 카운트를 해줘야함
					if (unit.getType() == UnitType.Zerg_Overlord && unit.isConstructing()) {
						onBuildingSupplyCount += UnitType.Zerg_Overlord.supplyProvided();
					}
				}
			}
			// 저그 종족이 아닌 경우, 건설중인 Protoss_Pylon, Terran_Supply_Depot 를 센다. Nexus, Command
			// Center 등 건물은 세지 않는다
			else {
				onBuildingSupplyCount += ConstructionManager.Instance().getConstructionQueueItemCount(InformationManager.Instance().getBasicSupplyProviderUnitType(), null) * InformationManager.Instance().getBasicSupplyProviderUnitType().supplyProvided();
			}

			if (currentSupplyShortage > onBuildingSupplyCount) {

				// BuildQueue 최상단에 SupplyProvider 가 있지 않으면 enqueue 한다
				boolean isToEnqueue = true;
				if (!BuildManager.Instance().buildQueue.isEmpty()) {
					BuildOrderItem currentItem = BuildManager.Instance().buildQueue.getHighestPriorityItem();
					if (currentItem.metaType.isUnit() && currentItem.metaType.getUnitType() == InformationManager.Instance().getBasicSupplyProviderUnitType()) {
						isToEnqueue = false;
					}
				}
				if (isToEnqueue) {
					BuildManager.Instance().buildQueue.queueAsHighestPriority(UnitType.Zerg_Overlord, BuildOrderItem.SeedPositionStrategy.MainBaseLocation, true);
				}
			}
		}
	}
}

위 코드는 인구수를 자동으로 채워주는 데 인구수가 12(인게임내에서는 6) 남았을 때 인구수를 채울 수 있는 Unit을 큐에 넣는다.

 

필자가 코드 전체를 작성할 수 없기에 개인적으로 꼭 필요하다 느끼는 것만 작성하였다.

추후 내전이 끝난 이후 작성할 15번째 글의 필자의 깃헙 주소를 참고하길 바라며, 마지막으로 리플레이 파일를 남겨두겠다. (내전은 8월 말 입니다.)

iCCup Fighti_ZvsP_203811.rep
0.14MB
iCCup Fighti_ZvsT_160832.rep
0.10MB
iCCup Fighti_ZvsZ_112214.rep
0.73MB

여러 아쉬운 점들이 더러 있고, 저프전이 가장 아쉬운 것 같다.

(초반 러쉬는 막으나, 중후반전에서 본진까지 뚫는것이 너무 아쉽다)