C#でカノジョをつくる（18日目）

お疲れ様です。たなしょです。
今日は辞書を辞書を読み込むクラス、カノジョの機嫌を更新するクラス、パターン辞書から抽出したパターンから応答フレーズを選んでくれるクラスを作成しました。
## 辞書を読み込むメソッド
1.dics配下にあるランダム辞書をオープンします。

```c#
string[] r_lines = File.ReadAllLines(
    @"dics\random.txt",
    System.Text.Encoding.UTF8
    );
```
2.ランダム辞書の文字列を一行ずつ取り出し、末尾の改行文字を取り除き_randomListに追加します。

```c#
foreach (string line in r_lines)
{
   string str = line.Replace("\n", "");
   if (line != "")
   { 
       _randomList.Add(str);
   }
}
```
3.dics配下にあるパターン辞書をオープンする。

```c#
string[] p_lines = File.ReadAllLines(
    @"dics\pattern.txt",
    System.Text.Encoding.UTF8
    );
```
4.パターン辞書の文字列を一行ずつ取り出し、末尾の改行文字を取り除きnew_linesに追加します。

```c#
List<string> new_lines = new();
foreach (string line in p_lines)
{
    string str = line.Replace("\n", "");
    if (line != "")
    {
        new_lines.Add(str);
    }
}
```

5.タブ文字で切り分け、パターン文字列と応答フレーズとして_patternListに追加します。

```c#
foreach (string line in new_lines)
{
    string[] carveLine = line.Split(new char[] { '\t' });
    _patternList.Add(
        new ParseItem(
            carveLine[0],
            carveLine[1])
        );
}
```

## カノジョの機嫌を更新するメソッド
1.現在の機嫌値更新する。最大値と最小値を超えたら最大値と最小値に更新します。

```c#
private void Adjust_mood(int val)
{
    _mood += val;
    if (_mood > MOOD_MAX)
        _mood = MOOD_MAX;
    else if (_mood < MOOD_MIN)
        _mood = MOOD_MIN;
}
```
2.ユーザーの発言にマッチした場合は機嫌値を更新します。

```c#
public void Update(string input)
{
    if (_mood < 0)
        _mood += MOOD_RECOVERY;
    else if(_mood > 0)
        _mood -= MOOD_RECOVERY;
    foreach (ParseItem item in _dictionary.Pattern)
    {
        if (!string.IsNullOrEmpty(item.Match(input)))
            Adjust_mood(item.Modify);
    }
}
```
## 抽出したパターンから応答フレーズを返す処理
1.正規表現のパターンを宣言して、Regexを生成する。パターンマッチしたものをMatchCollectionオブジェクトの要素に格納します。

```c#
string SEPARATOR = @"^((-?\d+)##)?(.*)$";
Regex rgx = new(SEPARATOR);
MatchCollection m = rgx.Matches(pattern);
```
2.機嫌変動値を存在したら変数に代入します。

```c#
_modify = 0;
if (string.IsNullOrEmpty(mach.Groups[2].Value) != true)
{
    _modify = Convert.ToInt32(mach.Groups[2].Value);
}
```
3.phrasesで取得した応答フレーズ"|"で分割して_phrasesの要素として追加します。

```c#
foreach (string phrase in phrases.Split(new char[] { '|' }))
{
    Dictionary<string, string> dic = new();
    MatchCollection m2 = rgx.Matches(phrase);
    Match mach2 = m2[0];
    dic["need"] = "0";
    if (string.IsNullOrEmpty(mach2.Groups[2].Value) != true)
    { 
        dic["need"] = Convert.ToString(mach2.Groups[2].Value);
    }
    dic["phrase"] = mach2.Groups[3].Value;
    _phrases.Add(dic);
}
```
4.matchしたユーザーの発言を返します

```c#
public string Match(string str)
{
    Regex rgx = new(_pattern);
    Match mtc = rgx.Match(str);
    return mtc.Value;
}
```
5.応答フレーズ群から応答フレーズをランダムに抽出します。

```c#
public string Choice(int mood)
{ 
    List<String> choices = new();
    foreach (Dictionary<string, string> dic in _phrases)
    {
        if (Suitable(
            Convert.ToInt32(dic["need"]),
            mood
            ))
        {
            choices.Add(dic["phrase"]);
        }
    }
    if (choices.Count == 0)
        return null;
    else 
    {
        int seed = Environment.TickCount;
        Random rnd = new(seed);
        return choices[rnd.Next(0, choices.Count)];
    }
}
``` 
7.カノジョの機嫌値が応答フレーズの必要機嫌値を満たすかどうかを判定します。

```c#
static bool Suitable(int need, int mood)
{
    if (need == 0)
        return true;
    else if (need > 0)
        return (mood > need);
    else
        return (mood < need);
}
```
## 最後に
今日はカノジョの核となるパターンで会話する処理と機嫌の値を調整する処理を作りました。
明日はresponderやフォームなどのデザイン部分や返答する部分を作ればカノジョが完成します。長かったです。