ML Agent でチャットNPCを作る

![ezgif-2-3205e257fe.gif](https://qiita-image-store.s3.amazonaws.com/0/258501/23b1972e-a539-eac1-1a1e-203158f8a597.gif)

スクリプトはとっても簡単です

```C#
public Text userchat;//INPUT側のプレイヤのチャットです
public Text chat;//OUTPUT側のagent達チャットです
string nowmessege = "";
string tomessege = "";
```

```C#
public override void CollectObservations()//学習のINPUT部分
    {
        byte[] vsbyte = System.Text.Encoding.UTF8.GetBytes(userchat.text);
        for (int i = 1; i < 26; i++)
        {
            if (i < vsbyte.Length + 1)
            {
                string svv = vsbyte[i - 1].ToString();
                if (svv.Length >= 3)
                {
                    AddVectorObs(int.Parse("" + svv[0]) * 0.1f + 0.09f);
                    AddVectorObs(int.Parse("" + svv[1]) * 0.1f + 0.09f);
                    AddVectorObs(int.Parse("" + svv[2]) * 0.1f + 0.09f);
                }
                else if (svv.Length == 2)
                {
                    AddVectorObs(0f);
                    AddVectorObs(int.Parse("" + svv[0]) * 0.1f + 0.09f);
                    AddVectorObs(int.Parse("" + svv[1]) * 0.1f + 0.09f);
                }
                else if (svv.Length == 1)
                {
                    AddVectorObs(0f);
                    AddVectorObs(0f);
                    AddVectorObs(int.Parse("" + svv[0]) * 0.1f + 0.09f);
                }
            }
            else
            {
                AddVectorObs(0f); AddVectorObs(0f); AddVectorObs(0f);
            }
        }
    }
```

```C#
public override void AgentAction(float[] vectorAction, string textAction)//学習のOUTPUT部分
    {
        byte[] aabyte = new byte[25] {0,0,0,0,0,0,0,0,0,0,
                                      0,0,0,0,0,0,0,0,0,0,
                                      0,0,0,0,0};
        for (int i = 1; i < 26; i++)
        {
            if (i < vectorAction.Length + 1)
            {
                string at = ((int)(vectorAction[(i * 3) - 3] * 10)).ToString() + ((int)(vectorAction[(i * 3) - 2] * 10)).ToString() + ((int)(vectorAction[(i * 3) - 1] * 10)).ToString();
                int att = int.Parse(at);
                aabyte[i - 1] = (byte)att;
            }
        }
        tomessege = System.Text.Encoding.UTF8.GetString(aabyte);
        if (nowmessege != tomessege)//Input string format error ができないようにするため作りました
        {
            chat.text = tomessege;
            nowmessege = tomessege;
        }
    }
```

と

Core Brain Player.csで```if (brain.brainParameters.vectorActionSpaceType == SpaceType.continuous)```部分を修正します


```C#
foreach (KeyContinuousPlayerAction cha in keyContinuousPlayerActions)
                        {
                        string aa = GameObject.Find("Canvas/Text").GetComponent<Text>().text;
                            byte[] csbyte = System.Text.Encoding.UTF8.GetBytes(aa);
                            for (int i = 1; i < 26; i++)
                            {
                                if (i < csbyte.Length + 1)
                                {
                                    string vvv = csbyte[i - 1].ToString();
                                    if (vvv.Length >= 3)
                                    {
                                        action[(i * 3) - 3] = int.Parse("" + vvv[0]) * 0.1f + 0.09f;
                                        action[(i * 3) - 2] = int.Parse("" + vvv[1]) * 0.1f + 0.09f;
                                        action[(i * 3) - 1] = int.Parse("" + vvv[2]) * 0.1f + 0.09f;
                                    } else if (vvv.Length == 2)
                                    {
                                        action[(i * 3) - 2] = int.Parse("" + vvv[0]) * 0.1f + 0.09f;
                                        action[(i * 3) - 1] = int.Parse("" + vvv[1]) * 0.1f + 0.09f;
                                    } else if (vvv.Length == 1)
                                    {
                                        action[(i * 3) - 1] = int.Parse("" + vvv[0]) * 0.1f + 0.09f;
                                    }
                                }
                            }
                    }
```
　
　
チャットを自動、手動に行うためのchat.csというスクリプトを作ります
InputField chattextとUpdate()を使うことで直接チャットできます

```C#
public class Chat : MonoBehaviour
{
    //    public InputField chattext;
    public Text textsend;
    public float time;
    public Text aauser;
/*    void Update()
    {
               if (chattext.text.IndexOf("\n") != -1)
               {
                   if (chattext.text != "\n")
                   {
                       string[] arr = chattext.text.Split('\n');
                       string chatmes = string.Join("", arr);
                       textsend.text = chatmes;
                   }
                   chattext.text = "";
               }
    }*/
    void LateUpdate()
    {
        time = time + Time.deltaTime;
        if (time >= 2.0f && time <= 2.2f)
        {
            textsend.text = "おはよ";
            aauser.text = "おうはよ～";

        }
        if(time >= 2.0f && time <= 2.2f && Input.GetKey(KeyCode.R))
        {
            textsend.text = "こんにちは";
            aauser.text = "こんにちは！";

        }
        if (time >= 10.0f /*&& time <= 10.2f*/)
        {
            textsend.text = "";
            aauser.text = "おはよこの町に";
            time = 0f;
        }
    }
}
```

人工知能学でneuronは1と0を
perceptronはその間が存在して0~0.1...~0.3...~0.9...~1のデータを操ります

25個の文字のByte25個を75個のAction(perceptron)で学習します

111のバイトがあったら3個のAction1,1,1（実際は0.1をかけて後に10かける）で文字でoを、
99のバイトはAction0,9,9を文字cを作るという
感じで
分解させ学習してめちゃ早いです

**SpaceTypeは全部Continuous、SpaceSizeは全部75にして、模倣学習の時は絶対にKey Continuous Player Actionsを１個!!!!!!!!!！！！！！！！！！！！！！！！！！にしてください、**

**PPOをするには報酬を追加してください。**PPO報酬の部分は追加していません。模倣学習のみの
スクリプトではありませんが、報酬を追加するまではPPOは空の学習になります

0.9f値は学習してみると分かりますが
最初にロボットが0.9f値ほどのくらい誤差が出て追加しました
スクロールみたいのをゲームに入れてその誤差を減るようにしてくれると（OUTPUTで-0.9fするだけだから）
ちゃんと学習した結果を見れます