teratail header banner
teratail header banner
質問するログイン新規登録
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

999閲覧

重複しないランダム表示について分からない箇所があります

Riehlvelt_love

総合スコア44

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2022/02/16 15:02

0

1

https://janken.asotetu.work/js_seiza_uranai/の星占いのゲームを作るコードですが、
イメージ説明
とありますが、重複を避けるためのプログラム
let rank= [];//ランキングのための変数
n=0;//繰り返し用プログラム
while(n < seiza.length){
if (seiza[un_r] != rank[n]){n++;}
else {break;}
}
が分かりません。
nは最初は0が代入されているので、はじめは
if (seiza[un_r] != rank[0]){n++;}
という意味になると思うんですが、seiza[un_r](配列seizaのランダム→仮にseiza[0]の”牡羊座”)と
rank(初めは空の配列)がイコールになる理由が分かりません
仮にn=0なので、rank[0]になりますが、それがどうやってseiza[0]の”牡羊座”やseiza[1]の"おうし座"とイコールになるんでしょうか?
rank[0]はrank[0]であって、seiza[0]の”牡羊座”やseiza[1]の"おうし座"という内容は含まれてないと思います
それとも、seiza[0]とrank[0]ならイコール、seiza[1]とrank[1]なら=ということでしょうか?
意味が分からなくて困ってます

また、
イメージ説明
も分かりません
「else登録しているものなら {break;プログラムを中断してください}」とありますが、プログラムを中断したら、途中でそこで終わりませんか?
どなたか解説お願いいたします

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

コードの説明

例えば、既に第1位に"さそり座"、第2位に"うお座"が選ばれていて、これから第3位を選ぶ場合を考えます。このとき、配列rankの中身は["さそり座", "うお座"]となっています。

まず、乱数un_rを使い、第3位となる星座の候補をランダムに選びます。ここでは、"うお座"が選ばれたとします。つまり、seiza[un_r]=="うお座"です。

次に、while文を使って配列rankの要素を先頭から順番に見ていき、size[un_r]と一致したらループを途中で抜けるようにします。この例ですと、

  • n==0rank[0]=="さそり座"size[un_r]と一致しないので、nを1増やす
  • n==1rank[1]=="うお座"size[un_r]と一致するので、while文を抜ける
    となります。

こうすることで、while文を回した後に、

  • n < seiza.lengthなら、while文を途中で抜けた = 重複がある
  • n == seiza.lengthなら、while文を途中で抜けなかった = 重複がない
    のように重複を判定することができます。

この例では重複があることが分かったので、何もせずにfor文の始めに戻り、再び星座の候補をランダムに選びます。ここでは"ふたご座"が選ばれたとします。そして先ほどと同様にwhile文を回すと、今度は重複がないと分かるので、iの値を1増やし、選んだ星座をrankに追加します。

以上のことを、iが12になるまでfor文を回すことで、第1位から第12位までの星座を重複のないように選んでいます。

JavaScript

1 for (i=0 ;i < seiza.length;){ //第12位が選ばれるまで繰り返す 2 3 n = 0; 4 un_r = Math.floor( Math.random() * seiza.length); //星座をランダムに選ぶ 5 color_r = Math.floor( Math.random() * color.length); //ラッキーカラーをランダムに選ぶ 6 7 //rankの先頭から順番に、重複がないか調べる 8 while(n < seiza.length){ 9 if (seiza[un_r] != rank[n]){n++;} 10 else {break;} //重複がある場合はループを抜ける 11 } 12 13 //重複がないならランキングに追加 14 if (n >= seiza.length){ 15 i++; 16 //(中略) 17 rank.push(seiza[un_r]);//配列に星座を追加 18 } 19 }

補足

どのように動作しているのか分かりにくいという場合は、以下のようにプログラムの該当箇所でログを出力してみるとよいでしょう。重複がある場合に、while文が途中で終了していることが分かると思います。

コード例:

JavaScript

1 console.group(`${i+1}`); 2 console.log(`seiza[${un_r}]==${seiza[un_r]}`); 3 while(n < seiza.length){ 4 console.log(`rank[${n}]==${rank[n]}`); 5 if (seiza[un_r] != rank[n]){n++;} 6 else {console.log('重複'); break;} 7 } 8 console.groupEnd();

ログ出力例(Chrome):

ログ出力例

コードの問題点

さて、このコードには致命的な欠陥があります。それは、上記のログ出力例からも分かる通り、配列rankで範囲外参照が起きていることです。

while文の条件式を見ると、n < seiza.lengthとなっています。rankの長さはseizaの長さより小さいですから、重複が無い場合に、nrankの末尾の要素の添え字よりも大きくなってしまい、範囲外参照が起きています。

JavaScriptは範囲外参照したときundefinedを返してくれますが、エラーやバグの原因になりかねないので、してはいけません。rankの各要素を調べるのですから、n < rank.lengthとしましょう。

修正例:

JavaScript

1 for (i = 0; i < seiza.length;){ 2 un_r = Math.floor( Math.random() * seiza.length); 3 color_r = Math.floor( Math.random() * color.length); 4 5 n = 0; 6 while(n < rank.length){ //修正 7 if (seiza[un_r] != rank[n]){n++;} 8 else {break;} 9 } 10 11 if (n == rank.length){ //修正 12 i++; 13 //(中略) 14 rank.push(seiza[un_r]); 15 } 16}

投稿2022/02/16 18:44

編集2022/02/16 18:48
luuguas

総合スコア501

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Riehlvelt_love

2022/02/17 14:09

分かりやすくありがとうございました!!理解できました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問