728x90
또다른 정찰기로서 써먹으면 좋은 저그 유닛
'스커지'
※ 스커지, 스컬지, 스콜지 등등으로 많이 불리지만 저자는 스커지라고 작성하겠다.
스커지는 재빠르게 적에게 붙어 자폭하는 공중에서 잘못 만나면 공중 유닛하나 잃어버릴 수 있지만
우리는 스커지의 속도를 보고 나쁘지않음을 깨닫고 정찰로서 사용하도록한다.
물론 시야가 짧지만 만일 맵이 섬맵일 수 있기에 정찰을 하도록 개발하였다.
저글링과 코드가 흡사하기에 이코드로 저글링 정찰의 코드를 대체하도록한다.
하지만 다른 점이 있다면 모든 스컬지들을 정찰하도록한다.
굳이 한 마리만 보낼 필요는 없다고 판단.
물론 추후 정찰을 해제해야할 수도 있기에 코드는 추후 수정될 가능성이 높다.
static int count = 0;
static ArrayList<TilePosition> makeNewList() {
BaseLocation bl1 = InformationManager.Instance().getMainBaseLocation(MyBotModule.Broodwar.self());
BaseLocation bl2 = InformationManager.Instance().getFirstExpansionLocation(MyBotModule.Broodwar.self());
BaseLocation bl3 = InformationManager.Instance().getMainBaseLocation(MyBotModule.Broodwar.enemy());
BaseLocation bl4 = InformationManager.Instance().getFirstExpansionLocation(MyBotModule.Broodwar.enemy());
if (bl1 == null | bl2 == null || bl3 == null || bl4 == null) {
return new ArrayList<TilePosition>();
}
ArrayList<TilePosition> listTilePosition = new ArrayList<TilePosition>();
if (listTilePosition.size() == 0) {
List<BaseLocation> listBaseLocation = BWTA.getBaseLocations();
if (bl3 != null && bl4 != null) {
ArrayList<TilePosition> tmpList = new ArrayList<TilePosition>();
for (BaseLocation bl : listBaseLocation) {
tmpList.add(bl.getTilePosition());
}
Collections.sort(tmpList, new ComparatorBaseLocation());
for (int i = tmpList.size() - 1; i >= 0; i--) {
if (tmpList.get(i).getX() >= 50 && tmpList.get(i).getX() <= 70 && tmpList.get(i).getY() >= 50 && tmpList.get(i).getY() <= 70) {
tmpList.remove(i);
}
}
int indexB1 = 0;
for (int i = 0; i < tmpList.size(); i++) {
if (tmpList.get(i).equals(bl1.getTilePosition())) {
indexB1 = i;
}
}
int index = indexB1;
boolean findEnemy = false;
while (findEnemy == false) {
if (tmpList.get(index).equals(bl3.getTilePosition()) || tmpList.get(index).equals(bl4.getTilePosition())) {
findEnemy = true;
break;
}
if (!tmpList.get(index).equals(bl1.getTilePosition()) && !tmpList.get(index).equals(bl2.getTilePosition()) && !tmpList.get(index).equals(bl3.getTilePosition()) && !tmpList.get(index).equals(bl4.getTilePosition())) {
listTilePosition.add(tmpList.get(index));
}
index++;
if (index >= tmpList.size()) {
index = 0;
}
}
index--;
if (index < 0)
index = tmpList.size() - 1;
findEnemy = false;
while (findEnemy == false) {
if (tmpList.get(index).equals(bl3.getTilePosition()) || tmpList.get(index).equals(bl4.getTilePosition())) {
findEnemy = true;
break;
}
if (!tmpList.get(index).equals(bl1.getTilePosition()) && !tmpList.get(index).equals(bl2.getTilePosition()) && !tmpList.get(index).equals(bl3.getTilePosition()) && !tmpList.get(index).equals(bl4.getTilePosition())) {
listTilePosition.add(tmpList.get(index));
}
index--;
if (index < 0) {
index = tmpList.size() - 1;
}
}
index++;
if (index > tmpList.size() - 1) {
index = 0;
}
boolean findSelf = false;
while (findSelf == false) {
if (tmpList.get(index).equals(bl1.getTilePosition()) || tmpList.get(index).equals(bl2.getTilePosition())) {
findSelf = true;
break;
}
if (!tmpList.get(index).equals(bl1.getTilePosition()) && !tmpList.get(index).equals(bl2.getTilePosition()) && !tmpList.get(index).equals(bl3.getTilePosition()) && !tmpList.get(index).equals(bl4.getTilePosition())) {
listTilePosition.add(tmpList.get(index));
}
index++;
if (index >= tmpList.size()) {
index = 0;
}
}
}
}
count++;
if (count % 2 == 0) {
Collections.reverse(listTilePosition);
}
return listTilePosition;
}
위 메소드를 사용하여 정찰을 위치를 지정한다.
적군과 본인의 기본 기지 영역을 제외하여 나머지들을 저장한다.
static HashMap<Integer, ArrayList<TilePosition>> mapScourgePatrol = new HashMap<Integer, ArrayList<TilePosition>>();
void scourgeMove(Unit scourge) {
if (!mapScourgePatrol.containsKey(scourge.getID()) || mapScourgePatrol.get(scourge.getID()).size() == 0)
mapScourgePatrol.put(scourge.getID(), makeNewList());
ArrayList<TilePosition> targetList = mapScourgePatrol.get(scourge.getID());
if (targetList.size() > 0) {
TilePosition target = targetList.get(0);
if (InformationManager.distanceTilePosition(target, scourge.getTilePosition()) <= 2)
targetList.remove(target);
else
commandUtil.attackMove(scourge, target.toPosition());
}
}
InformationManager에서 distanceTilePosition 메소드는 없기에 직접 구현을 하였다.
static double distanceTilePosition(TilePosition a, TilePosition b) {
return Math.sqrt((a.getX() - b.getX()) * (a.getX() - b.getX()) + (a.getY() - b.getY()) * (a.getY() - b.getY()));
}
그리고 종족에 따라 상황이 다르기때문에 작성하는 글에는 테란 코드만을 작성하겠다.
private void terranAction(Unit unit) {
for (Unit turret : MyBotModule.Broodwar.enemy().getUnits()) {
if (turret.getType() == UnitType.Terran_Missile_Turret) {
Position turretPosition = turret.getPosition();
if (InformationManager.distancePosition(unit.getPosition(), turretPosition) < 11 * 32) {
int X2 = unit.getPosition().getX();
int Y2 = unit.getPosition().getY();
int X1 = turretPosition.getX();
int Y1 = turretPosition.getY();
Position position = new Position(2 * X2 - X1, 2 * Y2 - Y1);
if (!position.isValid())
commandUtil.move(unit, MyBotModule.Broodwar.self().getStartLocation().toPosition());
else
commandUtil.move(unit, position);
setSpecialAction(unit, 0);
return;
}
}
}
runAwayAction(unit);
Unit vessel = getMostCloseEnemyUnit(UnitType.Terran_Science_Vessel, unit);
if (vessel != null && unit.getDistance(vessel) < 400) {
if (!checkGoliat(vessel)) {
commandUtil.attackUnit(unit, vessel);
return;
}
}
scourgeMove(unit);
}
private void runAwayAction(Unit unit) {
for (Unit goliath : MyBotModule.Broodwar.enemy().getUnits()) {
if (goliath.getType() == UnitType.Terran_Goliath) {
Position goliathPosition = goliath.getPosition();
if (InformationManager.distancePosition(unit.getPosition(), goliathPosition) < 10 * 32) {
int X2 = unit.getPosition().getX();
int Y2 = unit.getPosition().getY();
int X1 = goliathPosition.getX();
int Y1 = goliathPosition.getY();
commandUtil.move(unit, new Position(2 * X2 - X1 + r.nextInt(3), 2 * Y2 - Y1 + r.nextInt(3)));
setSpecialAction(unit, 0);
return;
}
}
}
Unit bunker = getMostCloseEnemyUnit(UnitType.Terran_Bunker, unit);
if (bunker != null && distanceTilePosition(bunker.getTilePosition(), unit.getTilePosition()) < 7) {
int X2 = unit.getPosition().getX();
int Y2 = unit.getPosition().getY();
int X1 = bunker.getPosition().getX();
int Y1 = bunker.getPosition().getY();
commandUtil.move(unit, new Position(2 * X2 - X1 + r.nextInt(3), 2 * Y2 - Y1 + r.nextInt(3)));
setSpecialAction(unit, 0);
return;
}
Unit valkyire = getMostCloseEnemyUnit(UnitType.Terran_Valkyrie, unit);
if (valkyire != null && distanceTilePosition(valkyire.getTilePosition(), unit.getTilePosition()) < 9) {
int X2 = unit.getPosition().getX();
int Y2 = unit.getPosition().getY();
int X1 = valkyire.getPosition().getX();
int Y1 = valkyire.getPosition().getY();
commandUtil.move(unit, new Position(2 * X2 - X1 + r.nextInt(3), 2 * Y2 - Y1 + r.nextInt(3)));
setSpecialAction(unit, 0);
return;
}
}
boolean checkGoliat(Unit unit) {
boolean goliatAround = false;
for (Unit goliath : MyBotModule.Broodwar.enemy().getUnits()) {
if (goliath.getType() == UnitType.Terran_Goliath) {
Position tp = goliath.getPosition();
if (InformationManager.distancePosition(unit.getPosition(), tp) <= 10 * 32)
goliatAround = true;
}
}
return goliatAround;
}
...
HashMap<Integer, Integer> mapSpecialActionTime = new HashMap<Integer, Integer>();
void setSpecialAction(Unit unit, int addTime) {
mapSpecialActionTime.put(unit.getID(), MyBotModule.Broodwar.getFrameCount() + addTime);
}
InformationManager에 distancePosition메소드는 distanceTilePosition 메소드와 매우 유사하기에 직접 구현하기를 바란다.
HashMap<Integer, Boolean> mapMode = new HashMap<Integer, Boolean>();
Random r = new Random();
private void scourgeControl(Unit unit) {
if (InformationManager.Instance().enemyRace == Race.Protoss)
protossAction(unit);
else if (InformationManager.Instance().enemyRace == Race.Terran)
terranAction(unit);
else
zergAction(unit);
}
스커지에게 위협적이라면 도주하고 그렇지않는 배슬을 발견하면 즉시 공격하도록한다.
영상을 끝으로 글을 마무리하겠다.
'스타봇' 카테고리의 다른 글
스타크래프트 봇 동아리, 내전용 봇 개발 (#11) | 디파일러 파트 (1) (0) | 2021.07.22 |
---|---|
스타크래프트 봇 동아리, 내전용 봇 개발 (#10) (0) | 2021.07.21 |
스타크래프트 봇 동아리, 내전용 봇 개발 (#8) (0) | 2021.07.16 |
스타크래프트 봇 동아리, 내전용 봇 개발 (#7) (0) | 2021.07.15 |
스타크래프트 봇 동아리, 내전용 봇 개발 (#6) (0) | 2021.07.14 |