• 締切済み

モンテカルロ法ベースのオセロプログラムを作りたいのですが

今、C言語でモンテカルロ法ベースのオセロプログラムを作っているのですが、なかなかうまくいきません。 エラー内容: ある程度書いてみたのですが、実行すると「Segmentation fault」とでてしまいます。 アルゴリズム内容: 構造体を用意して、ランダムに手を打ち勝ったら手の内容と勝ち数をカウントして、構造体に格納します。最後に一番勝ったてを指すというプログラムを書いています。 質問点: 「Segmentation fault」とでてしまいます。何故なのでしょうか? 解決方法と理由を教えてください。 プログラム内で他にも変な場所があれば、教えてください。 それと、モンテカルロ法だけだと弱いので、何かいい手はないでしょうか? 質問が多くて申し訳ございませんが、教えていただければ幸いです。 オセロのプログラムデータは添付しています。 開発環境のOSはubuntuを使用しています。Windowsの時、文字化けする可能性があります。 なにとぞよろしくお願いします。

みんなの回答

回答No.3

問題は多数ある。 ・モンテカルロ法で双方の手を作っている最中、片方だけ「置く場所が無く、パスしなければならない」と言う状態になったら、無限ループして帰って来ない。 現在は「P1、P2の双方とも置く場所がない」つまり「空きマスがもう無い時だけ」しか終了しない。 ・モンテカルロ法で求めた「一番勝った手」を探す際に、最後の最後で「初期化されてないlis構造体のap、aqメンバの値を、*p2、*q2に返している」ので、不定な値を元に盤面外にコマを置く。Segmentation faultが出ている理由。 構造体lisは不要なので   j = 0;   //一番勝った手   m = -1; //最も多く勝った回数   i = 0; //最も多く勝った手の番号   while(j<18){     if(m < list[j].count) { //最も多く勝ったのはj番目の手       m = list[j].count; //最も多く勝った回数を更新       i = j; //最も多く勝った手の番号       //printf("%d %d %d %d %d\n",j,list[j].no,list[j].ap,list[j].aq,list[j].count);     }     j++;   }   *p2 = list[i].ap; //i番目の手が最も多く勝った手   *q2 = list[i].aq; //i番目の手が最も多く勝った手 でよい。 ・モンテカルロ法で、list構造体配列に「次に打つ手」を格納するのは「勝った時」だけなので、終盤で「どの手を打っても負ける状態」になるとlist構造体配列に何も入らない。 その為、勝負回数(今はテストで1回になってるようだが)が尽きた時に1度も勝ててないと、list構造体配列が全初期化されたまま終わる。 そして、list構造体配列のどれも「勝った回数」が0になっている為、どれを選んだとしても*p2、*q2が0になる為、盤面外にコマを置く。 「何度試行しても1回も勝てない状態」でモンテカルロ関数を呼んだ場合は「もっとも負けが少ない手」を返すようにしないとならない。 たぶん、上記の3点を直せば「小学生程度の強さのオセロ」にはなる筈。

satoshi551
質問者

補足

ご回答ありがとうございます。 ある程度、いただいたヒントからプログラムを作り直しました。 http://www.geocities.jp/ohi_stoshi/monte_test2.c game関数の所で、モンテカルロと通常のランダムで打つコンピュータ同士が何回勝つかに書き直されてます。 ただモンテカルロ法のプログラムを作ると盤面によって戻ってこない、のですが。 モンテカルロ法をつかってるmonte関数の中で、 while (1) {  if (!exist_legal_move(board2, player2)) { player2 = aite(player2); if (!exist_legal_move(board2, player2)) { break; }  } と書いて、Playerがもし打つ手が無かったら、次のPlayerに変更され、そのPlayerも打つてが中たら終了という風に書いているので、戻ってこないはずが無いと思っているのですが・・。 どうしてなのでしょうか?

  • arain
  • ベストアンサー率27% (292/1049)
回答No.2

No.1です 簡単に確認してみました。 >何回も見直してるのですが、どこが悪いのかわかりません。 問題点は一か所ではなく、相互に作用をしているためヒントのみ記載します。 ・関数の引数にはわかりやすい名前をつけましょう。  もしくは関数ヘッダで何を行うための引数かわかるようにしておきましょう。 ・ループや配列要素などにはdefineを使用した定数値を用いると変更が楽です。 ・配列の添字が配列の要素内に収まっているのか確認しましょう。  要素以外の場所をアクセスした際の動作は保障外です。 ・ループ条件が大小比較でない場合、ループの上限を超えて動作することがあります(最悪無限ループ)。  ループの条件には必ず上限(下限)値もつけましょう。

satoshi551
質問者

お礼

ありがとうございます。 初期化を忘れてたり、色々穴がありました。 モンテカルロは動くようになりました。

  • arain
  • ベストアンサー率27% (292/1049)
回答No.1

>「Segmentation fault」とでてしまいます。何故なのでしょうか? どこかでメモリ破壊を起こしてるから。 ループの終端条件を超えての代入や、文字列バッファの扱いなど

satoshi551
質問者

補足

ご回答ありがとうございます。 >ループの終端条件を超えての代入や、文字列バッファの扱いなど 何回も見直してるのですが、どこが悪いのかわかりません。 TXTファイルを添付できなかったのでCファイルをアップロードシマシタ、以下がプログラムソースになります。 http://www.geocities.jp/ohi_stoshi/othello2_06.c