피할 수 있는 지점을 설정하고, 움직임 패턴을 만들어 적의 총알을 피한다!
Alisdair Owens Student, University of Southampton 2002년 5월
반중력 운동(Anti-gravity movement)은 대부분의 Robocoder 전문가들이 선택하는 움직임 유형이다. 이를 사용하여 지도상에서 피할 수 있는 지점을 설정하고 움직임 패턴을 만들며 적의 총알을 피할 수 있다. Alisdair Owens는 이 유용한 기술의 구현 방법을 설명하고 테스트 구동을 위해 로봇 예제도 제공한다.
반중력 운동(Anti-gravity movement)은 유연성이 뛰어난 기술로서 전투장 내에서 피신할 수 있는 특별한 지점 (중력 지점-gravity points)을 정의하여 패턴 분석 로봇을 혼란에 빠트린다. 각각의 중력 지점(gravity point)은 세기(strength)에 따라 할당된다. x와 y의 방향에서 세기의 요소를 결정하여 모든 적군 로봇을 피할 수 있다. ("반중력(Anti-gravity) 용어정리" 참조)
반중력(Anti-gravity) 용어정리
중력 지점(Gravity points): 공격하기 원하는 장소로 정의된 Robocode 전투장 내의 장소들.
힘(Forces): 각각의 중력 지점은 힘(force) 또는 세기(strength)를 할당 받는다. 값이 클수록 로봇은 그 지점에서 힘을 만들어 내면서 공격할 수 있다.
힘의 컴포넌트: 각각의 힘은 x (수평) 방향과 , y (수직) 방향에서 작동하는 컴포넌트를 갖고있다. 45도 각도는 x와 y 방향에서 동등한 컴포넌트를 갖고있다. 90도 각도는 x 방향에서 전적으로 작동한다.
힘 결정하기: 여러 힘들이 작동할 때 만들어진 모든 힘을 산정하는 과정이다. 예를 들어 x 방향에서 작동하는 -200의 힘이 있고 또한 x 방향에서 300의 힘이 있다면 만들어진 힘의 전체는 100이다. |
반중력 운동의 수학원리 반중력에 내포된 수학은 실제로 매우 간단하다. 삼각법만 알면 된다.
그림 1에서 "F"라는 화살은 Crazy로 부터 AntiGravityBot에 가해지는 힘의 방향을 나타낸다. 힘은 다른 두 개의 화살에서 보이듯이 x와 y에 있는 컴포넌트로 간주될 수 있다. 힘을 결정하여 x와 y 방향의 모든 중력 지점에서 모든 힘을 한데 모을 수 있다 .
그림 1. 힘 결정하기
로봇이 멀리있는 로봇에 의해 영향받지 않도록 하려면, 세기(strength)가 중력 지점의 힘이고 거리(distance)가 중력 지점과 로봇 사이의 거리인 곳에서 force = strength/Math.pow(distance,2) 함수를 사용하여 중력 지점으로부터 로봇에 가해지는 힘을 계산해야한다.
코드 다음 코드는 기본적인 시스템 코드이다. Listing 1은 반중력의 주요 함수를 보여주고 있다. 한 벡터 내에서 모든 중력 지점을 통해 순환하고 힘을 결정하며 정확한 방향으로 로봇을 움직인다. 적군 로봇들이 격퇴 지점에 가있도록 할 것을 권장하는 바이다. 이렇게 하려면 전투장 모양을 항상 업데이트 해야한다.
Listing 1.반중력의 일꾼: antiGravMove()
void antiGravMove() { double xforce = 0; double yforce = 0; double force; double ang; GravPoint p; for(int i = 0;i<gravpoints.size();i++) { p = (GravPoint)gravpoints.elementAt(i); //Calculate the total force from this point on us force = p.power/Math.pow(getRange(getX(),getY(),p.x,p.y),2); //Find the bearing from the point to us ang = normaliseBearing(Math.PI/2 - Math.atan2(getY() - p.y, getX() - p.x)); //Add the components of this force to the total force in their //respective directions xforce += Math.sin(ang) * force; yforce += Math.cos(ang) * force; } /**The following four lines add wall avoidance. They will only affect us if the bot is close to the walls due to the force from the walls decreasing at a power 3.**/ xforce += 5000/Math.pow(getRange(getX(), getY(), getBattleFieldWidth(), getY()), 3); xforce -= 5000/Math.pow(getRange(getX(), getY(), 0, getY()), 3); yforce += 5000/Math.pow(getRange(getX(), getY(), getX(), getBattleFieldHeight()), 3); yforce -= 5000/Math.pow(getRange(getX(), getY(), getX(), 0), 3); //Move in the direction of our resolved force. goTo(getX()-xforce,getY()-yforce); }
Listing 2의 helper 메소드는 가장 효율적인 방법으로 어떤 지점으로 움직일 수 있도록 하면서 로봇과 적군로봇 사이의 거리를 두도록 한다.
Listing 2. Helper 메소드
/**Move in the direction of an x and y coordinate**/ void goTo(double x, double y) { double dist = 20; double angle = Math.toDegrees(absbearing(getX(),getY(),x,y)); double r = turnTo(angle); setAhead(dist * r); }
/**Turns the shortest angle possible to come to a heading, then returns the direction the bot needs to move in.**/ int turnTo(double angle) { double ang; int dir; ang = normalisebearing(getHeading() - angle); if (ang > 90) { ang -= 180; dir = -1; } else if (ang < -90) { ang += 180; dir = -1; } else { dir = 1; } setTurnLeft(ang); return dir; }
/**/Returns the distance between two points**/ double getRange(double x1,double y1, double x2,double y2) { double x = x2-x1; double y = y2-y1; double range = Math.sqrt(x*x + y*y); return range; }
마지막으로, Listing 3에서 GravPoint 클래스를 볼 수 있는데 이것은 중력 지점에 대해 우리가 필요로하는 모든 데이터를 보유하고 있다. 격퇴하기 위해서는 power 는 마이너스(-)가 되어야한다.
Listing 3. GravPoint class
class GravPoint { public double x,y,power; public GravPoint(double pX,double pY,double pPower) { x = pX; y = pY; power = pPower; } }
전체 소스 다운로드.
작동 향상 Listings 1 부터 3의 코드는 합리적인 작동을 만들어낸다. 하지만 전투 퍼포먼스에는 미치지 못한다. 로봇이 다른 로봇과 일반적으로 멀리 떨어져있으면 벽에 밀착할 경향이 크다. 예를 들어 일단 로봇이 밑쪽 벽에 다다르면 이 보다 아래에 있는 로봇은 없다. 따라서 벽 자체에서 만들어진 반발력을 제외하고는 이것을 밀어낼 힘이 없는 것이다. 벽의 반발력은 제한된 범위이기 때문에 형편없는 작동만 만들어내는 것이다.
이 문제를 해결하기위해서 전투장 주변의 일련의 지점들에 모든 힘을 모으는 시스템을 사용한다. 그런다음 평균보다 큰 힘을 가진 지점들에 반발력 값을 할당하고 평균 힘보다 낮은 값을 가진 지점에 견인력 값을 할당한다. 그런 다음 로봇에 새로운 지점들의 힘을 할당한다. 견인 지점을 할당할 때 조심해야한다. 로봇이 견인 지점에 가까이 갈 때 근방을 배회하면서 결코 떠나지 않을 것이다. 이런 문제 때문에 중간 지점에 무작위로 위치를 할당하고 위치를 정기적으로 바꾼다.
추가적인 작동 향상 반중력은 놀랍도록 융통성이 있는 기술이다. 우리가 만들 수 있는 전체 작동 범위를 논하는 것은 불가능하다. 다음은 그 중 흥미로운 것들이다:
목표 선택: 공격하기 편하거나 힘이 약한 목표물에 낮은 반발력 값을 할당하여 그 목표물에 가까이 가서 공격할 수 있다.
불규칙성(Randomisation): 규칙성을 기본으로 하고, x와 y 힘에서 임의의 수를 더하거나 빼어서 좀더 임의적인 움직임을 만들어내고 때때로 멈추기도 하며 적군의 타겟 시스템을 속일 수도 있다.
총알 피하기 : 적군이 자신에게 발사할 때를 안다면 반중력 지점으로 발사되는 총알을 모델링할 수 있다. 예를 들어 선형 타케팅으로 발사된다면 매 순서마다 중력 지점의 위치를 업데이트 하여 총알을 피할 수 있다.
리더(leader)를 따르기: 자신의 로봇이 따라갈 "매력적인" 지점을 만드는 것이다. 이 지점을 움직여서 원하는 모든 패턴을 만들 수 있다. |