티스토리 뷰

반응형
출처 : http://www.ibm.com/developerworks/kr/library/j-robocode/index.html



총알을 피하고 정확한 공격 작전을 수행하면서 상속, 다형성, 이벤트 처리 및 내부 클래스를 배우는 것이 가능할까? 중독적인 게임광 대상 교육 툴인 Robocode가 전 세계 자바 개발자들에게 이를 가능하도록 한다.

Robocode는 사용하기 쉬운 로봇 전쟁 시뮬레이터로, Java 2를 지원하는 모든 플랫폼에서 실행된다. 여러분은 로봇을 만들어 전쟁터에 내보내고 다른 개발자가 만든 상대 로봇과 끝까지 싸우도록 해야한다. 여러분이 일단 이들을 무찌르고 나면 전세계적으로 형성되고 있는 리그 중 하나에 세계 최고 로봇에 대항하여 자신의 로봇을 출전시킬 수 있다.

각 Robocode 참가자는 자바 언어의 요소를 사용하여 자신의 로봇을 만드는데, 초보자부터 고급 해커에 이르기까지 모든 수준의 개발자들이 참가할 수 있다. 초보 자바 개발자들은 기본적인 사항들 (API 코드 호출하기, Javadocs 읽기, 상속, 내부 클래스, 이벤트 처리 등)을 배울 수 있다. 고급 개발자들은 동급 최강의 소프트웨어 로봇을 구축해야 하는 세계적인 과제에서 자신의 프로그래밍 스킬을 조율할 수 있다. 이 글에서 우리는 Robocode를 소개하고, 여러분의 첫번째 Robocode 로봇을 만들어 세계를 무찌르기 위해 출발하도록 할 것이다. 우리는 또한 Robocode를 움직이는 매혹적인 "장막 뒤"의 장치들을 엿보도록 하겠다.

다운로드 및 설치하기

Robocode는 IBM의 인터넷 부문인 Advanced Technology의 소프트웨어 엔지니어인 Mathew Nelson의 창작품이다. 우선 IBM alphaWorks Robocode 페이지로 간다. 여기에 Robocode 시스템의 최신 실행 파일들이 있다. 일단 설치에 필요한 모든 파일을 스스로 가지고 있는 배포판을 다운로드받은 후 다음 명령어를 사용하여 여러분의 시스템에 패키지를 설치한다. (물론 여러분 머신에 Java VM (JDK 1.3.x)가 미리 설치되어 있다고 가정한다.)



java -jar robocode-setup.jar

설치 과정 동안 Robocode는 로봇 컴파일을 위해 이 외부 자바 VM을 사용할 것인지를 물어 볼 것이다. 다른 대안으로는 Robocode 배포판의 일부분으로 제공되는 Jikes 컴파일러가 있다.

설치가 끝나면 쉘 스크립트 (robocode.sh), 배치 파일 (robocode.bat), 혹은 데스크탑의 아이콘에서 Robocode 시스템을 구동시킬 수 있다. 이 지점에서 전투장이 등장할 것이다. 여기에서 여러분은 로봇 편집기와 메뉴 방식의 컴파일러를 호출할 수 있다.




위로


Robocode 시스템의 구성 요소

Robocode를 활성화시키면 여러분은 두 개의 상호 관련된 GUI 창을 보게 될 것인데, 이들이 Robocode의 IDE가 된다.

  • 전투장
  • 로봇 편집기

그림 1은 작동중인 전투장과 로봇 편집기이다.



그림 1. Robocode IDE
Robocode IDE

전투장은 로봇간의 전투가 이루어지는 곳이다. 주 시뮬레이션 엔진이 들어 있으며, 여러분이 새로운, 혹은 기존의 전투를 생성하고 저장하고 열 수 있게 해준다. 여기에 있는 제어 장치들을 사용해 전쟁을 일시 중지, 재개, 종료시킬 수 있고 개별 로봇을 부수거나 있는 로봇의 통계를 얻을 수 있다. 또한 이 화면에서 로봇 편집기를 활성화시킬 수도 있다.

로봇 편집기는 로봇을 만드는 자바 소스 파일을 편집하기 위한 커스터마이즈된 텍스트 편집기이다. 로봇 편집기는 자바 컴파일러 (로봇 코드를 컴파일하기 위한)와 메뉴 내의 커스터마이즈된 로봇 packager를 통합시킨다. 로봇 편집기로 만들어지고 성공적으로 컴파일된 로봇은 모두 전투장에 나갈 준비 위치에 있게 된다.

Robocode의 로봇은 한 개 이상의 자바 클래스로 구성되어 있다. 이 클래스들은 JAR 패키지에 저장될 수 있다. Robocode의 최신 버전은 이를 위해 전쟁터 GUI 창에서 활성화될 수 있는 "Robot Packager"를 제공한다.




위로


Robocode 로봇의 해부

Robocode 로봇은 그래픽으로 된 탱크이다. 그림 2는 전형적인 Robocode 로봇을 보여준다.



그림 2. Robocode 로봇의 해부
Robocode robot

로봇은 회전총을 가지고 있고 총의 윗부분에는 회전 레이더가 있다. 로봇의 차량, 총 및 레이더는 모두 독립적으로 회전할 수 있다. 어느 때라도 로봇의 차량, 총, 레이더는 다른 방향으로 돌려질 수 있다. 기본적으로 이 아이템들은 차량의 이동 방향으로 정렬되어 있다.




위로


로봇 명령어

Robocode 로봇에 대한 명령어 세트는 모두 Robocode API의 javadoc에 문서화되어 있다. 여러분은 이들을 robocode.Robot 클래스의 public 메소드로 발견할 것이다. 이 섹션에서는 사용 가능한 명령어 각각을 카테고리별로 살펴 보자.




위로


로봇, 총, 레이더 움직이기

로봇과 그 장비를 움직이게 하기 위한 기본 명령어로 시작해보자.

  • turnRight(double degree)와 turnLeft(double degree): 지정된 각도로 로봇을 돌린다.

  • ahead(double distance)back(double distance): 지정된 픽셀 거리로 로봇을 이동시킨다. 이 두 메소드들은 로봇이 벽이나 다른 로봇에 부딪혔을 때 완료된다.

  • turnGunRight(double degree)와 turnGunLeft(double degree): 차량의 방향과 상관 없이 총의 방향을 돌린다.

  • turnRadarRight(double degree)turnRadarLeft(double degree): 총과 차량의 방향에 상관 없이 총 위의 레이더를 돌린다.

이 명령어들은 완성될 때까지 프로그램에 제어 장치를 반환하지 않을 것이다. 또한 다음 메소드들을 호출하여 달리 표시하지 않는다면 차량이 돌려졌을 때 총 (그리고 레이더)의 방향 역시 움직일 것이다.

  • setAdjustGunForRobotTurn(boolean flag): 플래그가 참으로 설정되면 차량이 움직이는 동안 총도 동일한 방향으로 움직인다.

  • setAdjustRadarForRobotTurn(boolean flag): 플래그가 참으로 설정되면 차량 (그리고 총)이 움직이는 동안 레이더도 동일한 방향으로 움직인다.

  • setAdjustRadarForGunTurn(boolean flag): 플래그가 참으로 설정되면 총이 움직이는 동안 레이더도 동일한 방향으로 움직인다. 또한 setAdjustRadarForRobotTurn(true)가 호출된 것처럼 행동할 것이다.



위로


로봇에 대한 정보 얻기

로봇에 관한 정보를 얻기 위한 많은 메소드가 존재한다. 다음은 빈번하게 사용되는 메소드 호출의 간단한 목록이다.

  • getX()getY() 로봇의 현재 좌표를 보여 준다.

  • getHeading(), getGunHeading()getRadarHeading() 차량, 총, 레이더의 현재 방향을 각도로 알려준다.

  • getBattleFieldWidth()getBattleFieldHeight() 현재 승부가 벌어지는 전투장의 크기



위로


발사 명령어

로봇과 로봇의 무기를 움직이는 방법을 터득했다면, 발포와 피해 제어 작업을 고려해야 한다. 각 로봇은 기본적인 "에너지 레벨"을 가지고 출발하는데, 에너지 레벨이 0으로 떨어지면 파괴된 것으로 간주된다. 발포할 때 로봇은 3단위까지의 에너지를 쓸 수 있다. 총알에 더 많은 에너지가 장착될수록 상대 로봇에게 더 많은 해를 끼칠 수 있다. fire(double power)와 fireBullet(double power)은 특정 에너지를 가진 총알을 발사하는데 사용된다(발포력). 호출의 fireBullet() 버전은 고급 로봇에서 사용될 수 있는 robocode.Bullet 객체에 대한 참조를 반환한다.




위로


이벤트

로봇이 움직이거나 방향을 돌릴 때마다 레이더도 항상 구동되어 있고, 로봇이 사정 거리 안에 있는 로봇을 추적하면 이벤트가 유발된다. 로봇 창조자로서 여러분은 전투 중에 일어나는 다양한 이벤트에 대한 처리를 선택할 수 있다. 기본 Robot 클래스는 이 이벤트 모두에 대한 기본 처리자를 가지고 있다. 그러나 여러분은 이러한 "아무 것도 하지 않는다"라는 기본 처리자들을 오버라이드하여 여러분 자신의 액션을 구현할 수 있다. 다음은 자주 사용되는 이벤트들이다.

  • ScannedRobotEvent: onScannedRobot()메소드를 오버라이드하여 ScannedRobotEvent를 처리한다. 이 메소드는 레이더가 로봇을 추적했을 때 호출된다.

  • HitByBulletEvent : onHitByBullet()메소드를 오버라이드하여 HitByBulletEvent를 처리한다. 이 메소드는 로봇이 총알을 맞았을 때 호출된다.

  • HitRobotEvent : onHitRobot() 메소드를 오버라이드하여 HitRobotEvent를 처리한다. 이 메소드는 여러분의 로봇이 다른 로봇을 쏘았을 때 호출된다.

  • HitWallEvent : onHitWall() 메소드를 오버라이드하여 HitWallEvent를 처리한다. 이 메소드는 여러분의 로봇이 벽을 쏘았을 때 호출된다.

다소 복잡한 로봇을 만들기 위해 우리가 알아야 할 것은 이것 뿐이다.여러분은 나머지 Robocode API를 Javadoc에서 볼 수 있는데, 전투장의 헬프 메뉴나 로봇 편집기의 헬프 메뉴에서 접근할 수 있다.

이제 우리 지식을 활용해 볼 시간이다.




위로


로봇 만들기

로봇 편집기는 로봇을 제어하기 위해 작성해야 하는 자바 코드를 표시할 것이다. Listing 1에 여러분이 볼 코드의 예가 나와 있다.



Listing 1. Robocode가 생성한 로봇 코드
package dw;
import robocode.*;

/**
 * DWStraight - a robot by (developerWorks)
 */
public class DWStraight extends Robot
{
	...  // <<Area 1>>
	/**
	 * run: DWStraight's default behavior
	 */
	public void run() {
		... // <<Area 2>>
		while(true) {
		... // <<Area 3>>
		}
	}
      ... // <<Area 4>>
	public void onScannedRobot(ScannedRobotEvent e) {
		fire(1);
	}
}

하이라이트된 부분은 로봇을 제어하기 위해 우리가 코드를 추가할 수 있는 부분이다.

여기에 우리는 클래스 범위 변수를 선언하고 그 값을 설정할 수 있다. 이들은 로봇의 run() 메소드 뿐 아니라 여러분이 만드는 다른 모든 헬퍼 메소드에서 사용가능할 것이다.

run() 메소드는 로봇의 일생을 개시하기 위해 전투 관리자에 의해 호출된다. 보통 두개의 영역 (Listing 1의 Area 2와 Area3으로 지정된 부분)으로 구성되는데, 여러분은 여기에 코드를 추가할 수 있다. Area 2에는 로봇 인스턴스당 한 번만 실행될 코드를 둔다. 이것은 반복적인 액션을 시작하기 전에 로봇을 사전 결정된 상태로 만드는데 종종 사용된다.

Area 3은 일반적인 run() 메소드 구현의 두번째 부분으로, 여기에 무한 while 루프 내에서 로봇이 참여할 반복 액션을 프로그래밍한다.

Area 4
로봇이 자신의 run()로직에서 사용할 헬퍼 메소드를 추가하는 곳이다. 또한 여러분이 오러라이드하고 싶은 이벤트 핸들러를 추가하는 곳이기도 하다. 예를 들어, Listing 1의 코드는 ScannedRobot 이벤트를 처리하고 로봇이 레이더에 의해 추적될 때마다 그 로봇에 바로 발사하게 한다.

우리의 첫번째 로봇인 DWStraight에 대해 Listing 2에 (빨간색으로) 나와 있는 것 같이 코드를 업데이트 것이다.



Listing 2. DWStraight 로봇 코드 추가
package dw;
import robocode.*;

public class DWStraight extends Robot
{
	public void run() {
		turnLeft(getHeading());
		while(true) {
			ahead(1000);
			turnRight(90);
			
		}
	}
      
	public void onScannedRobot(ScannedRobotEvent e) {
		fire(1);
	}
	public void onHitByBullet(HitByBulletEvent e) {
		turnLeft(180);
	}
      
}

다음은 이 첫번째 로봇이 영역별로 수행할 일들이다.

Area 2
로봇을 알려진 상태로 만들기 위해, turnLeft(getHeading())를 사용해 로봇이 0도를 향하도록 돌린다.

이 반복적인 섹션에서는 ahead(1000)을 사용해 갈 수 있는 한 멀리 로봇을 앞으로 움직인다. 로봇은 벽이나 다른 로봇과 부딪히면 멈출 것이다. 그러면 우리는 turnRight(90)을 써서 오른쪽으로 방향을 돌린다. 이것이 반복되면 로봇은 기본적으로 시계 방향으로 벽을 따라가게 될 것이다.

여기에서는 자동 생성된 ScannedRobot 이벤트를 처리하고 발견된 로봇에 직접 발포하는 것에 덧붙여, HitByBullet 이벤트를 추적하고 총에 맞을 때마다 180도로 돈다 (시계 방향과 시계 반대 방향으로 교대로).




위로


로봇 컴파일 및 테스트하기



그림 3. 새로운 전투 대화창 T
New Battle dialog

다른 로봇을 코딩 할 준비가 되면 참고 자료에 있는 코드 배포판과 함께 제공되는 dw.DWRotater 로봇을 보기 바란다. 이 로봇은 기본적으로 다음과 같은 기능을 가지고 있다.

  • 전쟁터의 중앙으로 움직인다.
  • 로봇을 추적할 때까지 총을 계속 회전시킨다.
  • 추적된 로봇 바로 앞에 발포한다. 발포할 때마다 다른 각도로 시도한다.
  • 다른 로봇이 쏜 총에 맞을 때마다 빠르게 앞뒤로 움직인다.

코드는 직접적이다. 우리는 여기에서 이 코드를 분석하지 않겠지만, 여러분이 분석해 볼 것을 권한다. Robocode와 함께 포함된 샘플 패키지는 여러 다른 로봇에 대한 코드도 제공한다.

추가적인 로봇 지원 클래스

로봇 설계에 좀 더 능숙해지면 여러분이 로봇에 포함시킬 수 있는 코드가 상당히 늘어날 것이다. 코드를 처리하기 위한 모듈화된 방식은 이것을 개별적인 자바 클래스들로 분해하고 packager를 사용해 이들을 하나의 패키지 (JAR 파일)로 번들링하여 여러분의 로봇 배포판의 일부로 포함시킨다. Robocode는 자신의 로봇 디렉토리에 들어 있는 패키지 내의 로봇 클래스들을 자동으로 발견할 것이다.

기타 로봇 하위 클래스들

누구든지 Robot의 하위 클래스를 만들 수 있고 로봇 개발에 사용될 수 있는 새로운 기능을 추가할 수 있다. Robocode는 AdvancedRobot이라는 Robot 하위 클래스를 제공하는데, 이 클래스는 비동기적인 API 호출을 가능케 한다. AdvancedRobot에 대한 설명은 이 글의 범위를 벗어나지만, 여러분이 기본적인 Robot 클래스의 작업에 익숙해지면 이 고급 클래스를 시험해 볼 것을 권한다.

Robocode를 설계한 동기

나는 Robocode 창시자인 Mathew Nelson에게 Robocode를 만든 원래 동기에 대해 물어 보았다. "Robocode를 개발한 동기 중 일부는 '자바는 느리다', '자바로는 게임을 작성할 수 없다'와 같은 말이 더 이상 진실이 아니라는 것을 세상에 입증하는 것이었다. 나는 목적을 달성했다고 생각한다."




위로


전쟁 시뮬레이터의 아키텍처

Robocode의 무대 뒤를 살펴보면 고성능 (사실적인 스피드로 전투를 렌더링하기 위해)과 유연성 (어려움 없이 복잡한 로봇 로직 작성을 가능케 하는)을 가진 정교한 시뮬레이션 엔진이 있다. 시뮬레이션 엔진의 아키텍처에 관한 내부 정보를 제공한 Robocode 창시자 Mathew Nelson애게 특히 감사드린다.

자바 플랫폼을 응용하는 설계

그림 4에 나와 있는 이 시뮬레이션 엔진은 대부분의 현대 Java VM이 제공하는 비선점형 스레딩을 응용하고, 이를 JDK GUI와 2D 그래픽 라이브러리가 제공하는 렌더링 기능과 결합시킨다.



그림 4. Robocode 시뮬레이션 엔진 아키텍처
Simulation Engine

시뮬레이션되고 있는 각 로봇이 자체적인 자바 스레드 상에 있고 적용할 수 있는 곳마다 VM의 원시 스레드 매핑을 응용한다는 사실에 유의한다. 전투 관리자 스레드는 시스템의 제어자이다. 시뮬레이션을 조정하고 그래픽 렌더링 하위시스템을 움직인다. 그랙픽 렌더링 하위 시스템 자체가 Java 2D와 AWT에 기반하고 있다.

느슨한 스레드 결합

공유된 자원에서 발생할 수 있는 잠재적인 (그리하여 시뮬레이션 엔진을 교착 상태에 빠지게 하거나 질식시키는) 문제들을 완화하기 위해 전투 관리자 스레드와 로봇 스레드간에 매우 느슨한 결합이 필요하다. 이러한 느슨한 결합을 구현하려면 각 로봇 스레드에 자체적인 이벤트 큐를 주어야 한다. 그러면 로봇의 이벤트들이 로봇의 자체 스레드에 보내져 처리된다. 이러한 스레드당 큐잉은 전투 관리자 스레드와 로봇 스레드 사이에, 그리고 로봇 스레드들 사이에 발생할 수 있는 충돌을 효과적으로 없애준다.




위로


Robocode 내부

여러분은 Robocode 시뮬레이터 엔진을 실행시에 한 세트의 플러그인 (사용자 정의 로봇)을 취하는 시뮬레이터 프로그램으로 볼 수 있다. 이 플러그인 세트는 제공되는 API (robocode.Robot 클래스의 메소드)를 사용할 수 있다. 물리적으로 각 로봇은 독립적인 자바 스레드이고, run() 메소드는 스레드에서 실행될 로직을 가지고 있다.

어느 때라도 로봇 스레드는 자신의 부모인 robocoode.Robot 클래스가 제공하는 API를 호출할 수 있으며, 이 API는 보통 Object.wait() 호출을 통해 로봇 스레드를 블록화할 것이다.




위로


전투 관리자 스레드

전투 관리자 스레드는 전쟁터의 로봇, 총알 및 렌더링을 관리한다. 시뮬레이션상의 "시간 개념"은 전투장에 렌더링되는 프레임의 수에 의해 정해진다. 실제 프레임율은 사용자에 의해 조정 가능하다.

일반적인 승부에서 전투 관리자는 각 로봇 스레드를 깨운 후 로봇이 준비를 갖출 때까지 (즉 블록화 작업을 수행하는 API를 다시 호출하는 것) 기다린다. 이 대기 시간은 보통 몇 만분의 1초에 지나지 않으며, 오늘날의 일반적인 시스템 속도에서 전략과 계산을 수행하는데 가장 복잡한 로봇이라도 1, 2 밀리세컨드 밖에 사용하지 않는다.

다음은 전투 관리자가 수행하는 로직의 의사 코드이다.



Listing 3.전투 관리자의 의사 코드
while (round is not over) do
   call the rendering subsystem to draw robots, bullets, explosions
   for  each robot do
       wake up the robot
       wait for it to make a blocking call, up to a max time interval
   end for
   clear all robot event queue
   move bullets, and generate event into robots' event queue if applicable
   move robots, and generate event into robots' event queue if applicable
   do battle housekeeping and generate event into robots' event queue
         if applicable
   delay for frame rate if necessary
end do

내부 for 루프에서 전투 관리자 스레드가 최대 시간 이상으로는 기다리지 않는다는 데 유의한다. (보통 애플리케이션 로직 에러나 무한 루프 때문에) 로봇 스레드가 정해진 시간 내에 블록화 API를 호출하지 않는다면 전투 관리자 스레드는 전투를 진행시킬 것이다. 고급 로봇들에게 통지하기 위해 SkippedTurnEvent가 로봇의 이벤트 큐에 생성된다.

교체될 렌더링 하위 시스템

현 구현판의 렌더링 하위 시스템은 간단히 전투 관리자로부터 명령문을 취해 전쟁터를 렌더링하는 AWT와 Java 2D 스레드이다. 향후 개정판에서는 이것이 교체될 것으로 예측된다. (예를 들어, 3-D renderer로). 현 구현판에서는 Robocode 애플리케이션이 최소화될 때마다 렌더링이 비활성화되어 시뮬레이션이 더 신속하게 진행되도록 한다.




위로


Robocode의 미래

Mathew Nelson은 alphaWorks Robocode 사이트 (참고 자료)에 있는 토론 그룹을 통해 Robocode 사용자 그룹과 밀접하게 피드백을 주고받고 있다. 이 피드백의 많은 부분이 실제 코드에 반영된다. Mathew가 계획하고 있는 향후 기능 개선은 다음과 같다.

  • 다른 객체와 장애물을 가진 사용자 정의 전투장 지도
  • 팀 기반의 전투
  • 토너먼트나 리그에 대한 통합된 지원
  • 탱크 몸체/총/레이더/무기의 스타일을 사용자가 선택할 수 있도록 함



위로


멈출수 없는 Robocode의 힘

최근이라 할 수 있는 2001년 7월 12일 선보인 프로젝트로서 Robocode의 명성은 괄목할만하다. 이용 가능한 최신 버전이 아직 1.0도 되지 않았지만 (이 글을 작성한 시점에서는 v. 0.98.2이다), 이미 전 세계 대학 캠퍼스와 기업 컴퓨터에서 매우 인기 있는 오락이 되고 있다. 사람들이 자신이 만든 로봇을 가지고 인터넷상에서 서로 싸우는 Robocode 리그 (즉 roboleagues)들이 빠른 속도로 등장하고 있다. 대학 교수들은 Robocode의 교육적 특성을 간파하고 컴퓨터 과학 커리큘럼에 포함시키고 있다. Robocode 사용자 그룹, 토론 목록, FAQ, 교재 및 Webring들을 인터넷상에서 많이 발견할 수 있다.

분명히 Robocode는 학생들과 밤에 일하는 엔지니어들에게 창조적 에너지를 발산하고 세계를 정복하는 환상을 채워주는 간단하고 재미있고 비위협적이지만 경쟁적인 방법을 제공하면서, 대중적인 게임과 교육 분야간의 틈을 메꾸었다고 할 수 있다.




위로


참고자료

반응형
댓글