こんにちは!どいこです。
ズンドコキヨシ問題について、前回の記事で
「「ズン」「ドコ」のいずれかをランダムで出力」する所までできました。
前回:【JavaScript/初学者向け】打倒!ズンドコキヨシ(前半戦)
しかし、まだキヨシは倒れていない・・・!
あきらめたらそこで試合終了なので、続きをやります。
#ズンドコキヨシとは(再掲)
「ズン」「ドコ」のいずれかをランダムで出力し続けて
「ズン」「ズン」「ズン」「ズン」「ドコ」の配列が出たら
「キ・ヨ・シ!」って出力した後終了する
#手順その②
###「ズン」「ズン」「ズン」「ズン」「ドコ」の配列が出たら
「キ・ヨ・シ!」って出力した後終了する
・ まずは「この並びで出たら反応するよ~」の「この並び」を判定するための配列(targetList
)と
「反応」の内容(answer
)を定義しておきます。
const targetList = ['ズン', 'ズン', 'ズン', 'ズン', 'ドコ']
const answer = 'キ・ヨ・シ!'
・ 次は「並びがtargetList
と同じか」を判定する段階ですね。
勇者どいこはココでつまづきました。
###つまづいた所(キヨシが出てこない)
if (randomOutput === targetList) {
console.log(answer)
}
要は「ランダムで作った配列の内容がtargetList
と同じ=
['ズン', 'ズン', 'ズン', 'ズン', 'ドコ']だったら
'キ・ヨ・シ!'って表示させようぜ!」
って意味なんですが
「'ズン', 'ズン', 'ズン', 'ズン', 'ドコ'」って出力されてる時もキヨシが出てこない。
♪せつなさよりも遠くへ~
なぜ?
その理由とは・・・
変数の中に直接配列が入っているわけではありません。
変数の中には、「参照」と呼ばれる「配列の場所」が記録されていて、
配列の実体は別の場所(メモリ上のどこか)にあります。
この事から、上のif文での比較においても
配列の中身の値を見比べているのではなく、参照先(保管場所)を見比べている事になります。
randomOutput
とtargetList
は、そもそも保管場所は異なりますよね。
(それぞれ別々に作られたものなので)
中身の値ではなく「お互いの保管場所を比較している」ため
結果はelse
となり、我々は「キ・ヨ・シ!」と叫ぶ事もままならないわけです。
###解決策
join()
を使う事にしました。
※当初はjson()を使うやり方を記載していましたが、物々しいので
コメントでのアドバイスを元に修正しました。ありがとうございます!
if (randomOutput.join() === targetList.join()) {
console.log(answer)
}
join() メソッドは、配列 (または配列風オブジェクト) の全要素を順に連結した文字列を新たに作成して返します。
区切り文字はコンマ、または指定された文字列です。
Array.prototype.join() - MDN web docs
join()
効果で、むきだしの値同士を突き合わせる事ができ
randomOutput
の出力が「'ズン', 'ズン', 'ズン', 'ズン', 'ドコ'」の時に
無事「'キ・ヨ・シ!'」と表示されるようになりました。
やったね
ちなみに「'キ・ヨ・シ!'」と叫んだら、ズンドコタイムは終了するのがお約束です。
forとは違って回数の決まっていないループ処理なので、while文を使います。
(条件式に当てはまる間だけ処理を繰り返し、当てはまらなくなったら終了させる)
なおかつ今回は、先に「ランダム配列を作る」必要があるので
do...whileを使います。
do...while 文は指定された文を、テスト条件が false に評価されるまで実行するループを作成します。条件は文を実行した後に評価されます。
結果として、指定された文は少なくとも 1 回は実行されます。
■ do : ランダム配列のrandomOutput
を生成&出力
■ while : 生成された配列とtargetList
を比較、一致しなければ再びdoを実行
(一致しない間処理を繰り返す ⇒ 一致したら終了)
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())
#回答まとめ(コード全体)
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)
}
(当初whileで書いていた所を、これまたコメントでアドバイスを頂き
do…whileに修正しています。ありがとうございます。)
俺たちの戦いはこれからだ!
ー最後までお読み頂き、とてもうれしく思います。
ありがとうございました。