Advanced Robot
자, 이제 더욱 내 로봇을 업그레이드 시켜야 할 차례입니다. 지난달에 배운 기본적인 로보코드 소스를 가지고 자신의 로봇을 스스로 많이 발전시켰나요? 만약 지난 달에 기사에 소개한 내용만 가지고 자신의 로봇을 좀더 좋게 만들어 보려고 했던 분들이라면, 곧 한계에 부딪히고 말았을 것입니다. 아직 못 느낀 분들이라면 이제부터 설명할 내용들을 한 번 눈여겨 보세요.
먼저 <리스트 2>를 봅시다.
<리스트2>
package myrobot;
import robocode.*;
public class MyFirstRobot extends Robot
{
public void run()
{
while(true)
{
ahead(100);
turnRight(90);
turnGunRight(360);
}
}
public void onScannedRobot(ScannedRobotEvent e)
{
fire(1);
}
public void onHitByBullet(HitByBulletEvent e)
{
turnLeft(90-e.getBearing());
}
}
아주 간단한 소스지요? 앞으로 100 픽셀 갔다가 오른쪽으로 90도 회전하고, 총을 360도 회전하는 소스입니다. 그런데 이 로봇에는 문제가 있습니다. 앞으로 100픽셀을 가고, 오른쪽으로 90도 회전하고 나서야 총을 360도 회전한다는 문제입니다. 결국 100픽셀 전진하는 동안은 적을 전혀 찾지 않는다는 말이고, 그만큼 공격할 시간이 줄어든다는 결론입니다. 이래서야 아무리 프로그래밍을 잘한다 하더라도 똑똑한 로봇을 만들기는 애초에 틀린 노릇이지요.
이런 문제를 해결할 수 있는 것이 Advance Robot입니다. 일단 결론을 먼저 말씀드리면,
<리스트 2>를 <리스트 3>처럼 수정하면 로봇은 조금 더 똑똑해집니다. <리스트 3>의 내용을 간단 히 분석해 보면, 로봇은 앞으로 100픽셀 가는 것과, 오른쪽으로 90도 회전하는 것, 그리고 총을 360도 회전하는 것을 모두 동시에 하게 됩니다. 그럼 로봇은 어떻게 움직이게 될까요? 앞쪽으로 원을 그리며 움직이면서 동시에 총도 회전하게 되는 것입니다.
<리스트 3>
package myrobot;
import robocode.*;
public class MyFirstRobot extends AdvancedRobot
{
public void run()
{
while(true)
{
setAhead(100);
setTurnRight(90);
setTurnGunRight(360);
execute();
}
}
public void onScannedRobot(ScannedRobotEvent e)
{
fire(1);
}
public void onHitByBullet(HitByBulletEvent e)
{
turnLeft(90-e.getBearing());
}
}
상속
<리스트2>를 MyFirstRobot1 이라고 하고, <리스트 3>을 MyFirstRobot2라고 합시다. 이 두 개의 소스에서 차이점이 몇 군데 있지만 가장 중요한 차이점은 다음 부분입니다.
◆리스트 2 : public class MyFistRobot1 extends Robot
◆리스트 3 : public class MyFistRobot2 extends AdvancedRobot
여기서 자바 키워드인 extends 뒤에 나오는 것이 상속(inheritance)을 받는 클래스 이름입니다. <리스트2>로 예를 들면 우리가 마든 MyFirstRobot 클래스는 Robot 클래스를 상속받는 다는 뜻입니다. 이때 MyFirstRobot은 Robot 클래스의 하위 클래스(subclass)가 되는 것이지요.
Robot 클래스에는 많은 메쏘들이 있습니다. (C를 비솟한 여러언어에서 함수라고 불리는 것에 해당합니다.) ahead()와 같은 메쏘들이 바로 Robot 클래스에서 제공하는 메쏘드들이지요. 이런 메쏘드들은 프로그래머가 모두 처음부터 끝까지 완전히 구현하려면 굉장히 많은 시간이 걸릴 것입니다. 그래서 이미 만들어진 메쏘드들은 편리하게 불러 쓰기 위해 상속을 받습니다. 송속의 개념은 다른 자바 책들을 이요해서 좀 더 확실하게 배우기 바랍니다.
어째뜬 예전에 만든 우리의 로봇은 <리스트 2>처럼 Robot 클래스를 상속받아, 그 메쏘드들을 불러서 사용합니다. 그런데 이번에 선보인 <리스트 3>의 로봇은 AdvancedRobot이라는 클래스를 상속받아 사용합니다. 바로 이것이 큰 차이입니다.
AdvancedRobot이라는 클래스는 Robot 클래스를 상속받아 좀더 많은 메쏘드들을 추가로 구현해 놓은 클래스입니다. AdvancedRobot 클래스는 Robot 클래스를 확장한 것이기 때문에, 이 클래스를 상속받아 사용하면 Robot 클래스만 상속받아 사용하는 것보다 좀 더 많은 메쏘들을 사용할 수 있습니다. 그 중 하나가 바로 setAhead()와 같은 메쏘들이지요.
Blocking 메쏘드와 non-blocking 메쏘드
이제 Robot 클래스를 상속받아 사용하는 것과 AdvancedRobot 클래스를 상속받아 사용하는 것의 차이를 이해했으리라 믿습니다.
한 마디로 AdvancedRobot 클래스를 상속해서 사용하면, Robot 클래스를 상속받아 사용하는 것보다 좀 더 많은 메쏘드들을 이용할수 있습니다. 여기서 앞서 간단히 설명한 소스들을 다시 한 번 봅시다. 아니 소스만 보지 말고, 이 두 개의 소스를 직접 입력해서 각각 실행해 보세요. <리스트2>의 로봇과 <리스트 3>의 로봇은 상당히 다른 움직임을 보여줍니다. 대체 AdvancedRovot 클래스에서는 어떤 메쏘드들을 제공하기에 이렇게 다른 행동이 가능할까요?
간단히 말해서 Robot 클래스에서 제공하는 메쏘드들은 blocking 메쏘드들이고, AdvancedRobot 클래스에 제공하는 확장 메쏘드들은 non-blocking 메쏘드들입니다. (blocking 이라는 용어를 적절히 한글화 할 수 없어서 그냥 영어로 쓰게 된 점은 양해를 바랍니다. 어설프게 한글화를 시도했다가는 오히려 개념 설명에 방해만 될 뿐이므로, 차라리 영어로 된 용어를 그대로 쓰는 쪽을 택했습니다.)
여기서 blocking 이라는 용어는 배구에서의 blocking을 생각하면 쉽게 이해할 수 있습니다.
자, 이제 <리스트 2>에서 제일 중요한 메쏘드인 run() 메쏘드안의 내용을 살펴보도록 합시다. 다음에 나와 있는 메쏘드들은 이미 여러분에게 친숙한 애용들입니다. 100픽셀 앞으로 갔다가 오른쪽으로 90도 회전하고, 그 다음에 총을 360도 회전하는 것이지요. 이 메쏘들이 모두 blocking 메쏘드들입니다. 그리고 Robot 클래스에서 제공하는 로봇의 움직임 모두 blocking 메쏘드들입니다.
ahead(100);
turnRight(90);
trunGunRight(90);
먼저 로봇은 전투가 시작되면 ahead(100) 명령어를 받고, 앞으로 100픽셀 전진합니다. 뒤에 오른쪽으로 회전하고 총을 회전하는 메쏘드들이 있지만, ahead()라는 메쏘드는 이 메쏘드에서 지정된 행동을 완전히 완료하기 전까지는 다음 명령어를 수행하지 않도록 되어 있습니다. ahead() 메쏘드가 다른 메쏘드의 실행을 막고 있다는 말입니다.
이제 100픽셀 전진이 끝나면 ahead(100) 명령어는 완전히 임무를 완수한 것이 됩니다. 그래서 다음 명령어인 turnRight(90) 이 실행되지요. 이것 또한 blocking 메쏘드라서, 90도 회전이라는 동작이 완료되기 전까지는 다음 명령어로 컨트롤을 넘겨주지 않습니다. 따라서 90도 회전이 완전히 완료되면, 다음 명령어인 trunGunRight(360)이 실행됩니다.
이제 AdvancedRobot 클래스에서 제공하는 non-blocking 메쏘드를 이용한 <리스트 3>을 봅시다.
setAhead(100);
setTurnRight(90);
setTurnGunRight(360);
메쏘드 이름이 Robot 클래스가 제공하는 blocking 메쏘드들과 비슷하지요?
Robot 클래스가 제공하는 메쏘드들의 첫 문자를 대문자로 바꾸고, 그 앞에 set을 붙였다는 점만 다릅니다. 이런 메쏘드들은 모두 AdvancedRobot 클래스가 제공하는 non-blocking 메쏘드들입니다.
일단 여기서는 앞으로 100 픽셀을 가도록 설정해 놓았습니다. 그리고 오른쪽으로 90도 회전하도록 설정을 해놓고, 총을 360도 회전하도록 설정해 놓았습니다. 여기서 excute() 메쏘드가 없다면 아무런 움직임을 보이지 않습니다. 단지 그렇게 움직이도록 설정(set)만 해놓은 상태이기 때문입니다.
excute() 메쏘드는 blocking call 메쏘드 중 하나인데. 이런 메쏘드를 호출해야 앞서 설정한 행동들을 실제로 수행하게 됩니다. 따라서 excute() 메쏘드가 호출될 때, 로봇은 비로소 움직이게 됩니다. 어떻게 움직일까요? 앞서 설정한 내용들을 hd시에 수행하게 됩니다. 또 총을 360도 회전하는 행동을 모두 동시에 하게 됩니다.
다음에 Robot 클래스가 제공하는 blocking 메쏘드들과, AdvancedRobot 클래스가 제공하는 non-blocking 메쏘드들의 정리를 해놓았습니다.
이름도 비슷하고 의미도 비슷하니깐 non-blocking 메쏘드들을 사용법에 맞게만 잘 이용하면 됩니다. 이제 Robot 클래스를 상속받아 사용하던 것을 AdvancedRobot 클래스로 바꾸고 좀더 좋은 로봇을 만들어 보기 바랍니다.
◆ turnRight : setTurnRight
◆ turnLeft : setTurnLeft
◆ turnGunRight : setTurnGunRight
◆ turnGunLeft : setTurnGunLeft
◆ turnRadarRight : setTurnRadarRight
◆ turnRadarLeft : setTurnRadarLeft
◆ ahead : setAhead
◆ back : setBack
참, 여기서 주의할 점이 있습니다. AdvancedRobot 클래스를 상속받아 사용하면 Robot 클래스가 제공하는 blocking 메쏘드들은 사용할 수 없을까요? 당연히 사용할 수 있습니다. 왜냐하면 AdvancedRobot은 Robot 클래스를 상속받은 클래스이기 때문에, Robot 클래스가 제공하는 메쏘드들도 모두 사용할 수 있습니다. 거기다 덧붙여 AdvancedRobot 클래스가 제공하는 메쏘드들은 추가로 사용할 수 있는 것입니다. 따라서 AdvancedRobot 클래스를 상속받아 사용하는 것이 훨씬 이익이겠지요.