T&Pスクリプト:配列と構造体を初期化するには

ホーム[H] > Big Huge Games > RoN Tips > T&Pスクリプト:配列と構造体を初期化するには
【こんなのどうでしょう?】シムシティ ソサエティーズ ディスティネーションズ
ジャンル:
Big Huge Games
シリーズ:
RoN Tips
種類:
データ/資料
最終更新:
2004年07月13日 12時35分
シリアル:
2004-07-13-01

RoN Oracleのフォーラムにて、Gigi氏がThrones and Patriots版のスクリプトで導入された配列と構造体の初期化の方法を説明しています。

要訳

T&Pにおいて、スクリプトに配列と構造体が導入されたが、この機能はほとんど文書化されていない。たとえば、

struct city_data {
   string city_name;
   int food,timber,metal,wealth;
};

...

city_data bla[] = { {"Berlin",100,100,100,100},
                    {"Leipzig",100,100,100,100}
                  };

というコードは、C++のコードとしては(stringという型を除けば)合法だが、Big Huge Scriptではコンパイラエラーになる。スクリプトで配列と構造体を初期化するにはどうしたらよいのか? 整数の配列を1から6の整数で初期化する場合を例にとって考えてみる。

// C++では有効
int array[] = {1,2,3,4,5,6};
// BHSでは動作しない
int array[] = {1,2,3,4,5,6};
int[] array = {1,2,3,4,5,6};
//BHSでは int[] foo と int foo[] 両方の宣言方法が合法

ループを使って初期化する方法も考えたが、これでは手間がかかってしまう。BHGから提供されているサンプルスクリプトを見ていて、次のようなコードを発見した。ctw_lib.bhsの193-198行目だ。

...
String list_array[];

if (list_name == "Building") {
  switch(diff) {
    case 1:
      list_array = ["Tower", "Tower", "Tower", "Fort", "Fort", "Barracks", "Barracks", "Stable", "Stable", "Temple"];
...

この代入はC++風の宣言ではない。そこでこういうやりかたを試してみた。

//BHG -- 動いた!
int array[] = [1,2,3,4,5,6];

これで配列を一行で初期化する方法はわかった。つぎの疑問は、どうやって整数型ではない、独自定義の構造体からなる配列を初期化するのか、だ。

struct city_data {
   string city_name;
   int food,timber,metal,wealth;
};

...

city_data bla[] = [ {"Berlin",100,100,100,100},
                    {"Leipzig",100,100,100,100}
                  ];

という書きかたではやはりコンパイルエラーになる。コンパイラは {"Berlin",100,100,100,100} という書きかたがcity_data型の構造体を指していると理解できないらしい。そこで {} を [] で置き換えてみる。

struct city_data {
   string city_name;
   int food,timber,metal,wealth;
};

...

city_data bla[] = [ ["Berlin",100,100,100,100],
                    ["Leipzig",100,100,100,100]
                  ];

またエラー。"Array declaration entries must be all of the same type"(配列宣言のエントリはすべて同じ型である必要がある)と言われてしまった。[]記法は配列にのみ使用できるらしい。こういう時にコンストラクタが使用できれば楽なのだが、この言語はC++ではない。そこでこういうやりかたを試してみた。

city_data first_element;
first_element.city_name = "Berlin";
first_element.food = 100;

//  ... 以下、second_element 等がつづく

city_data bla[] = [ first_element, second_element, third_element ];

これは意図通りに動作した。コードを清潔に保つために、コンストラクタのかわりをする関数を作ってみよう。

// class city_data
struct city_data {
   string city_name;
   int food,timber,metal,wealth;
};
// city_data のコンストラクタ
city_data scenario make_city_data(string city_name_,int food_,int timber_,int metal_,int wealth_) {
         city_data rval;
         rval.city_name = city_name_;
         rval.food = food_;
         rval.timber = timber_;
         rval.metal = metal_;
         rval.wealth = wealth_;
         return rval;
}

...

   city_data bla[] = [
           make_city_data("Berlin",100,100,100,100),
           make_city_data("hoho",100,100,100,100)
         ];


...

trigger feed_them_all (timer_expired("feedall")){
  // blaの配列を順にたどる。最初はBerlin, つぎはhoho
  for( int i = 0; i < bla.length; i++)
    // もし、"Berlin"や"hoho"という名前の都市が実際に存在するなら
    if (city_exists(bla[i].city_name)) { 
       // その都市の所有者を見つけ、所有者に資源を与える
       int owner =find_city_owner(bla[i].city_name); 
       give_good(owner,"Food",bla[i].food); 
       give_good(owner,"Timber",bla[i].timber);
       give_good(owner,"Wealth",bla[i].wealth);
       give_good(owner,"Metal",bla[i].metal);
      } // end if
} // end trigger

このやりかたはうまく動作した。これで簡潔な書きかたで構造体の配列を初期化することに成功した。