【JavaScript／初学者向け】打倒！ズンドコキヨシ（後半戦）

**こんにちは！どいこです。**

ズンドコキヨシ問題について、前回の記事で
「「ズン」「ドコ」のいずれかをランダムで出力」する所までできました。

[前回：【JavaScript／初学者向け】打倒！ズンドコキヨシ（前半戦）](https://qiita.com/doiko/private/d2cff877e24b8fbfd83d)


しかし、まだキヨシは倒れていない・・・！


あきらめたらそこで試合終了なので、続きをやります。


#ズンドコキヨシとは（再掲）
>「ズン」「ドコ」のいずれかをランダムで出力し続けて
>「ズン」「ズン」「ズン」「ズン」「ドコ」の配列が出たら
>「キ・ヨ・シ！」って出力した後終了する

#手順その②
###「ズン」「ズン」「ズン」「ズン」「ドコ」の配列が出たら<br>「キ・ヨ・シ！」って出力した後終了する

・ まずは「この並びで出たら反応するよ～」の「この並び」を判定するための配列（`targetList`）と
　「反応」の内容（`answer`）を定義しておきます。

```JavaScript
const targetList = ['ズン', 'ズン', 'ズン', 'ズン', 'ドコ']
const answer = 'キ・ヨ・シ！'
```
<br>

・ 次は「並びが`targetList`と同じか」を判定する段階ですね。
　 勇者どいこはココでつまづきました。

###つまづいた所（キヨシが出てこない）

```JavaScript
if (randomOutput === targetList) {
   console.log(answer)
}
```

要は「ランダムで作った配列の内容が`targetList`と同じ＝
['ズン', 'ズン', 'ズン', 'ズン', 'ドコ']だったら
'キ・ヨ・シ！'って表示させようぜ！」
って意味なんですが

**「'ズン', 'ズン', 'ズン', 'ズン', 'ドコ'」って出力されてる時もキヨシが出てこない。**

♪せつなさよりも遠くへ～:joy:
<br>

なぜ？
その理由とは・・・
>変数の中に直接配列が入っているわけではありません。
>変数の中には、「参照」と呼ばれる「配列の場所」が記録されていて、
>配列の実体は別の場所（メモリ上のどこか）にあります。

[JavaScriptの変数と配列と参照について](https://sbfl.net/blog/2017/05/30/javascript-variable-reference/)

---
この事から、上のif文での比較においても
配列の中身の値を見比べているのではなく、参照先（保管場所）を見比べている事になります。

`randomOutput`と`targetList`は、そもそも保管場所は異なりますよね。
（それぞれ別々に作られたものなので）

中身の値ではなく「お互いの保管場所を比較している」ため
結果は`else`となり、我々は「キ・ヨ・シ！」と叫ぶ事もままならないわけです。

###解決策

`join()`を使う事にしました。
<font color="gray">※当初はjson()を使うやり方を記載していましたが、物々しいので
　コメントでのアドバイスを元に修正しました。ありがとうございます！</font>

```JavaScript
if (randomOutput.join() === targetList.join()) {
   console.log(answer)
}
```

>join() メソッドは、配列 (または配列風オブジェクト) の全要素を順に連結した文字列を新たに作成して返します。
区切り文字はコンマ、または指定された文字列です。

[Array.prototype.join() - MDN web docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/join)


`join()`効果で、むきだしの値同士を突き合わせる事ができ
`randomOutput`の出力が「'ズン', 'ズン', 'ズン', 'ズン', 'ドコ'」の時に
無事「'キ・ヨ・シ！'」と表示されるようになりました。

やったね:relaxed:

---
ちなみに「'キ・ヨ・シ！'」と叫んだら、ズンドコタイムは終了するのがお約束です。
forとは違って回数の決まっていないループ処理なので、while文を使います。
（条件式に当てはまる間だけ処理を繰り返し、当てはまらなくなったら終了させる）
<br>

なおかつ今回は、先に「ランダム配列を作る」必要があるので
do...whileを使います。

>do...while 文は指定された文を、テスト条件が false に評価されるまで実行するループを作成します。条件は文を実行した後に評価されます。
結果として、指定された文は少なくとも 1 回は実行されます。

[do...while  - MDN web docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/do...while)
<br>

■ do　　 ：　ランダム配列の`randomOutput`を生成＆出力
■ while　：　生成された配列と`targetList`を比較、一致しなければ再びdoを実行
　　　　　　（一致しない間処理を繰り返す ⇒ 一致したら終了）

```JavaScript
do {
    // wordListのインデックス[0] or [1]をランダムで生成し、結果をrandomOutputの要素へ代入する処理を
    // 要素数（5個）分ループさせる
    for (let i = 0; i < randomOutput.length; i++) {
      randomOutput[i] = wordList[Math.floor(Math.random() * wordList.length)]
    }
    console.log(randomOutput) // ランダムに生成された配列を表示
    // トリガーとなる配列が現れるまで処理をループ
} while (randomOutput.join() !== targetList.join())
```

<br>
#回答まとめ（コード全体）

```JavaScript
function kiyoshi() {

  const wordList = ['ズン','ドコ'] // ランダムで表示するワード候補2種
  const elementsLength = 5
  const randomOutput = [...Array(elementsLength)] // 未定義の要素 × 5個の配列
  const targetList = ['ズン', 'ズン', 'ズン', 'ズン', 'ドコ'] // トリガーとなる配列
  const answer = 'キ・ヨ・シ！' //トリガーとなる配列が現れたら表示させるワード

  do {
    // wordListのインデックス[0] or [1]をランダムで生成し、結果をrandomOutputの要素へ代入する処理を
    // 要素数（5個）分ループさせる
      for (let i = 0; i < randomOutput.length; i++) {
        randomOutput[i] = wordList[Math.floor(Math.random() * wordList.length)]
      }
      console.log(randomOutput) // ランダムに生成された配列を表示
      // トリガーとなる配列が現れるまで処理をループ
  } while (randomOutput.join() !== targetList.join())
  // トリガー配列が現れたらループから抜けてanswerを表示させる
  console.log(answer)

}
```

<font color="gray">（当初whileで書いていた所を、これまたコメントでアドバイスを頂き
　do…whileに修正しています。ありがとうございます。）</font>

**俺たちの戦いはこれからだ！:innocent:**
<br>
ー最後までお読み頂き、とてもうれしく思います。
　ありがとうございました。