程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在Robocode中使用Vector實現敵人列表

在Robocode中使用Vector實現敵人列表

編輯:關於JAVA

前言

RoboCode的混戰模式中,如何更好的掌握多個對手的情況,從而采取更好的 策略,成為每一個玩家迫切需要解決的問題。而世界級的機器人大都采用了向量 (vector)數組的方式來保存多個對手的信息。

而且vector的作用不止於此,上屆世界冠軍Yngwie還使用vector來保存子彈 的命中率信息,為更好的決策提供依據。當然這超出了我們今天的話題,有興趣 的朋友可以看一下Yngwie中的Enemy類和Strategy類。

好了,讓我們正式開始今天的vector之旅吧,如果您對JAVA中的vector還不 是特別了解,沒關系,我在最後介紹了一些關於vector的知識。

給我們的敵人排個隊

熟悉JAVA的朋友都知道,vector是用來保存一系列對象的集合。今天我們用 他來保存我們的敵人的一些信息,把這些四處亂跑的家伙都抓進我們的集合還真 不是個輕松的活。孔子雲:“萬物皆類”。所以,我們首先要聲明一個類: Track類。將我們能知道的敵人的屬性全都作為這裡類中的一個屬性:名稱、絕 對角度、敵人坦克相對於你車頭方向的相對角度、距離、能量、速率和敵人坦克 所面對的方向等。這些都是通過ScannedRobotEvent對象得到的,具體的API函數 請參考Robocode的API幫助。代碼如下:

/**
  * Track類,保存目標的信息
  */
package mytest;
import robocode.*;
public class Track
{
     public String Name; //敵人坦克的名稱
     //敵人的絕對角度,通過計算得出
    public double Heading;
     //敵人坦克相對於你車頭方向的相對角度
    public double Bearing;
     public double Distance; //敵人坦克的距離
     public double Energy; //能量
     public double Velocity; //速率
     public double FaceHeading; //敵人坦克面向的方向
     public double trackX,trackY; //敵人坦克的坐標
    //下一個標准時間中敵人坦克所在的位置
   public double nextTrackX,nextTrackY;
     public void update(ScannedRobotEvent e)
     {
        Name=e.getName(); //敵人坦克的名稱
        Bearing=e.getBearing(); //敵人坦克相對於你車頭方向的 相對角度
        Distance=e.getDistance(); //敵人坦克的距離
        Energy=e.getEnergy(); //能量
        Velocity=e.getVelocity(); //速率
        FaceHeading=e.getHeading(); //敵人坦克面向的方向
     }
}

在戰場上,一個優秀的指揮官會很好的利用他手頭有限的信息,而我們的信 息都來自於雷達找到敵人後產生的ScannedRobotEvent事件,至於我們能得到哪 些信息,看上邊的注釋好了,不多解釋了。

下一步就是如何把已經現身在雷達中的敵人抓到一個vector裡去了,讓我們 回到我們的機器人主體中去:派生自AdvancedRobot 類的MyVector類中。

首先,聲明一個vector類型,並在run中進行初始化。

public class MyVector extends AdvancedRobot
{
     final double version=0.1; //版本號
     private Vector trackVector; //聲明我們的向量數組
     /**
     * run: MyVector's default behavior
     */
     public void run() {
        out.println("myVector Version is  "+version);

        trackVector=new Vector(); //初始化我們的向量數組

        while(true) {
            // Replace the next 4 lines with any  behavior you would like
            showTrack();
            setTurnRadarRight(360); //讓雷達不停轉
            execute();
        }
     }

好了,vector建好了,那下一步就……

請君入隊

在Robocode中90%以上的外界信息來自於雷達的掃描,在這個例子裡,我沒有 對雷達的動作進行更細致地處理,一直讓他在不停旋轉,從而能更多的收集不同 敵人的信息。如果是在單挑模式中,可能采取雷達鎖定目標會更加有效。

只要雷達工作正常,我們就能獲取每一個敵人的信息了。當敵人的信息源源 不斷地湧入我們的onScannedRobot中,我們的機器人要像一個優秀的指揮官一樣 去鑒別情報,那些是已經有的,那些是沒有的。如果已經存在我們則更新該對象 的屬性;如果沒有的話,就在向量數組中添加一個新的成員。讓我們去 onScannedRobot事件裡看一下吧。

/**
     * onScannedRobot: What to do when you see  another robot
     */
     public void onScannedRobot(ScannedRobotEvent e) {
        if(!isInVector(e))
        {
            Track myTrack=new Track();
            myTrack.update(e);
            trackVector.add(myTrack);
        }
     }

我的myVector機器人是靠自定義方法 isInVector來判斷該機器人是否存在於 向量數組中的,我們等下去看isInVector的裡邊。如果isInVector返回值為 false,則初始化一個Track對象,調用它的update方法來初始化敵人的信息,然 後調用Vector類型的add方法,將該對象加入到向量數組中。

在這裡請大家注意的一點是:同一個Vector對象中可以存儲不同類型的對象 ,這是JAVA優於C++的一點,但是切忌濫用,我們在trackVector對象中存貯的對 象都是Track類型。 好了,讓我們去isInVector裡邊看看吧。

/**
    * isInVector:自定義方法,判斷該機器人是否已存在於隊列中
    */
     public boolean isInVector(ScannedRobotEvent e)
     {
        int i=0;
        while(i<trackVector.size())
        {
            Track myTrack=(Track)trackVector.get(i);
            if(myTrack.Name==e.getName())
            {
               myTrack.update(e);
               return true;
            }
            i++;
        }
        return false;
     }

isInVector 方法的基本思路是,通過傳進來的ScannedRobotEvent中的 getName來和vector中已經存在的對象的Name來進行比較,如果有相同的Name存 在,則說明該敵人的對象已經儲存在vector中了,我們只需要簡單的調用Track 類的update方法,更新信息,並返回true 就可以了。如果沒有在vector中找到 同名的機器人,則返回false,交給onScannedRobot事件來將這個機器人添加到 vector中來。

這裡我使用了Vector類型的size方法來得到向量數組中存在的對象的數量, 在後邊我們還會用到這個方法。同時使用一個int變量來控制操作哪個對象,更 好的辦法是使用迭代器,有興趣的朋友可以參考一下《JAVA編程指南》。要得到 vector中的Track對象,則需要使用Vector 類型的get方法,它指定返回第幾個 對象。注意,這裡需要進行強制類型的轉換。得到對象後我們就可以比較Track 的 Name和ScannedRobotEvent的getName()是否相同了。

敵人不見了

在 Robocode的戰場上,殺戮與被殺的幾率是相同的。不知道大家想過沒有, 如果一個敵人被干掉了,他的對象還保存在我們的vector中!如果我們的火控系 統偏巧選中了他來作為下一個攻擊目標的話……不用擔心,如果我的機器人真那 麼傻,他恐怕等不到別人被殺的情況。很簡單,我們只需要在 onRobotDeath事 件中調用Vector類型的remove方法。Remove方法是用來刪除指定位置上的對象的 。下面代碼的基本思路和 isInVector是一樣的。顯示如下:

/**
    * onScannedRobot:有機器人被消滅時產生該事件
    */
     public void onRobotDeath(RobotDeathEvent event)
     {
        int i=0;
        while(i<trackVector.size())
        {
            Track myTrack=(Track)trackVector.get(i);
            if(myTrack.Name==event.getName())
            {
               trackVector.remove(i);
            }
            i++;
        }
     }

顯示敵人的距離

我們這麼辛苦地保存了戰場上所有敵人的信息後,由myVector在每個基本時 間裡報告每個機器人距我們的距離。但這裡應該注意的是,myVector報告的距離 是我們的雷達最後一次看到敵人時的距離,敵人很可能已經移動了。正如一位物 理學家所說:“我們無法預測未來是因為我們無法看到真實的現在。”

我在run的while中調用了下面的函數,用來顯示當前的時間、敵人的數量及 每個敵人與我們的距離。對數量的計算用到了Vector 的size方法。

/**
    * 自定義函數:顯示當前敵人的距離
    */
   public void showTrack()
   {
       int i=0;
        out.println("This Time is "+getTime());
        out.println("Track's count is "+trackVector.size ());

        while(i<trackVector.size())
        {
            Track myTrack=(Track)trackVector.get(i);
            out.println(myTrack.Name+"'s Distance is  "+myTrack.Distance);
            i++;
        }
}

好了,一個簡單的使用vector來保存敵人信息的機器人完成了,你可以在這 裡下載他的代碼。在這裡我們的機器人僅僅是將敵人的距離顯示了出來,但是, 實戰中我們可以通過對這些信息的分析,來確定下一個攻擊目標,比如最近的一 個。這就要看你的發揮了。我在這裡提供的機器人可以說是很幼稚的,甚至公然 違反了一些面向對象編程的原則,比如把類中的元素直接聲明成public。這些問 題請大家在編碼的過程中避免。我在這裡想說明的是,在Robocode中你可以使用 任何的JAVA技術,讓你的機器人更強大。

下面是我寫的機器人myVector輸出測量結果時的情況,大家可以看到Time2和 Time3時的情況是不同的,在Time2時,雷達只掃描到了Crazy和Fire兩個敵人; Time3的時候雷達又發現了Corner。當有機器人被消滅的時候,Vector中的對象 會馬上被刪除。大家如果有興趣可以從下面找到myVector的源代碼(resource), 大家可以親自實驗一下。

Vector基本概念

最後,我來為不十分熟悉JAVA的朋友來簡單講解一些Vector的基礎知識,熟 悉這些內容的朋友可以跳過。

Vector 類型定義了Object 類型的一個元素集合,它最大的特點是能夠根據 你的需要動態增長。它實現了List接口,因此你可以把它看作一個列表。Vector 中只儲存對象的引用,而不是實際的對象。這裡引用的概念和C++中的很類似, 熟悉C++的朋友可以對照理解一下。

Vector的長度可以通過size()來獲得,而它的容量則用capacity()來得到。 容量(capacity)指的是為這個Vector分配的空間,而長度(size)則是Vector 中已經使用了的空間,size和儲存的對象個數相同。而長度永遠小於容量,這點 請大家注意。

Vector的容量可以通過setSize(i)來更改,如果Vector對象占用的元素個數 小於i,則其余元素將被null填充;如果包含的數量超過i,則所有i後的對象引 用將被丟棄。

Vector 中使用add為向量數組添加新的元素。Add(yourObject)是在vector的 最後添加一個元素。而Add(i,yourObject)則是在 i指定的位置添加一個元素, 使i以後的元素向後移動,總長度加1。與此類似,set(i,yourObject)則是由 yourObject替換i位置上的元素。這裡大家需要注意的是,Vector的記數是從0開 始的,而不是從1開始的。

Vector中使用get(i)來得到對象的引用,使用remove(i)來刪除i位置上的元 素。另外你還可以使用firstElement()來得到Vector中的第一個元素。形式如下 :

YourObject you=(YourObject)vector.firstElement();

我們可以通過把一個對象作為參數傳遞給indexOf()方法來獲得存儲在一個 Vector中的對象的索引位置。

至於,迭代器等一些高級屬性,如果有興趣,大家可以參考一下《Java編程指南》。裡面進行了很詳細的解說.

最後,我還要感謝天翼.李(Skyala.Li)耐心地看完了這篇文章的初稿,並提 出了寶貴的意見。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved