artisoc cloudでのシュミレーション紹介(until quiet down)

#arisoc cloudでのシュミレーション
(株)構造計画研究所のartisoc cloudを用いてシュミレーションを行ったのでその紹介です。
制作物の動画は[こちら](http://nao-portfolio.hiho.jp/achieve/intro.html)
実行結果のイメージ図はこれです。
![ｓ (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667391/5e2f2b9e-1772-06cf-5446-b1a0b0f1568f.png)

##artisoc cloud とは
クラウド型のMAS(マルチエージェント・シュミレーション)です。つまり様々な物体が影響を及ぼしあっているシュミレーションをより簡単に再現できるものです。
詳しい説明は[参照：artisoccloud-MASコミュニティ-構造計画研究所](https://mas.kke.co.jp/artisoccloud/)を見てください。

##基本説明
ここではコードを読むための基本説明を少しだけ行います。
中では基本的にpythonで書かれています。
プログラムをする場所は主に
**Universe**：環境全体
**空間**:マップのこと
**エージェント各種**:実際に動く物
に分かれています。
また、特殊な関数として
**def univ_init(self)**:生成されたときにだけ通る
**def univ_step_begin(self)**:毎ステップ開始時に通る
**def univ_step_end(self)**:毎ステップ終了時に通る
**def univ_finish(self)**:シュミレーション終了時に通る
の４つがあります。
また、エージェントにはマップ上での動きのために**x座標(x)**、**y座標(y)**、**向き(direction)**、**layer**という変数を持っています。
このエージェントは**create_agt()**で作成することがでます。

##シュミレーションの説明
題名はuntil quiet downで同級生3人で制作しました。
学校での避難訓練をシュミレーションしました。校長先生が「皆さんが静かになるまで５分かかりました。」
というまでの生徒の行動パターンを俯瞰することでなにか得られるものがあるのではないかと考え製作しました。
生徒一人一人に**意識度(0~100)**が設定されており、その値が一定以上（100以上）になると静かになったという事で前を向き緑色になります。
意識度が上昇するポイントは
**・周りの静かな人の数**
**・先生と目が合うか**
**・校庭全体の静けさ**
の３つとしました。

##出力画面
![マップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667391/b00235b1-acaa-6e5e-a53f-00603fe9efbb.png)
出力画面の様子です。上の再生ボタンを押すと生徒が整列します。

##モデルツリー
![universe (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667391/8a6242e2-2433-205f-6f0c-fc58402a0355.png)
Universeのモデルツリーです。

![teacher (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667391/cc152090-bd90-098a-b8cc-6b8d760ba4d8.png)
teacherのモデルツリーです。

![ｓつでんｔ (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667391/8a62c2be-36a1-1677-3fa9-5c77f67032d5.png)
生徒のモデルツリーです。mensはgirlsと一緒なので省略しています。

##コード説明
```ruby:Universe
def univ_init(self):
    Universe.n=Universe.ninzuu
    print("アナウンス：訓練、訓練。職員室で火事が発生しました。校庭に避難してください。")
    Universe.noize=40*Universe.ninzuu
    for i in range(Universe.teacher_kazu):
        one=create_agt(Universe.koutei.teacher)
    
    create_agt(Universe.koutei.teacherboss)

def univ_step_begin(self):
    #生徒の整列
    Universe.time+=1
    Universe.retu+=1
    if Universe.time>3:#並び始めるタイミング調節
        if Universe.ninzuu>0:#残っている列の数が０でないなら列生成
            for i in range(20):##全部で２０人
                one=create_agt(Universe.koutei.mens)##男子生徒を生成
                two=create_agt(Universe.koutei.girls)##女子生徒生成
                one.goal=i+10##男子生徒の最終y座標
                one.x=(3*Universe.retu)+4+(2*10)-(2*Universe.n)#最大人数によって並ぶ場所を変化
                two.goal=i+10##女子生徒の最終y座標
                two.x=(3*Universe.retu)+1+4+(2*10)-(2*Universe.n)#最大人数によって並ぶ場所を変化
                Universe.time=0
            Universe.ninzuu-=1##列数
    else:
        Universe.retu-=1
    
def univ_step_end(self):
    if Universe.noize<=0:
        exit_simulation()
    pass
def univ_finish(self):
    print()
    print("校長：え～、皆さんが静かになるまでに約"+str(format(count_step()))+"秒かかりました。")
    if count_step()<=Universe.n*10:
        print("まじめな生徒が多くて先生はうれしいです。")
    else:
        print("結構時間がかかってしまいましたね、先生は少し...残念です。")
```
Universeでは
シュミレーション開始時(**univ_init(self)**)に
校長先生（**teacherboss**）、先生（**teacher**）を生成しています。
また、**univ_step_begin(self)**で生徒（**mens,girls**）を生成し、そのx座標、y座標を決めています。
**univ_step_end(self)**と**univ_finish(self)**でシュミレーションの終了タイミングと終了時の結果出力をしています。

```ruby:teacherboss
def agt_init(self):
    n=4+(2*10)-(2*Universe.n)
    m=(3*Universe.n)+8+(2*10)-(2*Universe.n)
    self.x=n+(m-n)/2
    self.y=33
    
def agt_step(self):
    ##校長の威厳
    SurroundStudent=self.make_agtset_around_own_sqgrid(5,False)
    for obj in SurroundStudent:
        if obj.color ==COLOR_RED  or obj.color ==COLOR_BLUE:##校長の周りに生徒がいるなら
            if obj.y>=obj.goal:#移動終わりまで待つ
                obj.cond=obj.cond+30#意識を上げる
```
校長先生(teacherboss)は動かないため初期設定は固定しました。
また、agt_step(self)では校長先生(teacherboss)の周りに静かでない生徒(mens,girls)がいるならば意識を毎ステップごとに30アップさせるようにしました。
前列の生徒は比較的静かな人が多いからです。

```ruby:teacher
def agt_init(self):
    self.place=rand()*3#場所振り
    if self.place>=2:#一番下
        self.x=(rand()*(3*Universe.n+4))+4+(2*10)-(2*Universe.n)
        self.y=8
        self.direction=0
    elif self.place>=1:#左
        self.x=4+(2*10)-(2*Universe.n)
        self.y=rand()*20+8
        self.direction=-90
    elif self.place>=0:#右
        self.x=Universe.n+8+(2*10)
        self.y=rand()*20+8
        self.direction=90
def agt_step(self):
    area=50 ##エリアの大きさ
    if self.place>=2:#下の動き
        if rand()*10<=1:##ランダムな動き
            self.x=self.x-1+rand()*2
        elif self.x<=5+(2*10)-(2*Universe.n):
            self.x=6+(2*10)-(2*Universe.n)
        elif self.x>=(3*Universe.n)+8+(2*10)-(2*Universe.n):
            self.x=(3*Universe.n)+7+(2*10)-(2*Universe.n)
    elif self.place>=0:#右左の動き
        if rand()*10<=1:##ランダムな動き
            self.y=self.y-1+rand()*2
        elif self.y<=8:
            self.y=9
        elif self.y>=28:
            self.y=27
    
    ##先生の目
    SurroundStudent=self.make_agtset_around_own_sqgrid(5,False)
    for obj in SurroundStudent:
        if obj.color == COLOR_RED or obj.color == COLOR_BLUE:
            if obj.direction==self.direction+180 and obj.y>=obj.goal:
                obj.cond+=10
```
先生（teacher）は３つの組に分けて場所をそれぞれ振り分けました。また、何回かに一回ランダムに動くようにもしました。
先生（teacher）のそばに生徒(mens,girls)がいて、自分の方角を向いているならばその生徒とは目が合ったという事で意識度を10上げています。

```ruby:girls
def agt_init(self):
    self.color = COLOR_RED # Init Color
    self.cond = rand() * Universe.ishiki # Init Cond
    self.i=30    
def agt_step(self):
    if(self.i==0):
        n=rand()*3
        if(n<1):
            self.direction=180
        elif(n<2):
            self.direction=270
        elif(n<3):
            self.direction=90
    #移動
    self.i-=1
    if self.goal>self.i:
        if self.y<=self.goal:
            self.y+=1
            
        else:
            # ここでself.cond上げる処理
            
            ##ノイズによる同調
            self.cond=self.cond+Universe.quietCount/80
            
            ##周りの子の様子(周りに緑の子がいればいるほど意識UP)
            SurroundAgents = self.make_agtset_around_own_sqgrid(2, False)
            count=0##周りの緑の人数の初期化
            for obj in SurroundAgents:
                if obj.color==COLOR_GREEN:
                    count+=1
            self.cond+=count/2
            
            ##先生からの目線は先生側に書く
         
            ## 意識が高いと静かになる（自分消去＋goodstudent 作成）    
            if self.cond > 100:
                good=create_agt(Universe.koutei.goodstudent)
                good.x=self.x
                good.y=self.y
                del_agt(self)
```
まず生徒を動かしてから意識を上げていきます。初期の意識度はrand()でランダムにしています。この時乱数の最大値はスライドバーで調整できるようにしてあります。
静けさや周りの様子で意識が上がり、意識度が100になったら自分を消して、静かな生徒**（goodstudent）**を生成するようにしています。

```ruby:mens
def agt_init(self):
    self.color = COLOR_BLUE # Init Color
    self.cond = rand() *Universe.ishiki # Init Cond
    self.i=30    
def agt_step(self):
    if(self.i==0):    
        n=rand()*3
        if(n<1):
            self.direction=180
        elif(n<2):
            self.direction=270
        elif(n<3):
            self.direction=90
    #移動
    self.i-=1
    if self.goal>self.i:    
        if self.y<=self.goal:
            self.y+=1
            
        else:
            # ここでself.cond上げる処理
            
            ##ノイズによる同調
            self.cond=self.cond+Universe.quietCount/80
            
            ##周りの子の様子(周りに緑の子がいればいるほど意識UP)
            SurroundAgents = self.make_agtset_around_own_sqgrid(2, False)
            count=0##周りの緑の人数の初期化
            for obj in SurroundAgents:
                if obj.color==COLOR_GREEN:
                    count+=1
            self.cond+=count/2
            
            ##先生からの目線は先生側に書く
            
        ## 意識が高いと静かになる（自分消去＋goodstudent 作成）
            if self.cond > 100:
                good=create_agt(Universe.koutei.goodstudent)
                good.x=self.x
                good.y=self.y
                del_agt(self)
```
girlsとほぼ一緒です。

```ruby:goodstudent
def agt_init(self):
    self.color = COLOR_GREEN # 静かになる(緑)
    self.direction=0
    Universe.quietCount +=1 # グローバル変数(静かな人の数)カウント
    Universe.noize-=1

def agt_step(self):
    pass


```
静かな生徒(goodstudent)が生成されるたびにカウントをするようにしているので、最後はこの数によってシュミレーションが終わるようになっています。

##まとめ
はじめてのartisoccloudでしたので手探りで作りました。他のシュミレーションにも使える場所が何か所もあるので覚書としても役に立ちそうです。