Upgrade to Pro — share decks privately, control downloads, hide ads and more …

サメ-⼩⿂モデルのMASをつくってみよう

 サメ-⼩⿂モデルのMASをつくってみよう

このドキュメントは「システム/制御/情報」2017 年5 ⽉号に掲載された解説記事「マルチエージェントシミュレーションをはじめてみよう」の補⾜資料であり,記事の中でMAS のサンプルとして挙げている「サメ-⼩⿂モデル」について,具体的な構築⼿順を紹介します.サメ-⼩⿂モデルは記事の筆者が初学者にMAS を教える際の練習サンプルとして使⽤しているもので,極めて簡単なモデルでありながら視覚的に⾯⽩い創発現象を観察することができます.サメ-⼩⿂モデルやそれを活⽤した教育プログラムに関しての詳細は上記解説記事をご覧下さい.

m-miura.jp

May 31, 2017
Tweet

More Decks by m-miura.jp

Other Decks in Programming

Transcript

  1. 1 サメ-⼩⿂モデルの MAS をつくってみよう 2017.05 Ver.01 http://m-miura.jp/ はじめに このドキュメントについて このドキュメントは「システム/制御/情報」2017

    年 5 ⽉号に掲載された解説記事「マルチエージェントシミュレーショ ンをはじめてみよう」の補⾜資料であり,記事の中で MAS のサンプルとして挙げている「サメ-⼩⿂モデル」につい て,具体的な構築⼿順を紹介します.サメ-⼩⿂モデルは記事の筆者が初学者に MAS を教える際の練習サン プルとして使⽤しているもので,極めて簡単なモデルでありながら視覚的に⾯⽩い創発現象を観察することができま す.サメ-⼩⿂モデルやそれを活⽤した教育プログラムに関しての詳細は上記解説記事をご覧下さい. artisoc について このドキュメントでは株式会社構造計画研究所が提供している MAS 開発プラットフォーム「artisoc」を⽤いてサメ- ⼩⿂モデルを構築する⼿順を紹介します.aritisoc はグラフィカルでユーザフレンドリな操作性と直感的なコーディ ンググロック構成などの特徴を持ち,初学者が MAS を学ぶ上で使⽤するのに適しています.また,artisoc は学 ⽣や教育機関に対して無料で公開されており,あなたが学⽣または教育機関職員であれば下記の WEB サイト からダウンロードして今すぐに MAS 構築の練習を初めることができます. artisoc4.0 WEB ページ:http://mas.kke.co.jp/modules/tinyd0/index.php?id=13 artisoc の使⽤⽅法やプログラム⽂法の細かいところは,上記 WEB サイトで公開されているマニュアル,書籍 「⼈⼯社会構築指南」(著:⼭影進,学⽣/教育機関向けには PDF 無料公開),artisoc ヘルプ等を参照 して下さい. モデルファイルについて 下記の WEB ページからサメ-⼩⿂モデルのファイルをダウンロードできるので,適宜ご利⽤下さい.ただし,本当に 簡単なモデルですので,初学者の⽅はまずは次ページ以降の⼿順に従って⾃分⾃⾝でモデル構築にトライしてみ て下さい. サメ-⼩⿂モデルダウンロードページ:http://m-miura.jp/mas/shark-fish/
  2. 2 MAS をつくってみよう 1. 空間,エージェント,変数を追加する artisoc を⽤いて MAS をつくる際に最初に⾏う作業は,空間,エージェント,変数を配置することです.この作 業はツリーウインドウからマウスによる操作で⾏うことができます.artisoc

    を⽴ち上げると,Universe という要素だ けが配置されたツリーウインドウが表⽰され,artisoc で MAS を構築する際の多くの作業がこのツリーウインドウを 起点とします. Universe はシミュレーションに⽤いる空間,エージェント,変数などの全てを包含する最上位の要素だと思って下 さい.まずは,Universe の下に空間を配置しましょう.ツリーウインドウで Universe と表⽰された部分を右クリッ クして出て来るサブメニューから「空間の追加」を選んで下さい.すると「空間プロパティ」が表⽰されるので,空間名 を sea,空間の⼤きさを X:100,Y:100,ループするにチェックを⼊れて「了解」ボタンを押します(図1).こ れでサメと⼩⿂が動き回る空間「sea」が追加されました. 図 1. 空間プロパティ 次に空間 sea にエージェント型を追加しましょう.ツリーウインドウで sea と記述された部分を右クリックして,「エー ジェント型の追加」を選びます.すると,エージェント型プロパティが表⽰されるので,エージェント型名を shark とし て下さい.今回は⽣成エージェント数をコントロールパネルから操作することができるようにするので,エージェント型 プロパティの画⾯では⽣成エージェント数は 0 としておきます.同様にして sea に fish というエージェント型を追加 します. ⼀般的な MAS ではさらに各エージェント型の下に変数を追加しますが,今回のモデルでは追加の変数は必要あり ません.エージェント型を追加した時点で各エージェント型の下には⾃動的に ID, X, Y, Layer, Direction の5つの変数が追加されます.今回のモデルではこのうち X,Y,Direction を⽤います. 次に Universe の下に表 1 に⽰す 4 つの変数を追加します.ツリーウインドウの Universe を右クリックし,「変 数の追加」を選んで下さい.変数プロパティで変数名や変数の型を⼊⼒します.Universe の下に追加された変 数は「Universe.変数名」と記述することでコード内のどこからでも参照,代⼊することができ,Global 変数のよう な形で使⽤することができます.
  3. 3 表 1. Universe の下に追加する変数 変数名 変数の型 役割 Ns 整数(Integer)

    サメエージェントの数を指定する Nf 整数(Integer) ⼩⿂エージェントの数を指定する Rs 実数(Double) サメエージェントの視野を指定する Rf 実数(Double) ⼩⿂エージェントの視野を指定する ここまででサメ-⼩⿂モデルに必要な最低限の空間,エージェント,変数の配置が終わりました.ツリーウインドウは 図 2 のような状態になっているはずです. 図 2. 配置後のツリーウインドウ
  4. 4 2. マップ出⼒を設定する artisoc では空間とその中で⾏動するエージェントを簡単な操作でグラフィカルに表⽰することができます.そのため の設定として「出⼒設定」を⾏います. メニューバーの「設定」から「出⼒設定」を選びましょう.すると出⼒項⽬リストウインドウが表⽰されるので,「マップ 出⼒」を選択して(通常は最初からマップ出⼒が選択された状態になっています)「追加ボタン」を押します.今回 はマップ出⼒しか使⽤しませんが,他にも時系列グラフやヒストグラムなど,様々なグラフィカル出⼒を選択すること ができます.

    追加ボタンを押すとマップ出⼒設定ウインドウが表⽰されます.ここではマップ名とマップタイトルにそれぞれ sea と⼊ ⼒して,左下のマップ要素リストという項⽬中の追加ボタンを押します.すると要素設定というウインドウが表⽰さ れ,エージェントの表⽰に関する設定を⾏うことができます.まず要素名を「サメ」として出⼒対象に「shark」を選 び,マーカーを•,エージェント表⽰⾊を⾚⾊に設定して「了解」を押しましょう.同様にして要素名を「⼩⿂」, 出⼒対象を「fish」,⾊を⻘⾊にしてもうひとつマップ要素リストを追加します.ここまでの設定で図 3 のようになっ ているはずです.このまま「了解」を押して出⼒項⽬リストでもう⼀度「了解」を押せば設定完了です.これで空間 とエージェントを表⽰する準備が整いました. 図 3. マップ出⼒設定
  5. 5 3. コントロールパネルを設定する 次にエージェントの数や視野などのシミュレーションパラメータを GUI から操作するためのコントロールパネルを設定し ます.メニューバーの「設定」から「コントロールパネル設定」を選び,表⽰されるウインドウで「追加」ボタンを押しまし ょう.すると「ユーザ設定項⽬」というウインドウが表⽰されるので,コントロール名を「サメの数」,設定対象を 「Ns」,インターフェースを「直接⼊⼒」に設定します(図 4).同様にして,⼩⿂の数(Nf),サメの視野

    (Rs),⼩⿂の視野(Rs)を全て「直接⼊⼒」で設定します(図 5). 図 4. ユーザ設定項⽬(コントロールパネル設定) 図 5. コントロールパネル-ユーザ設定項⽬リスト ここまでの設定でコントロールパネルの準備ができました.この時点で⼀度実⾏ボタンを押してシミュレーションを開 始してみましょう(図 6).すると,図 7 のようなコントロールパネルが表⽰されるはずです(マップ出⼒も表⽰さ れますが,この時点では⽣成数が 0 のためエージェントは上⼿く表⽰されません).最初はどれも 0 に設定されて いるので,図 7 のように各パラメータの値を⼊れましょう. 図 6. 実⾏ボタン 図.7 コントロールパネル
  6. 6 4. エージェントを⽣成する 次に,エージェントを⽣成する処理をコードで記述しましょう.artisoc では処理のタイミングに応じたいくつかのコー ディングブロックが⽤意されていて,ユーザは(基本的には)いずれかのコーディングブロックの中にコードを記述しま す.例えば,シミュレーション開始時に⼀度だけ実⾏する初期設定は Univ_Init というブロックに,各ステップのは じめに実⾏する処理は

    Univ_Step_Begin というブロックに記述します.これらのコーディングブロックはツリーウイン ドウの Universe と表⽰された部分をダブルクリックすることで表⽰するルールウインドウから記述することができます (図 8).各コーディングブロックの詳細と処理の流れについては artisoc のマニュアルまたは解説記事「マルチエー ジェントシミュレーションをはじめてみよう」の 2.3 節を参照して下さい. 図 8. Universe のコーディングブロック エージェントを⽣成する処理は「シミュレーションが開始したときに⼀度だけ実⾏される処理」に該当するので, Univ_Init の中に記述します.Univ_Init の中に次のように記述して下さい. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: Univ_Init{ Dim i As Integer For i = 0 to Universe.Ns - 1 CreateAgt(Universe.sea.shark) Next i For i = 0 to Universe.Nf - 1 CreateAgt(Universe.sea.fish) Next i } ここで 6 ⾏⽬の「CreateAgt(Universe.sea.shark)」は,サメ(shark)エージェントを 1 つ⽣成するという処 理を⽰します.この処理を Ns 回繰り返すことで,全部で Ns 体の shark エージェントが⽣成されます.⼩⿂
  7. 7 (fish)エージェントについても同様です(9~11 ⾏⽬).Dim や For,Next などのプログラミング⽂法の詳細 については artisoc のマニュアルやヘルプを参照して下さい. これでシミュレーションを開始した直後にそれぞれ

    Ns 体,Nf 体のサメおよび⼩⿂エージェントが⽣成されるようにな りました.しかしこの時点でシミュレーションを実⾏しても,マップ出⼒では図 9 のように左下に 1 つのサメエージェン トが表⽰されるだけで,指定した数(Ns,Nf 体)のエージェントが⽣成されたようには⾒えません.これは,確か に指定した数のエージェントが⽣成されてはいるのですが,どのエージェントも座標が(0, 0)にいるので全て重なって いて,⼀番上のエージェントだけが表⽰されているように⾒えるためです.そこで次は,各エージェントの初期位置 をランダムで決めるような処理を記述します. 図 9. シミュレーションの実⾏結果(ここまでの⼿順の時点)
  8. 8 5. エージェントの初期配置をランダムにする 前節までの設定と記述では⽣成されたエージェントが全て(0, 0)の位置にいて図 9 のようになってしまうので,各エ ージェントが空間内のバラバラの位置にランダムで配置されるようにします.各エージェントに関する処理はツリーウイ ンドウで各エージェントをダブルクリックして表⽰される「ルール:エージェント名」というウインドウで表⽰される Agt_Init

    と Agt_Step というコーディングブロックに記述します(図 10).ここで Agt_Init にはエージェントが⽣ 成されたときに⼀度だけ実⾏される処理を,Agt_Step には各ステップでエージェントごとに実⾏される処理を記述 します. 図 10. ルールウインドウ(各エージェント) 初期配置をランダムにする処理は「エージェントが⽣成されたときに⼀度だけ実⾏される処理」に該当するので, Agt_Init の中に記述します.shark と fish のそれぞれの Agt_Init の中に次のようなコードを記述して下さい. 1: 2: 3: 4: 5: Agt_Init{ My.X = GetWidthSpaceOwn() * Rnd() My.Y = GetHeightSpaceOwn() * Rnd() My.Direction = 360 * Rnd() } ここで My という記述は「このエージェント⾃⾝」を表します.例えば My.X = 100 と記述すると,「このエージェン トの変数 X に 100 を代⼊する」という⽂になります.ここでは空間の横幅を取得する GetWidthSpaceOwn() という関数と,0~1 の間の実数をランダムで返す Rnd()という関数を⽤いて 2 ⾏⽬のように記述することで,X 座 標の値を 0~空間の横幅 の間のランダムな数に設定しています.Y 座標についても同様です(3 ⾏⽬).ま た,4 ⾏⽬で値を代⼊している Direction という変数は,エージェントの向きを⾓度[degree]で指定します.ラ ンダムな向きを向くために,代⼊する値を 0~360 の間のランダムな数としています.これらのコードを記述してから シミュレーションを実⾏すると,図 11 のようにエージェントが空間中にバラけて表⽰されます.
  9. 9 図 11. シミュレーションの実⾏結果(ここまでの⼿順の時点) 6. ステップごとにエージェントが前に進むようにする 次はいよいよ,エージェントを動かしてみましょう.エージェントが現在向いている⽅向に指定の距離だけ進む Forward(arg)という関数があるので,これを使います.shark と fish

    それぞれの Agt_Step の中に下記のよう に記述して下さい. 1: 2: 3: Agt_Step{ Forward(1) } これで各ステップに各エージェントが距離 1 だけ進むようになります.5 の⼿順でエージェント⽣成時にランダムな⽅ 向を向くようにしているので,シミュレーションを実⾏すると各エージェントがバラバラの⽅向に進むことが確認できま す.
  10. 10 7. 視野内のエージェントのうち,最近接のエージェントを取得する サメ-⼩⿂モデルでは,各エージェントは下記のルールに従って動きます. 1) サメから⾒て視野内の最近接エージェントが⼩⿂だった場合,⼩⿂の⽅に向かう 2) サメから⾒て視野内の最近接エージェントがサメだった場合,最近接のサメから遠ざかる⽅向(反対⽅向) に向かう 3)

    ⼩⿂から⾒て視野内にサメがいる場合,最近接のサメから遠ざかる⽅向(反対⽅向)に向かう これらのルールに該当する処理は Agt_Init に記述することになりますが,いずれの場合もまずは「視野内の最近 接のエージェント」を取得しなければなりません.サメ(shark)エージェントの Agt_Init に記述するコードのうち, 視野内の最近接エージェントを取得する部分のコードは下記のようになります. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: Dim arroundAgtSet as AgtSet Dim nearestAgt as Agt Dim nearestDistance as Double Dim one as Agt MakeAllAgtSetAroundOwn(arroundAgtSet, Universe.Rs, False) nearestAgt = GetAgt(arroundAgtSet, 0) nearestDistance = MeasureDistance(My.X, My.Y, My.X, My.Y, Universe.sea) For each one in arroundAgtSet distance = MeasureDistance(My.X, My.Y, My.X, My.Y, Universe.sea) if distance < nearestDistance then nearestDistance = distance nearestAgt = one End if Next one 上のコードの中で使⽤している関数は下記のような処理を⾏います.詳しい使い⽅や説明は artisoc のヘルプ等 を参照して下さい. — MakeAllAgtSetAroundOwn(arg1, arg2, arg3):arg2 で指定する距離内にいる全てのエージェントを 取得して,arg1 で指定するエージェント集合に⼊れる — GetAgt(arg1, arg2):arg1 で指定するエージェント集合の arg2 番⽬のエージェントを返す — MeasureDistance(arg1,arg2,arg3,arg4,arg5):arg1~arg4 で指定した座標間の距離を返す また,For each one in ~ の⽂は,エージェント集合に含まれるエージェントを順に取り出して処理を⾏っていく 制御⽂です.これについても詳しくは artisoc のヘルプ等を参照して下さい. 上のコードで⾏われる処理の内容は下記のようになります.この処理の結果,エージェント型変数 nearestAgt には,⾃分から⾒て視野内(距離 Universe.Rs 内)にいるエージェントのうち,最も近いエージェントが代⼊さ れます.なぜそのようになるか,考えてみて下さい.
  11. 11 [1] ⾃分から⾒て視野内(距離 Universe.Rs 内)にいるエージェントを全て取得し,エージェント集合型変数 arroundAgtSet に代⼊する:6 ⾏⽬ [2] arroundAgtSet

    の⼀番最初(0 番⽬)のエージェントを取得し,nearestAgt に代⼊する.また,その エージェントまでの距離を nearestDistance に代⼊する.これらは,繰り返し処理を⾏うにあたっての初期 値である:8 ⾏⽬と 9 ⾏⽬ [3] arroundAgtSet の i 番⽬のエージェントを取り出して,そのエージェントまでの距離を測る:12 ⾏⽬ [4] その距離が現在の nearestDistance よりも⼩さかった場合,nearestDistance を⼩さい⽅の値に更新 し,nearestAgt を i 番⽬のエージェントに⼊れ替える:13 ⾏⽬~16 ⾏⽬ [5] i を 1 増加させながら[3]~[4]の⼿順を繰り返す:11 ⾏⽬~17 ⾏⽬ 上記の⼿順のうち[2]~[5]は「あるエージェント集合に⼊っているエージェントのうち,最も⾃分に近いエージェントを 取り出す」という処理に相当し,そのような処理は⼩⿂(fish)エージェントの⽅でも使います.そこで次は, [2]~[5]の処理を関数としてまとめて,使いまわせるようにします. 8. 独⾃関数をつくる&使う artisoc では独⾃の関数やサブルーチンを定義することができます.それらを別のファイルに記述してインクルードす ることもできますが,今回は同じモデルファイル中に記述することにします.この場合,ツリーウインドウで Universe をダブルクリックすると表⽰される「ルール:Universe」ウインドウの中に独⾃関数を記述します.このウインドウの中 にすでに⽤意されている Univ_Init, Univ_Step_Begin,Univ_Step_End,Univ_Finish の外側であれ ばどこに記述してもよいですが,今回は図 12 に⽰すように Univ_Finish の下の部分に記述することにしましょ う. 図 12. 独⾃関数の記述場所 独⾃関数の定義⽅法については artisoc のマニュアルやヘルプなどを参照して下さい.ここでは⼿順 7 の項で⽰し た[2]~[5]を関数化したものとして,図 12 に⽰す場所に下記のように記述します.
  12. 12 1: 2: 3: 4: 5: 6: 7: 8: 9:

    10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: Function GetNearestAgt(originAgt as Agt, arroundAgtSet as AgtSet) as Agt{ //arroundAgtSet に含まれるエージェントのうち,originAgt に最も距離が近いエージェントを返す Dim distance as Double Dim nearestDistance as Double Dim nearestAgt as Agt Dim one as Agt nearestAgt = GetAgt(arroundAgtSet, 0) nearestDistance = MeasureDistance(originAgt.X, originAgt.Y, nearestAgt.X, nearestAgt.Y, Universe.sea) For each one in arroundAgtSet distance = MeasureDistance(originAgt.X, originAgt.Y, one.X, one.Y, Universe.sea) if distance < nearestDistance then nearestDistance = distance nearestAgt = one End if Next one Return(nearestAgt) } これで GetNearestAgt(arg1, arg2)という関数を⽤いることで,arg2 で指定するエージェント集合に⼊ってい るエージェントのうち,arg1 に最も近いエージェントを返り値として取得することができるようになりました.⼿順 7 の 項で⽰した[2]~[5]の処理が分からない,⾃分では書けないという初学者の⽅は安⼼して下さい.この部分の処 理について理解できなくても,上記のように独⾃関数を記述すれば,GetNearestAgt( )を使⽤することがで き,[2]~[5]の処理を⾏うことができます. 図 12 で⽰す部分に記述した独⾃関数は,「ルール:Universe」の中であればそのまま関数名を記述することで 呼び出すことができます.各エージェントのルール(Agt_Init と Agt_Step)の中から呼び出す場合は関数名の 前に@をつけて下さい.つまり,上記の独⾃関数を各エージェントのルールの中で使うためには, @GetNearestAgt(arg1, arg2) のように記述しなければなりません.
  13. 13 9. サメの⾏動モデルを記述する ⼿順 8 で定義した独⾃関数を使って,サメ(shark)エージェントの⾏動ルールを記述しましょう.ルール: shark の Agt_Step の中に次のように記述して下さい.

    1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: Agt_Step{ Dim arroundAgtSet as AgtSet Dim nearestAgt as Agt MakeAllAgtSetAroundOwn(arroundAgtSet, Universe.Rs, False) If CountAgtSet(arroundAgtSet) > 0 then nearestAgt = @GetNearestAgt(My, arroundAgtSet) If SpecifyAgtType(nearestAgt) == CAgtType("Universe.sea.shark") then //視野内最近接エージェントがサメだった場合 My.Direction = GetDirection(My.X, My.Y, nearestAgt.X, nearestAgt.Y, Universe.sea) + 180 Else //視野内最近接エージェントが⼩⿂だった場合 My.Direction = GetDirection(My.X, My.Y, nearestAgt.X, nearestAgt.Y, Universe.sea) End if End if Forward(1) } 8 ⾏⽬で「If CountAgtSet(arroundAgtSet) > 0 then」としているのは,視野内に他のエージェントがいた 場合に向きを変える処理をするためです.CountAgtSet(arg1)はエージェント集合 arg1 に含まれるエージェン トの数を数える関数であり,視野内にエージェントがいなかった場合は CountAgtSet (aroundAgt Set) の値 が 0 となります.そこで,もし CountAgtSet(arroundAgtSet) > 0 ならば(すなわち arroundAgtSet に 1 体以上のエージェントが含まれるならば)という分岐を⼊れておくのです.視野内に他のエージェントがいない場合 は向きを変える処理が⾏われず,そのままの向きで距離 1 進みます:19 ⾏⽬. 9 ⾏⽬で独⾃関数 GetNearestAgt(My, arroundAgtSet)を使っています.Agt_Step から独⾃関数を呼 び出す場合は関数名に@をつけるのを忘れないで下さい.9 ⾏⽬で視野内の最近接エージェントを nearestAgt に代⼊し,その後の If 分岐(10 ⾏⽬~17 ⾏⽬)で,nearestAgt が shark だった場合と fish だった場合 で向き(My.Direction)を変える処理を分けています.nearestAgt がサメだった場合は,nearestAgt の⽅ 向(GetDirection 関数で取得する)とは反対⽅向(+180 度)を向くようにしています. SpecifyAgtType(), CagtType(), GetDirection()などの関数についてはヘルプを参照して下さい.
  14. 14 10. ⼩⿂の⾏動モデルを記述する fish の Agt_Step も基本的には⼿順 9 で⽰した shark

    の Agt_Step と同じような形で記述しますが,下記の 点で少しだけ異なります. — ⼩⿂の⽅は視野内のサメ(shark)エージェントだけを⾒ればよいので,MakeAllAgtSetAroundOwn() ではなく,MakeOneAgtSetAroundOwn()を使います.使い⽅の詳細はヘルプを参照して下さい. — サメから逃げるときは少しだけスピードを早くしてあげます※この設定はなくても同じようなシミュレーション結果に なります これらを考慮して,fish の Agt_Step には以下のように記述して下さい. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: Agt_Step{ Dim arroundAgtSet as AgtSet Dim nearestAgt as Agt MakeOneAgtSetAroundOwn(arroundAgtSet, Universe.Rs, Universe.sea.shark, False) If CountAgtSet(arroundAgtSet) == 0 then //視野内にサメエージェントがいなかったとき Forward(1) Else //視野内にサメがいた場合 nearestAgt = @GetNearestAgt(My, arroundAgtSet) My.Direction = GetDirection(My.X, My.Y, nearestAgt.X, nearestAgt.Y, Universe.sea) + 180 Forward(1.5) End if }
  15. 15 11. シミュレーションを実⾏する&コードまとめ ⼿順 10 まで終了すれば,サメ-⼩⿂モデルの完成です.実⾏ボタン(図 6)を押してシミュレーションを開始して みましょう.図 13 はサメの数:10,⼩⿂の数:500

    のときのシミュレーションのキャプチャです.同じようなシミュ レーション結果になることを確認して下さい. 図 13. シミュレーション実⾏中のマップ出⼒(サメの数:10,⼩⿂の数:500) サメと⼩⿂の数や,⼩⿂の視野の値を変化させると,全体の挙動が変わります.条件によっては,個々のルール からは直感的には予想できない⾯⽩い創発現象が発⽣しますので,いろいろ試してみて下さい.創発現象につい ては,解説記事「マルチエージェントシミュレーションをはじめてみよう」の 3 章をご覧下さい. 次ページ以降に本ドキュメントで紹介したサメ-⼩⿂モデルのコードをまとめます.シミュレーションが上⼿く動かなかっ た⽅はコードをチェックしてみて下さい.コードに問題がない場合は,要素の階層構造(ツリーウインドウ),出⼒ 設定(マップ出⼒),コントロールパネルのいずれかに問題がある可能性が⾼いので,⾒直して下さい. 質問・ご意⾒があれば,http://m-miura.jp/contact からご送信下さい.
  16. 16 ルール:Universe Univ_Init{ Dim i As Integer For i =

    0 to Universe.Ns - 1 CreateAgt(Universe.sea.shark) Next i For i = 0 to Universe.Nf - 1 CreateAgt(Universe.sea.fish) Next i } Univ_Step_Begin{ } Univ_Step_End{ } Univ_Finish{ } Function GetNearestAgt(originAgt as Agt, arroundAgtSet as AgtSet) as Agt{ //arroundAgtSet に含まれるエージェントのうち,originAgt に最も距離が近いエージェントを返す Dim distance as Double Dim nearestDistance as Double Dim nearestAgt as Agt Dim one as Agt nearestAgt = GetAgt(arroundAgtSet, 0) nearestDistance = MeasureDistance(originAgt.X, originAgt.Y, nearestAgt.X, nearestAgt.Y, Universe.sea) For each one in arroundAgtSet distance = MeasureDistance(originAgt.X, originAgt.Y, one.X, one.Y, Universe.sea) if distance < nearestDistance then nearestDistance = distance nearestAgt = one End if Next one Return(nearestAgt) }
  17. 17 ルール:shark Agt_Init{ My.X = GetWidthSpaceOwn() * Rnd() My.Y =

    GetHeightSpaceOwn() * Rnd() My.Direction = 360 * Rnd() } Agt_Step{ Dim arroundAgtSet as AgtSet Dim nearestAgt as Agt MakeAllAgtSetAroundOwn(arroundAgtSet, Universe.Rs, False) If CountAgtSet(arroundAgtSet) > 0 then nearestAgt = @GetNearestAgt(My, arroundAgtSet) If SpecifyAgtType(nearestAgt) == CAgtType("Universe.sea.shark") then //視野内最近接エージェントがサメだった場合 My.Direction = GetDirection(My.X, My.Y, nearestAgt.X, nearestAgt.Y, Universe.sea) + 180 Else //視野内最近接エージェントが⼩⿂だった場合 My.Direction = GetDirection(My.X, My.Y, nearestAgt.X, nearestAgt.Y, Universe.sea) End if End if Forward(1) }
  18. 18 ルール:fish Agt_Init{ My.X = GetWidthSpaceOwn() * Rnd() My.Y =

    GetHeightSpaceOwn() * Rnd() My.Direction = 360 * Rnd() } Agt_Step{ Dim arroundAgtSet as AgtSet Dim nearestAgt as Agt MakeOneAgtSetAroundOwn(arroundAgtSet, Universe.Rf, Universe.sea.shark, False) If CountAgtSet(arroundAgtSet) == 0 then //視野内にサメエージェントがいなかったとき Forward(1) Else //視野内にサメがいた場合 nearestAgt = @GetNearestAgt(My, arroundAgtSet) My.Direction = GetDirection(My.X, My.Y, nearestAgt.X, nearestAgt.Y, Universe.sea) + 180 Forward(1.5) End if } その他の設定 空間 格⼦モデル,X:100,Y:100,ループする マップ出⼒ 原点位置:左下,表⽰型:チェス型,マーカーの拡⼤率:2.0 コントロール パネル Ns,Nf,Rs,Rf を設定対象とし,全て直接⼊⼒インターフェース