質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

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

Q&A

解決済

4回答

852閲覧

JavaScriptの再帰的関数がうまくいきません。マインスイーパーを作成中

oika77

総合スコア184

JavaScript

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

0グッド

1クリップ

投稿2019/04/04 12:13

編集2019/04/04 16:32

JavaScript

1コード 2//変数の設定 3const MS_SIZE=8;//マインスイーパーのサイズ 4var i,j; 5var tate,yoko,x,y; 6const number_of_mines=8;//地雷の数 7var counter=0; 8 9// 配列を用意 10var cell = new Array(MS_SIZE); 11for(i=0; i<MS_SIZE; i++){ 12 cell[i] = new Array(MS_SIZE); 13} 14for(i=0; i<MS_SIZE; i++){ 15 for(j=0; j<MS_SIZE; j++){ 16 cell[i][j]=0; 17 } 18} 19 20//地雷を配置 21for(i=0; i<number_of_mines; i++){ 22 tate=Math.floor(Math.random()*(number_of_mines)); 23 yoko=Math.floor(Math.random()*(number_of_mines)); 24 if(cell[yoko][tate]!=-1){ 25 cell[yoko][tate]=-1; 26 } 27 else{ 28 i--; 29 } 30} 31 32 33//地雷の周囲 34for(tate=0; tate<MS_SIZE; tate++){ 35 for(yoko=0; yoko<MS_SIZE; yoko++){ 36 if(cell[yoko][tate]==-1){ 37 for(j=-1; j<2; j++){ 38 for(i=-1; i<2; i++){ 39 if(yoko+j<MS_SIZE && yoko+j>=0 && tate+i<MS_SIZE && tate+i>=0){ 40 if(cell[yoko+j][tate+i]!=-1){ 41 cell[yoko+j][tate+i]++; 42 } 43 } 44 } 45 } 46 } 47 } 48} 49 50//ボードを開いたとき、クリックした時 51function openBoard(x,y){ 52 id="cell"+x+y; 53 target = document.getElementById(id); 54 if(cell[x][y]!=-1 && cell[x][y]!=0){ 55 target.innerHTML = cell[x][y]; 56 target.style.padding="7px 13.5px"; 57 target.style.textAlign="center"; 58 counter++; 59 if(counter==(MS_SIZE*MS_SIZE-number_of_mines)){ 60 window.alert("クリア"); 61 } 62 } 63 else if(cell[x][y]==0){ 64 target.innerHTML = cell[x][y]; 65 target.style.padding = "7px 13.5px"; 66 target.style.textAlign = "center"; 67 openBoard0(x,y); 68 } 69 else{ 70 target = document.getElementById(id); 71 target.innerHTML = "外れ"; 72 window.alert("あなたは爆死しました。") 73 } 74} 75 76//0が出た時その周りの0も開く関数 77function openBoard0(x,y){ 78 for(j=-1; j<2; j++){ 79 for(i=-1; i<2; i++){ 80 yoko=x+j; 81 tate=y+i; 82 if(yoko<MS_SIZE && yoko>=0 && tate<MS_SIZE && tate>=0){ 83 id="cell"+yoko+tate; 84 target = document.getElementById(id); 85 target.innerHTML = cell[yoko][tate]; 86 target.style.padding = "7px 13.5px"; 87 target.style.textAlign = "center"; 88 if(cell[yoko][tate]==0){ 89 openBoard0(yoko,tate); 90 } 91 } 92 } 93 } 94} 95

openBoard0という関数は0(地雷が周りにゼロ)を開いたら、その周りのcellを開く関数です。これ自体はうまく動作します。
問題はopenBoard0という関数の中の、再帰的にopenBoard0(yoko,tate)を出すところがうまくいきません。
教えていただけたらとても嬉しいです。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2019/04/05 08:27

あなたは、自分の求める回答以外のことやアドバイスに興味を示さないようだけれど tate=Math.floor(Math.random()*(number_of_mines)); yoko=Math.floor(Math.random()*(number_of_mines)); これはまずいよ!前回もそういったのだけれど。直す気が無いのかな?
oika77

2019/04/05 09:39

なるほど確かに!ありがとうございます すみません。前回はあまり気にしてませんでした。
guest

回答4

0

無限ループしているみたいですね。
1111
1AB1
1111
↑のAとBは0だとして、Aを押された時にAを中心に関数が呼ばれますが、周りに0(B)があるのでBを中心にもう一度関数が呼ばれます。Bの周りには0(A)があるのでAを中心にもう一度関数が呼ばれます。
既に開いた0を示す値(-1とか?)を入れるか、開いてあるかどうかを示すフラグセットを用意してみてはいかがでしょうか?

投稿2019/04/05 00:58

moredeep

総合スコア1507

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

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

oika77

2019/04/06 07:09

回答していただき、本当にありがとうございます。その点に関して気づいていませんでした。訂正いたします。
guest

0

蓋を開けてみれば単純な話です。

問題はopenBoard0という関数の中の、再帰的にopenBoard0(yoko,tate)を出すところがうまくいきません。

教えていただけたらとても嬉しいです。

質問文のここがバグってます。

開いたマスが偶然0だったとしましょう。
じゃあその周りの8マスは全部0なのですか?

いやいや、自分の周り8マスに「地雷は埋まっていない」事が保証されるだけで、
周り8マスは全て0以上ですよね。
0かも知れないし、1以上かもしれない。

従って実行すべきなのはopenBoard0ではなく、openBoardです。

投稿2019/04/05 04:45

編集2019/04/05 04:46
miyabi-sun

総合スコア21158

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

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

oika77

2019/04/05 09:46

回答本当にありがとうございます。 今回は再帰関数を「もしcell==0ならば」の中に入れているので大丈夫なのではないでしょうか。
miyabi-sun

2019/04/05 09:58

あー、cellは数字でしたか。 なら主原因は無限ループですね。 ですが、やはりopenBoard0ではなく、openBoardだけを叩くようにして下さい。 0の箇所をクリックして残ったマスを全部埋めてもクリア条件を満たせないようになり、 結局同じようなコードをあちこちにコピペすることになります。 なので、openBoard0はあくまで自分の周囲8マスをクリックするだけにした方が良いですね。
oika77

2019/04/06 07:09

確かにその通りでした。ありがとうございます。
guest

0

関数openBoard0の中で使うyoko,tateは当該関数の中で定義するローカル変数にしておかないとまずいのではないでしょうか。

投稿2019/04/04 12:48

KojiDoi

総合スコア13671

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

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

oika77

2019/04/04 16:28

回答ありがとうございます。ただローカル変数にしてもうまくいきませんでした。
guest

0

自己解決

何人もの方に回答していただき、本当にありがおうございました。
今回の問題点は、結論から言うと、この3人の方からご指摘いただいた箇所が全てです。
iとjをローカル変数に直したのと、cellを開いたかどうかを記録するようにしました。

つまり、スクリプトはこれです。

JavaScript

1コード 2//変数の設定 3const MS_SIZE=8;//マインスイーパーのサイズ 4var tate,yoko,x,y; 5var check0=0; 6const number_of_mines=8;//地雷の数 7//var counter=0; 8var close, open; 9 10close=0; 11open=1; 12 13// ゲームボードの配列を用意 14var cell = new Array(MS_SIZE); 15 16for(var i=0; i<MS_SIZE; i++){ 17 cell[i] = new Array(MS_SIZE); 18} 19 20for(var i=0; i<MS_SIZE; i++){ 21 for(var j=0; j<MS_SIZE; j++){ 22 cell[i][j]=0; 23 } 24} 25//ゲームボードの状態を表す配列を用意(状態とは開いたか開いてないか) 26var cellState = new Array(MS_SIZE); 27for(var i=0; i<MS_SIZE; i++){ 28 cellState[i] = new Array(MS_SIZE); 29} 30for(var i=0; i<MS_SIZE; i++){ 31 for(var j=0; j<MS_SIZE; j++){ 32 cellState[i][j]=close; 33 } 34} 35 36//地雷を配置 37for(var i=0; i<number_of_mines; i++){ 38 tate=Math.floor(Math.random()*(MS_SIZE)); 39 yoko=Math.floor(Math.random()*(MS_SIZE)); 40 if(cell[yoko][tate]!=-1){ 41 cell[yoko][tate]=-1; 42 } 43 else{ 44 i--; 45 } 46} 47 48//地雷の周囲 49for(var tate=0; tate<MS_SIZE; tate++){ 50 for(var yoko=0; yoko<MS_SIZE; yoko++){ 51 if(cell[yoko][tate]==-1){ 52 for(var j=-1; j<2; j++){ 53 for(var i=-1; i<2; i++){ 54 if(yoko+j<MS_SIZE && yoko+j>=0 && tate+i<MS_SIZE && tate+i>=0){ 55 if(cell[yoko+j][tate+i]!=-1){ 56 cell[yoko+j][tate+i]++; 57 } 58 } 59 } 60 } 61 } 62 } 63} 64 65//ボードを開いたとき、クリックした時 66function openBoard(x,y){ 67// console.log('openBoard : ' + x + ',' + y); 68 id="cell"+x+y; 69 target = document.getElementById(id); 70 if(cellState[x][y]==close){ 71 if(cell[x][y]>0){ 72 target.innerHTML = cell[x][y]; 73 target.style.padding="7px 13.5px"; 74 target.style.textAlign="center"; 75 cellState[x][y]=open; 76 77 } 78 else if(cell[x][y]==0){ 79 target.innerHTML = cell[x][y]; 80 target.style.padding = "7px 13.5px"; 81 target.style.textAlign = "center"; 82 cellState[x][y]=open; 83 openBoard0(x,y); 84 } 85 else if(cell[x][y]==-1){ 86 target = document.getElementById(id); 87 target.innerHTML = "外れ"; 88 window.alert("あなたは爆死しました。") 89 } 90 } 91} 92 93//0が出た時その周りの0も開く関数 94function openBoard0(x,y){ 95 for(var j=-1; j<2; j++){ 96 var yokox=x+j; 97 if(yokox<0 || yokox>=MS_SIZE) continue; 98 for(var i=-1; i<2; i++){ 99 var tatey=y+i; 100 if(tatey<0 || tatey>=MS_SIZE) continue; 101     cellState[yokox][tatey]); 102 if(cellState[yokox][tatey]==close){ 103 openBoard(yokox,tatey); 104 } 105 } 106 } 107} 108 109

投稿2019/04/06 07:31

編集2019/04/06 07:40
oika77

総合スコア184

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問