• 締切済み

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

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

みんなの回答

  • chie65535
  • ベストアンサー率43% (8536/19408)
回答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

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 大富豪におけるモンテカルロ法について

    私は現在、モンテカルロ法を用いた大富豪AIの構築を行おうとしています。 そこで質問&確認なのですが、 モンテカルロ法(仮に原始モンテカルロ)とは、 (1)ある条件下でとりあえず出せる手の内でランダムな手を出しつつゲーム全体を最後までプレイさせ、終わった時にどの条件下でどの手を出した時有効か有効でないかを記録し、最終的にそれらを統計的に見て、例えば『場に7以下が出ている場合は8を出せば統計的に有効なので出す。』というように手を決定する。 (2)ある条件下で、相手の手札を推測し、その上でランダムな手を出しつつ最後までプレイ(ただ、この「最後までプレイ」というのは自ターン時に別ルーチンで進める。プレイヤーの頭の中のみでゲームが行われているイメージ)し、最も評価の高かった手を出す。この時、ゲーム全体で見れば、自プレイヤーがただ普通に1ターンの内にカードを出したようにみえる。 の二つの内のどちらが正しいのでしょうか(画像参照)。 また、原始モンテカルロを改良した「モンテカルロ木探索」「UCB1を用いたモンテカルロ」についてもご教授していただければ幸いです。 色々調べたり論文をあさったりしているのですが未だ理解が及ばない状況です。 勉強不足で申し訳有りませんが、何卒ご教授願います

  • 学生です。宿題のプログラムについてヒントお願いします。

    今年、C++を始めた専門学生です。 学校で「じゃんけんプログラム」を作れという宿題が出ました。 その内容は、コマンドプロンプト上で 「5回じゃんけんをして、多く勝った方を『勝ち』と表示する」という物です。 「ポインタと構造体を使え」とのことですが 先生に何度か聞いたのですが 結局、良くわかりませんでした。 僕はアルゴリズムの理解度が曖昧だそうです。 自分ではアルゴリズムもそうですが 書き方の時点でも良くわかってないと思います。 ポインタも、構造体も、いまいち良くわかっていません。 プロトタイプ宣言も、どこに書けばよいのか・・ 他のクラスメイトは出来ているようなので、今更先生に聞けなくて フローチャートは書いてみたものの 書き方が全く思うように行かず、エラーが出て焦っています。 初歩的すぎて難しい質問かもしれませんが どなたかご享受願います。

  • モンテカルロ法による磁性体のヒステリシス曲線のシミュレーション

    2次元イジングモデルの強磁性体に対してモンテカルロ法でヒステリシス曲線をシミュレーションしたいのですが、うまくできません。わかっていることと言えば,1.モデルのスピンの初期状態をランダムにする。2.磁場を除序に変化させる。この2つくらいで、ボルツマン表の確率に従ってスピンを反転させるのをどこで行えばよいかなどいろいろわかりません。どなたか詳しく教えてください。おねがいします。

  • モンテカルロ法を用いた磁性体のヒステリシス曲線(磁化曲線)のシミュレーション

    2次元イジングモデルの強磁性体に対してモンテカルロ法でヒステリシス曲線をシミュレーションしたいのですが、うまくできません。わかっていることと言えば, 1.モデルのスピンの初期状態をランダムにする。 2.磁場を除序に変化させる。 この2つくらいで、ボルツマン表の確率に従ってスピンを反転させるのをどこで行えばよいかなどいろいろわかりません。どなたか詳しく教えてください。おねがいします。

  • プログラム実行時にわからないエラーメッセージが出ました

    書いたプログラムをcygwinでコンパイルし実行してみたのですが 数値を入力していくと次のようなエラーメッセージが出ました。 エラーの意味と、可能なら解決法をおしえていただきたいです。 よろしくお願いします。 12 [main] so 3092 _cygtls::handle_exceptions: Error while dumping state ( probably corrupted stack) Segmentation fault (core dumped)

  • 構造体へのポインタの動的確保について

    構造体へのポインタを動的確保しようとmalloc関数を使用すると segmentation faultが起きます。 typedef struct cell{ char *word; int count; struct cell *next; }node_t; という構造体で node_t *ptr=(node_t*)malloc(sizeof(node_t)*num); という風に動的確保しようとするとsegmentation faultが起きました。 gdbを使って調べると Starting program: /home/programII/week05/a.out file1 file2 Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7b4ce36 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 というメッセージが返ってきます。 これはライブラリとのリンクが正しく行われていないということでしょうか? しかし、ポインタの動的確保以外でmalloc関数を使用すると 正常に動作するのでライブラリ自体が無いわけではないようです。 ptr[2]といった風にポインタを参照したいのですが上手くいきません。 よろしくお願いします。

  • sprintf関数の使用法について

    sprintf関数の使用法がまずいようで、実行すると Segmentation faultエラーが発生します。 コードは以下のとおりです。 main(){ char buf[100]; int h,m,s; h=12; m=30; s=47; sprintf(buf,"%s:%s:%s",h,m,s); } bufに時分秒をコロン区切りで格納したいの ですが、どうすれば良いのか教えて下さい。

  • 多人数のじゃんけんプログラム

    多人数でのじゃんけんプログラムを作成しています。 設定としては、 自分とコンピュータのじゃんけん大会 コンピュータの参加人数は最大で10人、 コンピュータの参加人数は自分で任意選択(1~10人)、誰か参加するかはランダム 出す手は、(自分の手→任意に選択)(コンピュータの手→参加者ごとにランダムで設定) 自分・コンピュータ(1~10)に固有の名前を与えてそれぞれの勝ち数をカウントする じゃんけん終了後、買った回数順に順位をつけて、1位から順に表示する。 ↑のようなプログラムを作成したいと思っております。 私が悩んでいる点は、じゃんけんの結果判定の方法と勝ち数ごとの順位付け・並び替えの方法です。(全部ですね・・・) 結果の判定方法は、 場に出ている手が2種類なら(勝ちか負け)、1種類・3種類なら(あいこ)とし、 2種類の場合には、出ている手と比較し勝敗判定を行う、 という形がいいのかなと思ってます(javaでどう書けばいいのかはわかりません--;) 並べ替えは、配列をうまく使えばいけるでしょうか? ネットやテキストなどで学習中ですが全体的にわからない点が多く、 考え方(結果判定・順位付け&並び替え)やソースサンプルなどお教えいただけると嬉しいです。 どうぞ宜しくお願いいたします。

    • ベストアンサー
    • Java
  • Cでオセロゲームプログラム

    Cでオセロゲームのプログラムを作ろうと思ってますが 下記のプログラムに構造体、2分木(ゲーム木)、リスト構造、ミンマックス法、バックトラック法等を含みたいのですが どのように書いていったらいいかわかりません。 どなたかわかる方いましたらよろしくお願いします。 #include <stdlib.h> #include <stdio.h> #define BOARD_SIZE 8 #define WALL '*' #define BLACK 'x' #define WHITE 'o' #define NONE ' ' char board[ BOARD_SIZE+2 ][ BOARD_SIZE+2 ] ; void board_initialize() { int i , j ; /* 周囲を壁で囲む */ for( i = 0 ; i < BOARD_SIZE+2 ; i++ ) { board[ 0 ][ i ] = WALL ; board[ BOARD_SIZE+1 ][ i ] = WALL ; board[ i ][ 0 ] = WALL ; board[ i ][ BOARD_SIZE+1 ] = WALL ; } /* 内部を何もない状態にする */ for( i = 1 ; i <= BOARD_SIZE ; i++ ) { for( j = 1 ; j <= BOARD_SIZE ; j++ ) { board[ i ][ j ] = NONE ; } } /* オセロの初期状態の配置 */ board[ BOARD_SIZE/2 ][ BOARD_SIZE/2 ] = WHITE ; board[ BOARD_SIZE/2+1 ][ BOARD_SIZE/2+1 ] = WHITE ; board[ BOARD_SIZE/2 ][ BOARD_SIZE/2+1 ] = BLACK ; board[ BOARD_SIZE/2+1 ][ BOARD_SIZE/2 ] = BLACK ; } void board_print() { int i , j ; printf( " " ) ; for( i = 1 ; i <= BOARD_SIZE ; i++ ) printf( "%2d" , i ) ; printf( "\n" ) ; for( j = 1 ; j <= BOARD_SIZE ; j++ ) { printf( "%2d:" , j ) ; for( i = 1 ; i <= BOARD_SIZE ; i++ ) { switch( board[ j ][ i ] ) { case WALL : printf( "■" ) ; break ; case BLACK : printf( "●" ) ; break ; case WHITE : printf( "○" ) ; break ; case NONE : printf( "+" ) ; break ; } } printf( "\n" ) ; } } int main(void) { board_initialize() ; board_print() ; }

  • C言語の学習法について

    こんにちは。私は大学二年生で今授業でC言語を学んでいます。 内容は数値計算を行っております。(二分法とかガウス消去法とか) 授業体系としては、プログラムの作成をするというものなのですが、私はプログラムを作るのが苦手です。 なので、自己学習をしようと思うのですが、効果のある勉強法とはどういったものなのでしょうか? プログラムについては自分で手を動かした数だけ上達していくといわれているのでなにか作成しようと思っています。 そこでなのですが 数値計算でアルゴリズムが頭に浮かんでこないというのは、もともとの知識不足なのだからゲーム(じゃんけん)などのプログラムを作る参考書をやるべきだ。 数値計算という内容に慣れていないのが原因だから数値計算に特化した参考書をすすめていくべきだ。 この二つの考えがあります。どちらにするべきでしょうか? プログラムを見ればアルゴリズムが理解できるのですが、 その逆、 つまり、問題からどういったアルゴリズムを作成し、それをどうプログラムとして作るのか。ができません。 まとまりのつかない文章で申し訳ございません。どんな些細なことでもいいのでなにかありましたら是非ともアドバイスよろしくお願いします。