Power Virtual Agetns と Power Automate で Wordle を作る②

# はじめに

Teams版のPower Virtual AgetnsとPower Automateを利用して、最近話題の [Wordle](https://www.nytimes.com/games/wordle/index.html) を作ってみました。全２回の２回目です。

:::note info
第１回目の記事は[「Power Virtual Agetns と Power Automate で Wordle を作る①」](https://qiita.com/MiyakeMito/items/f71a2541a5d2c284af9c)になります
:::

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/PowerVirtualAgents?src=hash&amp;ref_src=twsrc%5Etfw">#PowerVirtualAgents</a> で <a href="https://twitter.com/hashtag/Wordle?src=hash&amp;ref_src=twsrc%5Etfw">#Wordle</a> を作ってみました。<br>答えは100の候補からランダムで設定するため、ゲームとしては簡単です笑<br>昨夜はWORDLEの事をよく知らずに適当なものを実装してしまってごめんなさい。<a href="https://twitter.com/hashtag/%E6%B0%97%E3%81%BE%E3%81%BE%E3%81%AB%E5%8B%89%E5%BC%B7%E4%BC%9A?src=hash&amp;ref_src=twsrc%5Etfw">#気ままに勉強会</a> <a href="https://t.co/HMB4VUv1vj">pic.twitter.com/HMB4VUv1vj</a></p>&mdash; Miyake Mito (@MiTo60448639) <a href="https://twitter.com/MiTo60448639/status/1500385230489743360?ref_src=twsrc%5Etfw">March 6, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# メイン処理の作成

全体象は下図になります。今回は、赤枠で囲ったメイン処理部分を記載します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/cee72a24-0db1-cc60-90dd-3bede3465567.png)


## ③トピック「ループ１」

利用者から回答を受け、フローで答え合わせした結果を表示するトピックを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/d8154438-5023-0e46-0147-8fb9f54d0f58.png)

### ③-1 トピック間の変数の受け渡し

トピックの先頭で、呼び出し元のトピックから値を受け取ります。
[質問する]を２つ用意し、[特定]に[ユーザーの応答全体]を選択します。
[応答に名前を付けて保存]で設定された変数を選び、[変数のプロパティ]で[他のトピックから値を受け取ります]にチェックを付けます。

:::note warn
[他のトピックから値を受け取ります]をONすると、チャットボット実行時には問い合わせとして動作しません。
トピックの引数の定義となります。
:::



**■ 「答え」の定義**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/f5fcc079-e5eb-3954-a87f-be472ca1accf.png)

**■ 「回答履歴」の定義**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1eb971c2-2a28-4f56-ed9c-cc7fcee83f96.png)


### ③-2 回答の質問

回答を質問します。
[条件]アクションを追加し、"リセット"と入力された場合、[前回](https://qiita.com/MiyakeMito/items/f71a2541a5d2c284af9c)作成したトピック「初期化」に戻り、ゲームをリセットします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/86db560e-1044-69ce-727f-ceb863cba2da.png)

### ③-3 フロー「メイン処理」の呼び出し

ここで一旦、フローを保存し[アクションを呼び出す]でフローの作成を選択します。








## ④フロー「メイン処理」

ユーザーの入力した回答に対し、答え合わせをするフローを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/844c83f5-6d0c-abe9-a2cd-e71c7f02a693.png)

### ④-1 引数の設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/a6eebced-6996-445d-f18c-cf28f9d9e292.png)

引数に、
* 「答え」：ゲームの答え
* 「回答履歴」：今回のゲームで今までユーザーが入力した回答の履歴
* 「回答」：入力された回答

を設定します。

:::note warn
「回答履歴」は、 **" APPLE,POINT,CIGAR,MAJOR "** のように、カンマ区切りの文字列として定義します
:::


### ④-2 答えの配列を作成

[作成]アクションで、トリガーにある引数の「答え」を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/6130203f-1aa8-ce93-3a01-3c61e7d707cf.png)

さらに[選択]アクションで、「答え」の文字を、1文字ずつの配列に分解します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1a14d2fe-dd28-18c2-cfa7-3ba10bac60bc.png)

```
range(0,length(outputs('答え')))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/2b14b1ab-c1b9-9a7c-1d75-7efb290433b1.png)

```
substring(outputs('答え'),item(),1)
```

:::note info
「答え」が"HUMPH"であれば、以下の配列が返ります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/f2cdcecd-203d-2818-3e3c-e5ed2dd5ce64.png)
:::

### ④-3 回答履歴+回答の配列を作成

「回答履歴」に今回の回答を追加します。
上記で記載したように、「回答履歴」は過去の「回答」を順にカンマで区切った文字列として定義しています。

「回答履歴」が存在する場合はconcat()関数で文字連結をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/6d3c3357-c92c-79cd-9df3-ab32dd810ff4.png)

```
if(empty(triggerBody()['text_1']),triggerBody()['text_2'],concat(triggerBody()['text_1'],',',triggerBody()['text_2']))
```

さらに、","（カンマ）を区切り文字として、split()関数で配列に変換します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/030da514-3f83-fb96-94ee-ffcee120e526.png)

```
split(outputs('回答履歴+回答'),',')
```

### ④-4 色の設定

答え合わせの「結果」を表示する際の色を10進数で設定します。

念のため、各色の説明をします。

* 緑：「答え」の中にあり、位置も正しいです
* 黄：「答え」の中に含まれますが、位置は違います
* 灰：「答え」に含まれません

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/e73dc174-80ed-76df-5c0e-4a6bab91d08f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/73c63865-4929-8df3-c965-bc568f70e618.png)


### ④-5 回答履歴の答え合わせ処理

Wordle で、「回答」できるチャンスは6回です。
よって「回答履歴」の要素数は最大で6になります。

6個の「回答履歴」に対し、答え合わせ処理を実施します。

:::note warn
処理を単純化するため、「回答」の度に過去の履歴も答え合わせしています
また、このような繰り返し処理はApply to eachを利用すると処理が簡略化できますが、レスポンスを考慮し除外しています
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/247f43e5-6bd2-ecf7-8fe8-4896847e1740.png)


#### 1つ目の回答履歴の答え合わせ処理

1つ目の「回答履歴」の答え合わせでは、以下の処理を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/cc54afc6-9e18-77b1-4785-7ca58a21ff6b.png)

[選択]アクションで「回答履歴」の1番目の要素（添え字=0）に対し、
1. 1文字ずつ分解し、「答え」の同じ位置の文字と比較　⇒　同値の場合は緑（当たり）で文字を出力
2. 1.でHitしなかったら、contains()関数で「答え」に存在するかチェック ⇒　存在する場合は黄（位置が異なる）で文字を出力
3. 上記以外 ⇒ 灰（ハズレ）で文字を出力


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/3e22f736-dcbf-d949-a9b5-f9f8241a9397.png)

```
range(0,length(outputs('回答履歴+回答_array')?[variables('intCount')]))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/a5ef2923-6660-a280-e898-44bb05e8380d.png)

```
if(equals(substring(outputs('回答履歴+回答_array')?[variables('intCount')],item(),1),substring(outputs('答え'),item(),1)),outputs('背景色1'),if(contains(outputs('答え'),substring(outputs('回答履歴+回答_array')?[variables('intCount')],item(),1)),outputs('背景色2'),outputs('背景色3')))
```

上記で取得した色と、「回答履歴」の各文字を下記のHTMLに挿入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/2463eb95-adaa-1503-f026-603530e1fbb1.png)

```

<span style="color: WHITE; background-color:rgb(@{body('答え合わせ_1')?[0]}); font-family:'游ゴシック体'; font-size: 25px;">&nbsp;@{substring(outputs('回答履歴+回答_array')?[variables('intCount')],0,1)}&nbsp;</span>
<span style="color: WHITE; background-color:rgb(@{body('答え合わせ_1')?[1]}); font-family:'游ゴシック体'; font-size: 25px;">&nbsp;@{substring(outputs('回答履歴+回答_array')?[variables('intCount')],1,1)}&nbsp;</span>
<span style="color: WHITE; background-color:rgb(@{body('答え合わせ_1')?[2]}); font-family:'游ゴシック体'; font-size: 25px;">&nbsp;@{substring(outputs('回答履歴+回答_array')?[variables('intCount')],2,1)}&nbsp;</span>
<span style="color: WHITE; background-color:rgb(@{body('答え合わせ_1')?[3]}); font-family:'游ゴシック体'; font-size: 25px;">&nbsp;@{substring(outputs('回答履歴+回答_array')?[variables('intCount')],3,1)}&nbsp;</span>
<span style="color: WHITE; background-color:rgb(@{body('答え合わせ_1')?[4]}); font-family:'游ゴシック体'; font-size: 25px;">&nbsp;@{substring(outputs('回答履歴+回答_array')?[variables('intCount')],4,1)}&nbsp;</span>
```

#### ２つ目以降の回答履歴の答え合わせ処理

２回目以降の処理は、１回目の処理をベースに、条件を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/35210cb6-cfdd-5ec2-97b6-1b80614a52cc.png)

該当する「回答履歴」が存在する時のみ、答え合わせ処理を実施します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/ddcfce6e-d2b8-0cdc-92ca-a66bda5a7ca0.png)

```
outputs('回答履歴+回答_array')?[variables('intCount')]
```

条件が合致する場合の処理は、上記の回答履歴１の処理をコピーしてください。

:::note info
複数アクションをまとめてコピーする場合は、コピー対象を[スコープ]に格納すると一括で複製できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1e49fe4b-6172-81f4-9641-d71d50f3bdb4.png)
:::

コピー後、HTMLの先頭に2行分の改行コードを追加し（＝Teamsチャットでの1行分の改行）、色情報の挿入内容をコピーしたアクション名に変更してください。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/90a317cb-67ca-bb2d-468e-ca542e985a25.png)

同様に、回答履歴２の処理をコピーし、回答履歴３~６を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/300869ae-95e0-804d-ea35-477132d83bf1.png)

### ④-6 トピックへの戻り値設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/1b596a19-709a-bd28-d816-fe4277856573.png)

「結果」に、１から６の回答履歴の答え合わせ結果をconcat()関数で結合した文字列を設定します。

```
concat(outputs('結果_1'),outputs('結果_2'),outputs('結果_3'),outputs('結果_4'),outputs('結果_5'),outputs('結果_6'))
```

回答履歴には「④-3 回答履歴+回答の配列を作成」で作成した、回答履歴と回答を","で結合したものを設定します。

```
outputs('回答履歴+回答')
```

トピック「ループ１」に戻り、[アクションを呼び出す]で、作成したフローを呼び出します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/17904c36-50c9-33b7-b873-feba4d49081f.png)

## ⑤トピック「ループ2」

トピック「ループ2」は、トピック「ループ1」を複製してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/e99bf75f-0a79-57ff-12d6-b3ae1f352019.png)

複製後、[状態]をオンにしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/67d82d31-910f-89bf-80b9-852cfef27dd3.png)

また、トピック先頭にて、「答え」と「回答履歴」に対し「他のトピックから値を受け取ります」をONにしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/7e6e5a64-a04d-17f7-4135-88e28ef92974.png)

## トピックのリダイレクト設定

[前回](https://qiita.com/MiyakeMito/items/f71a2541a5d2c284af9c)作成した①トピック「初期化」の末尾に、③トピック「ループ1」へのリダイレクトを追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/287af760-e917-b3ed-c986-580a8d077c0e.png)

③トピック「ループ1」の末尾に、⑤トピック「ループ2」へのリダイレクトを追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/bd67bd65-8452-01b3-c20b-200df9afbade.png)

⑤トピック「ループ2」の末尾に、③トピック「ループ1」へのリダイレクトを追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/b6c94178-3b84-137f-0fc9-3b60689444fe.png)

以上で完成です。

# 注意

Teamsの Power Virtual Agents ポータルで、作成したWordleゲームを実行すると、HTMLが解釈されず下図のように表示されてしまします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/0f5e16d7-c27d-c659-f145-307e18d015f1.png)

ゲームをプレイする際は、チャットボットを[公開]し、Teamsチャットから実行してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/64978d45-d164-7c91-b5a3-2e361d5a1604.png)


# まとめ

Power Virtual Agents と　Power Automate を利用した Wordle の作り方を紹介しました。
Power Virtual Agents のチャットの構成や、Power Automate での配列操作を工夫することで、快適に遊べるゲームを作成することが可能です。

是非作って、Playしてみてください！