IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  Java technology | Open source  >

CodeRally 作ってみよう!

ラリーカー作成のチュートリアル

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません


レベル: 初級

developerWorks Japan, 編集室, IBM

2004年 8月 13日

CodeRallyはJavaプログラミングによってラリーカーの動作を2次元グリッド上でシミュレートさせて得点を競うプログラミングゲームです。ここでは、ラリーカーを作成する主要API(Application Programing Interface)をチュートリアル式にご紹介します。ここでご紹介するAPIは全てではありません。基本的なAPIの使用方法を習得し、あなたの独創的な戦略・戦術をプログラムとしてインプリメントできるよう挑戦してみてください。

エンジンとプログラムの構造を理解する

ラリーカーの作成は、RallyCar.javaを編集します。Eclipseを起動し、RallyCar.javaを開いてください。RallCar.javaには1つのクラスと5つのメソッドが書かれています。RallyCarクラスはCarクラスをextends(継承)しています。すなわち、CarクラスはRallyCarクラスの親クラス(Supper Class)になり、親クラスであるCarクラスのフィールドやメソッドをRallyCarクラスは全て使用することができます。


図1.ラリーカーの編集
図1.ラリーカーの編集

RallyCarクラスの各メソッドについて説明します。RallyCarクラスの詳細については、APIリファレンスをご覧ください。

A ラリーカーの名前をCodeRallyのエンジンに返すメソッドです。初期値は「No Name」に設定されています。
B チーム名をCodeRallyのエンジンに返すメソッドです。初期値は「No School」に設定されています。
C

ラリーカーの色をCodeRallyエンジンに返します。初期値はCarクラスのフィールドとして定義されている「CAR_BLUE」が設定されています。他、「CAR_ORANGLE」、「CAR_PERPLE」、「CAR_RED」、「CAR_TEAL」、「CAR_YELLOW」がフィールドとして定義されています。

D レースが始まりラリーカーがトラック上に配置されるまでの間にCodeRallyのエンジンが実行します。レース前にフィールド上の情報収集などを行うことができますが、1秒以上時間のかかるコードは無視されます。1秒間にどれだけの情報収集・データ加工などができるか挑戦してみてください。
E レースがスタートし、ラリーカーが動き出すと、CodeRallyエンジンはmoveメソッドを1クロックチック毎に実行します。このとき、エンジンはラリーカーにmoveメソッドの4つの引数として前の移動サイクル中に起こったことについて情報を与えます。これらのパラメータは、(1) 前回呼び出されたときにmove()メソッドが使用した時間(ミリ秒)、(2) 前のサイクル中に車が壁に衝突したかどうか、(3) 前のサイクル中に他の車と衝突したかどうか、および (4) 前のサイクル中に他の車からスペアタイヤをぶつけられたかどうかを指定します。最初のパラメータは整数型、2番目はブール型、3番目と4番目のパラメータは該当する車のICar参照(他車かタイヤによる衝突が起きなかった場合はヌル)です。最初のパラメータは、移動の完了までに許される最大時間を超える恐れがないかどうかを判断するのに役立ちます。

RallyCarクラスを編集しないままプライベートトラック上にエントリーした場合、自車は止まったまま動かない状態でした。それでは、ラリーカーを動かしてみましょう。




上に戻る


ラリーカーの直進

ラリーカーを移動させるにはスロットル値を変化させます。スロットルを変化させることによりスピードが増します。スロットル値は100(MAX_THROTTLE)?-50(MIN_THROTTLE)まで設定できます。


図2.ラリーカーのスロットル設定
ラリーカーのスロットル設定

スロットル値を変えるには、親クラスであるCarクラスのsetThrottle(int throttle)メソッドを使用します。MAX_THROTTLEはCarクラスでint型フィールド(変数)として100に設定されていますのでsetThrottleの引数にMAX_THROTTLEを設定しましょう。(リスト1.スロットルの設定)
File > Save メニュー項目を選択してファイルを保存します。(test)をクリックして車がプライベートトラック上で前進するか確認してください。


リスト1.スロットルの設定
                
...
public void  move(int lastMoveTime, boolean hitWall, ICar collidedWithCar, ICar hitBySpareTire) {
    // put implementation here
    // スロットル(アクセル)の設定
    setThrottle(MAX_THROTTLE);
	
}
...




上に戻る


ステアリング操作

ラリーカーを動かすことはできましたが、このままでは目的の位置まで移動するにはラリーカーの向きを変えて進む必要があります。車の向きを変えるためにはステアリングを操作します。レース開始時のステアリングは直進方向0に設定されています。ステアリングを左、右に変化させて車の進行方向を変えることができます。ステアリング値は左右-10(MAX_STEER_LEFT)から10(MAX_STEER_RIGHT)に設定できます。


図3.ラリーカーのステアリング設定
ラリーカーのステアリング設定

ここで、ラリーカーを右方向へ動かしてみましょう。ステアリングを設定するには、CarクラスのsetSteeringSetting(int steering)メソッドを使用します。引数はステアリング値を設定します。ステアリング値はCarクラスでint型フィールド(変数)として10に設定されているMAX_STEER_RIGHTを設定します。(リスト2.ステアリングの設定)
File > Save メニュー項目を選択してファイルを保存します。(test)をクリックして車がプライベートトラック上で右方向に回転するか確認してください。


リスト2.ステアリングの設定
                
import com.ibm.rally.Car;
import com.ibm.rally.ICar;
...
public void move(int lastMoveTime, boolean hitWall, ICar collidedWithCar, ICar hitBySpareTire) {
    // put implementation here
				// ステアリング(ハンドル)を右に切る
    setSteeringSetting(MAX_STEER_RIGHT);
// スロットル(アクセル)の設定
    setThrottle(MAX_THROTTLE);
}
...




上に戻る


チェックポイントの通過

得点するためにはレーストラック上のチェックポイントを通過する必要があります。レーストラック上のチェックポイントを見つけるにはCarクラスのgetCheckpoints()メソッドを使用します。getCheckpoints()メソッドの戻り値はIObjectクラス型の配列リストとして得ることができます。チェックポイントはレーストラック上にランダムに複数設置されますので、得られる配列のインデックスをプログラムで取得する必要があります。ここでは、1カ所目のチェックポイントに向かってラリーカーが進むようにします。

CodeRallyのトラックは、左上を原点として、X方向1010単位、Y方向580単位の2次元の世界です。トラックの周囲には壁があり、車はこの壁を越えることはできません。ラリーカーとオブジェクトの位置関係は、CarクラスのgetHeadingTo(IObject obj)で得ることができます。引数には目標とするオブジェクトをIObjectクラス型で設定します。戻り値は、トラックのY軸垂直上向き方向を0度としてラリーカーを中心にオブジェクトへの角度をint型で得ることができます。角度は0度から359度までの正数であり、時計回りに増えます。このメソッドを使用することにより、ラリーカーから見てオブジェクトが何度方向にあるかがわかります。次に、ラリーカーをオブジェクトの方向に傾けるため、現在のラリーカーが何度の方向を向いているのかを調べるため、CarクラスのgetHeading()メソッドを使用します。getHeading()メソッドは引数を取らず、戻り値はラリーカーが座標上でどの方向を向いているのかを表すint型の角度を返します。ラリーカーを中心としたオブジェクトの方向(getHeadingTo()の戻り値)とラリーカーの向き(getHeading()の戻り値)を比較した結果からステアリングを左右適切な方向に切ると、ラリーカーはオブジェクトの方向へ向いて進みます。


図4.ラリーカーとオブジェクトの相対位置関係
ラリーカーとオブジェクトの相対位置関係

ステアリングを左右のどちらかに切る場合、ラリーカーの進行方向に対して目標物(オブジェクト)が左、正面、右、のどの方向にあるのかを把握する必要があります。CodeRallyの世界ではラリーカーを中心としたトラック上の絶対角度を返します。すなわち、図5に示すとおりラリーカーの進行方向に対して右が+、左が-といった単純な値が帰ってくるわけではありません。ここで、車の進行方向をcar_h、目標物の方向をobj_hとします。図5を見ると、ラリーカーの傾きがcar_h度である場合、car_h度からcar_h+180度の範囲内にあるobj_h(目標物)は必ず右側となり、それ以外は左側と判定できます。一方、ラリーカーの傾きが180度から359度の範囲にある場合、car_h-180度からcar_h度の範囲にあるobj_h(目標物)は必ず左側となり、それ以外は右側と判定できます。

図5.ラリーカーとオブジェクトの相対方向関係1

図6.ラリーカーとオブジェクトの相対方向関係2

ラリーカーとオブジェクトの相対位置関係 ラリーカーとオブジェクトの相対位置関係

getCheckpoints()の戻り値はIObjectsクラス型ですので、IObjectクラスの場所を示すためインポート文が必要です。リスト3の赤字のコードを追加してください。
File > Save メニュー項目を選択してファイルを保存します。(test)をクリックして車がプライベートトラック上で1カ所目(配列インデックス0)のチェックポイントに向かって方向を変えるか確認してください。


リスト3.チェックポイントへの移動
                
import com.ibm.rally.Car;
import com.ibm.rally.ICar;
//IObjectクラスの場所を指定
import com.ibm.rally.IObject;

...
public void move(int lastMoveTime, boolean hitWall, ICar collidedWithCar, ICar hitBySpareTire) {

    // put implementation here
    // チェックポイントのリストを取得
    IObject cp[] = getCheckpoints();
    // 1番目のチェックポイントへ向かう
    // ラリーカーからチェックポイントへの方向(角度)を取得
    int cp_h = getHeadingTo(cp[0]);
    //スロットル(アクセル)の設定
    setThrottle(MAX_THROTTLE)
    // ラリーカーが現在進んでいる方向(角度)を取得
    int car_h = getHeading();
    // ラリーカーの進行方向とオブジェクトへの方向を比較する
    if (cp_h < car_h){
        // ステアリング(ハンドル)を左に切る
        setSteeringSetting(MAX_STEER_LEFT);
    } else {
        // ステアリング(ハンドル)を右に切る
        setSteeringSetting(MAX_STEER_RIGHT);
    }
}
...




上に戻る


チェックポイントの連続通過

チェックポイント通過による得点は、同じチェックポイントを連続的に通過しても1回目しか得点になりません。最も効率的な得点を重ねるにはチェックポイントに振られた番号を順番に通過することです。ここでは、チェックポイントを順に連続的に通過するようにします。リスト4の赤字のコードを追加してください。チェックポイントを連続して通過するためには、既に通過したチェックポイントを認識する必要があります。既に通過したチェックポイントを調べるには、CarクラスのgetPreviousCheckpoint()メソッドを使用します。getPreviousCheckpoint()メソッドの戻り値は通過したチェックポイントのインデックスを返します。一度もチェックポイントを通過していない場合は-1を返します。getPreviousCheckpoint()メソッドで得られるチェックポイントのインデックスとgetCheckpoints()のインデックスを比較して次ぎのチェックポイントを把握します。ここで注意するのは、再帰的に周回するよう最後のインデックスの次は最初のインデックス0に戻らなければいけません。getPreviousCheckpoint()メソッドの戻り値が最後のインデックスであった場合、向かうべきチェックポイントのインデックスを0にします。
File >Save メニュー項目を選択してファイルを保存します。(test)をクリックして車がプライベートトラック上でチェックポイントを番号順に通過します。


リスト4.チェックポイントの連続通過
                
import com.ibm.rally.Car;
import com.ibm.rally.ICar;
//IObjectクラスの場所を指定
import com.ibm.rally.IObject;

...
public void move(int lastMoveTime, boolean hitWall, ICar collidedWithCar, ICar hitBySpareTire) {

    // put implementation here
    int cp_h;
    // チェックポイントのリストを取得
    IObject cp[] = getCheckpoints();
    // 前回通過したチェックポイントを得る
    int prev_cp_index = getPreviousCheckpoint();
    // 前回通過したチェックポイントがあるかを調べる
    if(prev_cp_index == -1){
        // 通過したチェックポイントがなければ向かうチェックポイントをインデックス0に設定
        cp_h = getHeadingTo(cp[0]);
    } else {
        // 通過したチェックポイントがある場合
        // 最後のチェックポイントを通過したかどうかを調べる
        if(prev_cp_index == (cp.length - 1)){
            // 最後のチェックポイントを通過した場合は次に向かうチェックポイントをインデックス0に設定
            cp_h = getHeadingTo(cp[0]);
        }else{
            // 最後のチェックポイントではない場合、次のチェックポイントに設定
            cp_h = getHeadingTo(cp[(prev_cp_index + 1)]);
        }
    }
    //スロットル(アクセル)の設定
    setThrottle(MAX_THROTTLE)
    // ラリーカーが現在進んでいる方向(角度)を取得
    int car_h = getHeading();
    // ラリーカーの進行方向とオブジェクトへの方向を比較する
    if (cp_h < car_h){
        // ステアリング(ハンドル)を左に切る
        setSteeringSetting(MAX_STEER_LEFT);
    } else {
        // ステアリング(ハンドル)を右に切る
        setSteeringSetting(MAX_STEER_RIGHT);
    }
}
...




上に戻る


燃料の補給

レースカーが走行するためには燃料が必要です。ここでは、燃料が30を切ると給油所に向かい、満タンになるまで燃料を補給するようにします。レーストラック上には給油所が3ヵ所設置されます。走行中に燃料が不足した場合、最も近い給油所を探し、レースカーを給油所に向かわせます。

まず、レースカーの燃料を得るためにCarクラスのgetFuel()メソッドで残量を調べ、残量が30以下かどうかを判定します。次にレーストラック上の給油所の位置を調べるためにCarクラスのgetFuelDepots()メソッドを使用します。getFuelDepots()メソッドの戻り値は、チェックポイントの時と同様にIObjectクラスの配列で得られます。給油所は3ヵ所ですので、配列のインデックスは0から2となります。

効率よく給油所に向かうため、得られたIObjectクラス型の3ヵ所の給油所から最も近い給油所を調べます。レースカーからIObjectクラス型のオブジェクトまでの距離を調べるには、CarクラスのgetDistanceTo(IObject obj)メソッドを使用します。戻り値はdouble型です。


リスト5.最寄りの給油所を取得
                
// ラリーカーの残燃料を得る
int car_fuel = getFuel();
// 残燃料が30以下の場合は最寄りの給油所へ向かう
if(car_fuel >= 30){
    // 最寄りの給油所
    IObject gas_station;
    // 給油所オブジェクトを得る
    IObject fuel_depo[] = getFuelDepots();
    // 3ヵ所の給油所までの距離を取得
    double fuel0 = getDistanceTo(fuel_depo[0]);
    double fuel1 = getDistanceTo(fuel_depo[1]);
    double fuel2 = getDistanceTo(fuel_depo[2]);
    // 距離を比較して最も近い給油所を特定
    if(fuel0 < fuel1){
        if(fuel0 < fuel2){
            gas_station = fuel_depo[0];
        }else{
            gas_station = fuel_depo[2];
        }
    }else{
        if(fuel1< fuel2){
            gas_station = fuel_depo[1];
        }else{
            gas_station = fuel_depo[2];
        }
    }
}

給油を行うには、ラリーカーと給油所の距離が25単位以内でないといけません。チェックポイントのように通過するだけで得点を得られるのと違い、給油所では給油可能範囲に留まる必要があります。レースカーの場合、スロットルとステアリングは瞬時に変更できますが、速度と方向は慣性が働くためすぐには変わりません。よって、スロットル全開で給油所に向かっても急には止まれませんので何らかの対策が必要です。


図7.ラリーカーと給油所
ラリーカーと給油所

ここでは、給油所までの距離が100以内に近づくとスロットルを10まで落とし、給油可能距離(25以内)になるとスロットルを0にします。


リスト6.慣性対策を施したラリーカーの給油
                
// ラリーカーの残燃料を得る
int car_fuel = getFuel();
// 残燃料が30以下の場合は最寄りの給油所へ向かう
if(car_fuel >= 30){
    // 最寄りの給油所
    IObject gas_station;
    // 給油所オブジェクトを得る
    IObject fuel_depo[] = getFuelDepots();
    // 3ヵ所の給油所までの距離を取得
    double fuel0 = getDistanceTo(fuel_depo[0]);
    double fuel1 = getDistanceTo(fuel_depo[1]);
    double fuel2 = getDistanceTo(fuel_depo[2]);
    // 距離を比較して最も近い給油所を特定
    if(fuel0 < fuel1){
        if(fuel0 < fuel2){
            gas_station = fuel_depo[0];
        }else{
            gas_station = fuel_depo[2];
        }
    }else{
        if(fuel1< fuel2){
            gas_station = fuel_depo[1];
        }else{
            gas_station = fuel_depo[2];
        }
    }
    // 最寄りの給油所までの距離を得る
    double fuel_distance = getDistanceTo(gas_station);
    // 給油所までの距離が100以内であれば減速する
    if(fuel_distance <= 100){
        // 給油可能距離かどうかを判定
        if(fuel_distance <= 25){
            // スロットル(アクセル)の設定
            setThrottle(0);
        } else {
            //スロットル(アクセル)の設定
            setThrottle(10);
        }
    } else {
        setThrottle(MAX_THROTTLE);
    }
}




上に戻る


データの蓄積と分析

リスト6のプログラムではまだ不十分です。リスト6のプログラムは給油中に残燃料が30を越えると給油を行うコードは実行されず、チェックポイントを通過するプログラムが実行されてしまいます。このままでは、満タンまで給油できませんので、残燃料が30を越えても給油中かどうかを判断する必要があります。moveメソッド内で定義した変数のデータは、moveメソッドが終了するたびにメモリ上から消去されます。よって、moveメソッド外で定義と初期化を行います。

給油中を表すboolean型のフィールド(変数) fuel_flag を定義します。初期化はレースが始まる前に実行される initialize() メソッド内で行います。moveメソッド内では残燃料が30以下になるとtrue(給油中)に設定し、残燃料が100になった時にfalseに戻します。給油か走行かの判断はfuel_flagで判断できるようになります。


リスト7.データの定義と初期化
                
import com.ibm.rally.Car;
import com.ibm.rally.ICar;
//IObjectクラスの場所を指定
import com.ibm.rally.IObject;
...
    // 給油中フラグの定義(true:給油中,false:走行中)
    protected boolean fuel_flag;
    public void initialize() {
        // put implementation here
        // 給油中フラグの初期化
        fuel_flag = false;
    }
...
    public void move(int lastMoveTime, boolean hitWall, ICar collidedWithCar,ICar hitBySpareTire) {
        // put implementation here
        // ラリーカーの残燃料を得る
        int car_fuel = getFuel();
        // 残燃料が30以下の場合、給油中フラグをtrueに設定
        if(car_fuel <= 30){
            fuel_flag = true;
        }
        // 残燃料が30以下の場合は最寄りの給油所へ向かう
        if(fuel_flag == true){
            if(car_fuel == 100){
                // 満タンになると給油中フラグをfalseに設定
                fuel_flag = false;
            }
...

ここまでの全実装をリスト8に示します。コピーをして File > Save メニュー項目を選択してファイルを保存します。(test)をクリックして車がプライベートトラック上でここまでの実装を確認してください。


リスト8.給油機能付き周回ラリーカー
                
import com.ibm.rally.Car;
import com.ibm.rally.ICar;
//IObjectクラスの場所を指定
import com.ibm.rally.IObject;
/**
 * This is the class that you must implement to enable your car within
 * the CodeRally track. Adding code to these methods will give your car
 * it's personality and allow it to compete.
 */
public class RallyCar extends Car {
   /**
    * @see com.ibm.rally.Car#getName()
    */
    public String getName() {
        return "No Name";
    }
   /**
    * @see com.ibm.rally.Car#getSchoolName()
    */
    public String getSchoolName() {
        return "No School";
    }
   /**
    * @see com.ibm.rally.Car#getColor()
    */
    public byte getColor() {
        return CAR_BLUE;
    }
   /**
    * @see com.ibm.rally.Car#initialize()
    */
    // 給油中フラグの定義(true:給油中,false:走行中)
    protected boolean fuel_flag;
    public void initialize() {
        // put implementation here
        // 給油中フラグの初期化
        fuel_flag = false;
    }
   /**
    * @see com.ibm.rally.Car#move(int, boolean, ICar, ICar)
    * Put the car in reverse for a few moves if you collide with another car.
    * Go toward the first gas depot.
    */
    public void move(int lastMoveTime, boolean hitWall, ICar collidedWithCar,ICar hitBySpareTire) {
        // put implementation here
        // ラリーカーから見たオブジェクトの方向(角度)
        int obj_h;
        // ラリーカーの残燃料を得る
        int car_fuel = getFuel();
        // 残燃料が30以下の場合、給油中フラグをtrueに設定
        if(car_fuel <= 30){
            fuel_flag = true;
        }
        // 残燃料が30以下の場合は最寄りの給油所へ向かう
        if(fuel_flag == true){
            if(car_fuel == 100){
                // 満タンになると給油中フラグをfalseに設定
                fuel_flag = false;
            }
            // 最寄りの給油所
            IObject gas_station;
            // 給油所オブジェクトを得る
            IObject fuel_depo[] = getFuelDepots();
            // 3ヵ所の給油所までの距離を取得
            double fuel0 = getDistanceTo(fuel_depo[0]);
            double fuel1 = getDistanceTo(fuel_depo[1]);
            double fuel2 = getDistanceTo(fuel_depo[2]);
            // 距離を比較して最も近い給油所を特定
            if(fuel0 < fuel1){
                if(fuel0 < fuel2){
                    gas_station = fuel_depo[0];
                }else{
                    gas_station = fuel_depo[2];
                }
            }else{
                if(fuel1< fuel2){
                    gas_station = fuel_depo[1];
                }else{
                    gas_station = fuel_depo[2];
                }
            }
            // 最寄りの給油所までの距離を得る
            double fuel_distance = getDistanceTo(gas_station);
            // 給油所までの距離が100以内であれば減速する
            if(fuel_distance <= 100){
                // 給油可能距離かどうかを判定
                if(fuel_distance <= 25){
                    // スロットル(アクセル)の設定
                    setThrottle(0);
                } else {
                    //スロットル(アクセル)の設定
                    setThrottle(10);
                }
            } else {
                setThrottle(MAX_THROTTLE);
            }
            obj_h = getHeadingTo(gas_station);
        } else {
            int cp_h;
            // チェックポイントのリストを取得
            IObject cp[] = getCheckpoints();
            // 前回通過したチェックポイントを得る
            int prev_cp_index = getPreviousCheckpoint();
            // 前回通過したチェックポイントがあるかを調べる
            if(prev_cp_index == -1){
                // 通過したチェックポイントがなければ向かうチェックポイントをインデックス0に設定
                cp_h = getHeadingTo(cp[0]);
            } else {
                // 通過したチェックポイントがある場合
                // 最後のチェックポイントを通過したかどうかを調べる
                if(prev_cp_index == (cp.length - 1)){
                    // 最後のチェックポイントを通過した場合は次に向かうチェックポイントをインデックス0に設定
                    cp_h = getHeadingTo(cp[0]);
                }else{
                    // 最後のチェックポイントではない場合、次のチェックポイントに設定
                    cp_h = getHeadingTo(cp[(prev_cp_index + 1)]);
                }
            }
            setThrottle(MAX_THROTTLE);
            obj_h = cp_h;
        }
        // ラリーカーが現在進んでいる方向(角度)を取得
        int car_h = getHeading();
        // ラリーカーの進行方向とオブジェクトへの方向を比較する
        if (obj_h < car_h){
            // ステアリング(ハンドル)を左に切る
            setSteeringSetting(MAX_STEER_LEFT);
        } else {
            // ステアリング(ハンドル)を右に切る
            setSteeringSetting(MAX_STEER_RIGHT);
        }
    }
}




上に戻る


スペアタイヤによる攻撃

スペアタイヤは進行方向にしか投げれません。レース開始時に3本、補給により最大5本まで持つことができます。スペアタイヤは相手にぶつけることができれば得点できるだけでなく、相手の燃料を10単位失わせることができ、かつ、10クロックチックの間動けなくすることができますので、効率的な使い方をしたいところです。ここでは、相手の車に衝突した後に進行方向に距離50以内で他車がいた場合投げることにします。ここでは以下の4つの情報が必要です。

  • 他車との衝突検出
  • 他車と自車の位置関係
  • 他車と自車の距離関係
  • スペアタイヤの投げ方

他車との衝突が発生したかどうかは、CodeRallyエンジンによって各車に伝えられる情報です。moveメソッドの引数に ICar型の変数collidedWithCarで衝突したラリーカーを得ることができます。次にcollidedWithCarで得られた情報をもとに他車と自社の位置関係を取得します。ICarインタフェースはIObjectインタフェースを親にもっていますので、これまでオブジェクトの位置関係を調べるのに使ってきたCarクラスのgetHeadingTo(IObject obj)メソッドの引数に設定することができます。また、同様にCarクラスのgetDistanceTo(IObject obj)メソッドを使用して他車と自車の距離関係も調べることができます。

他車と衝突時に+15度から-15度の間に距離70以内に他車を検出した場合にCarクラスのthrowSpareTire()メソッドを使ってスペアタイヤを投げます。スペアタイヤは一度投げると25クロックチック間は、別のスペアタイヤを投げることはできません。throwSpareTire()メソッドの戻り値はスペアタイヤを投げることができた場合boolean型でtrueを返し、投げることができなかった場合はfalseを返します。


リスト9.ラリーカーの衝突検出とスペアタイヤによる攻撃
                
...
public void move(int lastMoveTime, boolean hitWall, ICar collidedWithCar, ICar hitBySpareTire) {
      // put implementation here
    // 他車との衝突を検出
    if(collidedWithCar != null){
        // 衝突したラリーカーの方向(角度)を取得
        System.out.println("collided!");
        int col_car_h = getHeadingTo(collidedWithCar);
        if(((col_car_h - getHeading()) <= 30) | (330 <= (col_car_h - getHeading()))){
            // 衝突したラリーカーとの距離を取得
            double col_car_distance = getDistanceTo(collidedWithCar);
            if(col_car_distance <= 70){
                throwSpareTire();
                System.out.println("throw SpareTire");
            }
                System.out.println("heading:"+col_car_h+",distance:"+col_car_distance);
        }
    }
	
...




上に戻る


プロテクトモードによる防御

他車からのスペアタイヤの攻撃を防ぐにはスペアタイヤを避けるか、もしくは、プロテクトモードになるといった方法があります。プロテクトモードになるにはCarクラスのenterProtectMode()メソッドを使用します。戻り値は現在プロテクトモードかどうかをboolean型で返します。プロテクトモードの間はスペアタイヤがあたっても、他車に衝突しても自車を守ることができますプロテクトモードで移動中は、通常の2倍の速さで燃料を消費します。プロテクトモードは一度開始すると50クロックチック間続き途中で解除することはできません。ここでは、他車との衝突による影響から守るため距離が70以内になった時にプロテクトモードを使用します。


リスト10.プロテクトモードを備えたラリーカー
                
...
public void move(int lastMoveTime, boolean hitWall, ICar collidedWithCar, ICar hitBySpareTire) {
      // put implementation here
    // 他車との衝突を検出
    if(collidedWithCar != null){
        // 衝突したラリーカーの方向(角度)を取得
        System.out.println("collided!");
        int col_car_h = getHeadingTo(collidedWithCar);
        if(((col_car_h - getHeading()) <= 30) | (330 <= (col_car_h - getHeading()))){
            // 衝突したラリーカーとの距離を取得
            double col_car_distance = getDistanceTo(collidedWithCar);
            if(col_car_distance <= 70){
                  enterProtectMode();
                  throwSpareTire();
                  System.out.println("throw SpareTire");
            }
            System.out.println("heading:"+col_car_h+",distance:"+col_car_distance);
        }
    }
...

ここでご紹介したほかにもCodeRallyには様々な情報を得るためのがあります。CodeRallyのマニュアルを見て戦略・戦術に合わせたAPIを使ってください。また、オブジェクト指向を駆使して他車の細かな情報を得ることもできるはずです。ぜひ、戦略を練り最強のラリーカーを作ってみてください。


目次に戻る



参考文献



著者について

developerWorks Japan 編集室




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



はいいいえわからない
 


 


12345
不充分・不完全である大変素晴らしい
 


上に戻る


    日本IBMについて プライバシー お問い合わせ