オセロ

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ざこ

オセロ

#1

投稿記事 by ざこ » 16年前

今度はAIを組み入れてみました。ちょっと長いですが・・
void COsero2Dlg::OnPaint() 
{
        if (IsIconic())
    {
                  CPaintDC dc(this); // 描画用のデバイス コンテキスト

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // クライアントの矩形領域内の中央
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // アイコンを描画します。
        dc.DrawIcon(x, y, m_hIcon);
    }

    else
    {
        if(InitFrag){
            CDC *pDC=GetDC();
            int x,y;
            
            CBrush gray_brush, black_brush, white_brush;

            white_brush.CreateStockObject(WHITE_BRUSH);//白色
            gray_brush.CreateSolidBrush(RGB(200,200,200));//灰色
            black_brush.CreateSolidBrush(RGB(0,0,0));//黒色
            pDC->SelectObject(&gray_brush);

            for(x=0;x<MASU_NUM;x++){
                for(y=0;y<MASU_NUM;y++){
                    pDC->Rectangle(x*MASU_SIZE,y*MASU_SIZE,(x+1)*MASU_SIZE,(y+1)*MASU_SIZE);

                    if(m_Board[x][y]==0)continue;
                    else if(m_Board[x][y]==BLACK_STONE)pDC->SelectObject(&black_brush);
                    else if(m_Board[x][y]==WHITE_STONE)pDC->SelectObject(&white_brush);
            

                    pDC->Ellipse(x*MASU_SIZE+3, y*MASU_SIZE+3,(x+1)*MASU_SIZE-3,(y+1)*MASU_SIZE-3);
                    pDC->SelectObject(&gray_brush);
                }
            }
    
            ReleaseDC(pDC);
        }
        
        CDialog::OnPaint();
    }
}

void COsero2Dlg::OnButton1() 
{
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
        
        
        MessageBox("ゲームを開始します");
        InitFrag=TRUE;
        CurSor=TRUE;
        CDC *pDC=GetDC();
        pDC->TextOut(450,100,"オセロゲーム");
        CStatic *fr;
        fr=(CStatic *)GetDlgItem(IDC_STATIC1);
        fr->SetWindowText("黒が先手です");
        shokika();//初期化関数
        OnPaint();//描画関数
        ReleaseDC(pDC);

}

void COsero2Dlg::shokika()//盤の初期化
{
    int x,y;
    for(x=0;x<MASU_NUM;x++){
        for(y=0;y<MASU_NUM;y++){
            m_Board[x][y]=0;
            m_Board[3][3]=BLACK_STONE;
            m_Board[4][4]=BLACK_STONE;
            m_Board[3][4]=WHITE_STONE;
            m_Board[4][3]=WHITE_STONE;
        }
    }
        Frag=TRUE;//先手は黒
        CButton *B;
        B=(CButton *)GetDlgItem(IDC_BUTTON1);
        B->EnableWindow(FALSE);
        countALL=0;//手数の初期化

}

void COsero2Dlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
    // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください
    
    int x,y;
        x=point.x/MASU_SIZE;//(例) 0-50のどこをクリックしても0と認識されるようにする
        y=point.y/MASU_SIZE;

        CDC *pDC=GetDC();
        
        
            if(Rule(x,y)){
                
                Reverce( x,y );
                PutStone(x,y);//交互に石を置く関数
                countALL++;
                OnPaint();
            
                CStatic *p;
                p=(CStatic *)GetDlgItem(IDC_STATIC1);
                
                p->SetWindowText("黒の番です");
                
                
                ReleaseDC(pDC);
            
                End();
                MessageBox("CPUが打ちます");
                AI();
                nothing();

            }

BOOL COsero2Dlg::Rule(int x, int y)
{

    if(x>=MASU_NUM && y>=MASU_NUM )return(FALSE);//マス数を超えるような位置には置けない。
    if(m_Board[x][y]==WHITE_STONE ||m_Board[x][y]==BLACK_STONE)return(FALSE);//既に石がおいてあるところには置けない。
    if(Rule(x,y,1,0))return TRUE;//右
    if(Rule(x,y,0,1))return TRUE;//下
    if(Rule(x,y,1,1))return TRUE;//右下
    if(Rule(x,y,-1,-1))return TRUE;//左下
    if(Rule(x,y,0,-1))return TRUE;//上
    if(Rule(x,y,-1,0))return TRUE;//下
    if(Rule(x,y,1,-1))return TRUE;//右上
    if(Rule(x,y,-1,1))return TRUE;//左上


    return FALSE;
    
    
}
void COsero2Dlg::PutStone(int x, int y)//交互に打つようにする
{

    if(Frag==TRUE)
        m_Board[x][y]=BLACK_STONE;
    else
        m_Board[x][y]=WHITE_STONE;

    Frag=!Frag;


}

BOOL COsero2Dlg::Rule(int x, int y, int v_x, int v_y)
{
    int put_stone;
    if(Frag==FALSE)
        put_stone=WHITE_STONE;
    else

        put_stone=BLACK_STONE;
    x+=v_x;//
    y+=v_y;

    if(m_Board[x][y]==0)return(FALSE);//
    if(m_Board[x][y]==put_stone)return(FALSE);
        x+=v_x;
        y+=v_y;
    while(x>=0 &&x<MASU_NUM && y>=0&& y<MASU_NUM){
    if(m_Board[x][y]==0)return(FALSE);
    if(m_Board[x][y]==put_stone)return(TRUE);
    

        x+=v_x;
        y+=v_y;

    }
    
    return FALSE;
}



void COsero2Dlg::Reverce(int x, int y)
{

        if(Rule(x,y,1,1)){
        
            Reverce(x,y,1,1);
        }
        if(Rule(x,y,-1,-1)){
            
            Reverce(x,y,-1,-1);
        }
        if(Rule(x,y,1,0)){
        
            Reverce(x,y,1,0);
        }
        if(Rule(x,y,0,1)){
        
            Reverce(x,y,0,1);
        }
        if(Rule(x,y,-1,0)){
        
            Reverce(x,y,-1,0);
        }
        if(Rule(x,y,0,-1)){
        
            Reverce(x,y,0,-1);
        }
        if(Rule(x,y,1,-1)){
            
            Reverce(x,y,1,-1);
        }
        if(Rule(x,y,-1,1)){
        
            Reverce(x,y,-1,1);
        }
        
        
        
}


void COsero2Dlg::Reverce(int x, int y, int v_x, int v_y)
{

    int put_stone;
    
    if(Frag==FALSE)
        put_stone=WHITE_STONE;
 
    else
        put_stone=BLACK_STONE;
    
    while(m_Board[x+=v_x][y+=v_y]!=put_stone)

        m_Board[x][y]=put_stone;
        
    
    
    
   
}

ざこ

Re:オセロ前編

#2

投稿記事 by ざこ » 16年前

続きです。
int COsero2Dlg::count(int stone)
{

    int x,y;
    int  count=0;

    for(x=0;x<MASU_NUM;x++)
        for(y=0;y<MASU_NUM;y++)
            if(m_Board[x][y]==stone)
                count++;
    return(count);
}
//判定する関数です。
void COsero2Dlg::End()
{
    num1=0,num2=0;
    CString str1,str2;
    num1=count(BLACK_STONE);//黒だった場合num1に黒石の数を入れる
    num2=count(WHITE_STONE);//白だった場合num2に白石の数を入れる
    str1.Format("%d",num1);
    str2.Format("%d",num2);

    if(countALL==60){
        if(num1>num2){
            MessageBox(str1,"黒石の数");
            MessageBox(str2,"白石の数");
            MessageBox("黒の勝ちです","勝敗判定");
            AfxGetApp()->m_pMainWnd->DestroyWindow();
        }

        else if(num1<num2){
            MessageBox(str1,"黒石の数");
            MessageBox(str2,"白石の数");
            MessageBox("白の勝ちです","勝敗判定");
            AfxGetApp()->m_pMainWnd->DestroyWindow();
        }

        else{
            MessageBox(str1,"黒石の数");
            MessageBox(str2,"白石の数");
            MessageBox("引き分けです","勝敗判定");
            AfxGetApp()->m_pMainWnd->DestroyWindow();
        }
    }
 
}

void COsero2Dlg::nothing()
{
    int x,y,no=0,bl=0,wh=0;
    for(x=0;x<MASU_NUM;x++){
        for(y=0;y<MASU_NUM;y++){
            if(Rule(x,y)==FALSE)
                no++;
            if(m_Board[x][y]==BLACK_STONE)
                bl++;
            if(m_Board[x][y]==WHITE_STONE)
                wh++;
        }
    }
    if((no==64)&&(countALL!=60)&&((bl!=0)&&(wh!=0))){
        MessageBox("打つ所がありません");
        MessageBox("手番を変更します");
        AI();

    }
    if(bl==0){
        MessageBox("黒石が無くなったので白の勝ちです");
        AfxGetApp()->m_pMainWnd->DestroyWindow();
    }
    if(wh==0){
        MessageBox("白石が無くなったので黒の勝ちです");
        AfxGetApp()->m_pMainWnd->DestroyWindow();
    }
}





BOOL COsero2Dlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
    if(CurSor==TRUE){
        HCURSOR myCSR;
        if(myCSR){
            ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
            return TRUE;
        }
    }
    
    return CDialog::OnSetCursor(pWnd, nHitTest, message);
}

void COsero2Dlg::OnMouseMove(UINT nFlags, CPoint point) 
{
    // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください
        int x,y;
        x=point.x/MASU_SIZE;
        y=point.y/MASU_SIZE;

        if(Rule(x,y,1,1)){
            CurSor=TRUE;
        
        }
        else if(Rule(x,y,-1,-1)){
            CurSor=TRUE;
        
        }
        else if(Rule(x,y,1,0)){
            CurSor=TRUE;
            
        }
        else if(Rule(x,y,0,1)){
            CurSor=TRUE;
        
        }
        else if(Rule(x,y,-1,0)){
            CurSor=TRUE;
            
        }
        else if(Rule(x,y,0,-1)){
            CurSor=TRUE;
        
        }
        else if(Rule(x,y,1,-1)){
            CurSor=TRUE;
        
        }
        else if(Rule(x,y,-1,1)){
            CurSor=TRUE;
        
        }
        else{
            CurSor=FALSE;
        }
    CDialog::OnMouseMove(nFlags, point);
}

void COsero2Dlg::AI()
{
    int x,y,X,Y;
    for(x=0;x<MASU_NUM;x++){
        for(y=0;y<MASU_NUM;y++){
            if(Rule(x,y)){
                X=x;
                Y=y;
            }
        }
    }
    
        m_Board[X][Y]=WHITE_STONE;
        Reverce( X,Y );    
        Frag=!Frag;
                  countALL++;
        OnPaint();
                  End();
                  nothing();
    
                
                
}


ヘッダファイルはこちらになります
class COsero2Dlg : public CDialog
{
// 構築
public:
    
    BOOL CurSor;
    BOOL Frag;//手番の設定
    BOOL InitFrag;//ボタンがクリックされるまで描写されないようにするBOOL変数
    int num2;//白石の数
    int num1;//黒石の数
    int countALL;//手数を数える。盤がいっぱいになったら勝利判定
    int m_Board[MASU_NUM][MASU_NUM];
    
    
    
    
    void End();//勝利判定をする関数
    int count(int stone);//石を数える
    void nothing();//打つところがない場合の設定
    void Reverce(int x, int y,int v_x, int v_y);
    void Reverce(int x, int y);//裏返しにする関数
    BOOL Rule(int x,int y, int v_x, int v_y);
    void PutStone(int x, int y);//交互に打つように設定をする
    BOOL Rule(int x, int y);//裏返しにできる所のみ置けるようにする設定をする。
    void AI();//コンピューターの設定をする関数
    void shokika();//初期化関数
}



稚拙な所は初心者の為ご容赦下さい。MFCのダイアログベースで作成しました。ダイアログ上のボタンをクリック
すると盤が描画されます。思考ルーチンなんですが今回のはそういう大層なものではなく、置ける場所を
探し出して置く、という単純なものだと思います。OnSetCurSorでは石が置ける場所に限りカーソルを変化
させています。ご質問したいのは打つ所がない場合CPUに手番をチェンジしてるのですが途中でエラーが出て
止まってしまいます。他にも色々危ない感じのがたくさんあるような気もします・・
よろしければ何かアドバイスください。

Mist

Re:オセロ前編

#3

投稿記事 by Mist » 16年前

> エラーが出て止まってしまいます。

ソースの断片のみ掲示する場合はここのところを詳しく説明してください。
見るべきポイントを絞りこまないと回答は得られにくいと思います。

ざこ

Re:オセロ前編

#4

投稿記事 by ざこ » 16年前

成る程、説明しますね。
打つ所がなくなると「打つ所がありません」→「手番を変更します」と表示されその後にAI()を
実行するつもりなのですが「手番を変更します」の後に

『問題が発生しました。プログラムを終了します』 と出てしまいます。

Mist

Re:オセロ前編

#5

投稿記事 by Mist » 16年前

VC環境だったらステップ実行で、「手番を変更します」の後どこまで実行できるのか確認してもらいたいです。

AI関数はちょっと危険な所があります。
もし、forの中のRule関数から一度もTrueが帰ってこない場合、XとYは一度も代入されないので不定値のままになります。
X、Yの不定値がm_Boardの配列数よりも大きい値の場合メモリ破壊が発生します。
「打つ場所がない」=「Rule関数からTRUEが返らない」ですよね?

ざこ

Re:オセロ前編

#6

投稿記事 by ざこ » 16年前

うーん何かRuleの中で止まってますね。
「ハンドルされていない例外はOsero2.exeにあります:0xC0000005:Aceess Violation」とでます。

そうだと思います。ただAI()入れず自分で黒も白も操作してるときはいけてたんですよね。

Mist

Re:オセロ前編

#7

投稿記事 by Mist » 16年前

> if(x>=MASU_NUM && y>=MASU_NUM )return(FALSE);//マス数を超えるような位置には置けない。

これは間違い、ANDじゃなくてORにしないと。
これだとxもyもMASU_NUM以上の時しかFALSEにならないから、片方だけ超えている場合はその後が実行されてしまいます。
これを直せば少なくともRuleで止まることはなくなるのではないでしょうか。

ざこ

Re:オセロ前編

#8

投稿記事 by ざこ » 16年前

次はfor文抜けた所で止まってしましました。

Mist

Re:オセロ前編

#9

投稿記事 by Mist » 16年前

ひとつ質問。

AIを使用しない(人が操作する)場合は正しく動作するんですよね?
その場合、Rule(int x, int y)実行時のxとyの値の範囲を教えてもらえませんか?

Rule(x, y, v_x, v_y)のソースを見る限り、xとyの値によってはm_Boardの範囲外にアクセスします。

AI()はxとyを0~(MASU_NUM-1)の範囲で実行しますが、例えばx=0,y=0の状態で
if(Rule(x,y,-1,-1))return TRUE;//左下
    if(Rule(x,y,0,-1))return TRUE;//上
    if(Rule(x,y,-1,0))return TRUE;//下
    if(Rule(x,y,1,-1))return TRUE;//右上
    if(Rule(x,y,-1,1))return TRUE;//左上
を実行するとRule(引数4個)の
x+=v_x;
    y+=v_y;
のところでx,yのいずれか、もしくは両方が-1になります。

Mist

Re:オセロ前編

#10

投稿記事 by Mist » 16年前

> 次はfor文抜けた所で止まってしましました。

AIも指す所がない場合(forの中でRuleから一度もTRUEが返ってこない)を考慮しないといけないですね。

ざこ

Re:オセロ前編

#11

投稿記事 by ざこ » 16年前

>>Rule(x, y, v_x, v_y)のソースを見る限り、xとyの値によってはm_Boardの範囲外にアクセスします
while(x>=0 &&x<MASU_NUM && y>=0&& y<MASU_NUM){

として範囲外アクセスしないようにできてると思いますがなってないのかな

ざこ

Re:オセロ前編

#12

投稿記事 by ざこ » 16年前

おそらく
int x,y,X,Y;
    for(x=0;x<MASU_NUM;x++){
        for(y=0;y<MASU_NUM;y++){
            if(Rule(x,y)){
                X=x;
                Y=y;
            }
        }
    }
の所だとは思いますがRuleが全てFALSEのときなら
int x,y,X,Y;
    for(x=0;x<MASU_NUM;x++){
        for(y=0;y<MASU_NUM;y++){
            if(Rule(x,y)){
                X=x;
                Y=y;
            }
                            else{continue;}
        }
    }
としてみたんですがやはり同じ症状です。

Mist

Re:オセロ前編

#13

投稿記事 by Mist » 16年前

> x+=v_x;//
> y+=v_y;
>
> if(m_Board[x][y]==0)return(FALSE);//
> if(m_Board[x][y]==put_stone)return(FALSE);

いや、そのwhileよりも前の時点ですでに変更した値でのxとyを使ってm_Boardを参照しているでしょ。
範囲外にリードアクセスするだけであれば停止してしまう確率は低いですが、期待した結果は得られないでしょう。(運良く動く場合もあるでしょうが)
そもそも、Rule(引数2個のほう、むぅC++はこういうときにめんどくさいな)で問答無用で周囲8方向をチェックしているのはまずくないですか?
例えば左上(座標0,0)のマスには右、右下、下方向にしかマスは存在しませんよね。
現状はこの辺の考慮が抜けているように(私には)見えます。
考慮されているということであればご説明していただけますか。

その辺が知りたかったので以下の質問をしたわけですが。
>> AIを使用しない(人が操作する)場合は正しく動作するんですよね?
>> その場合、Rule(int x, int y)実行時のxとyの値の範囲を教えてもらえませんか?

ざこ

Re:オセロ前編

#14

投稿記事 by ざこ » 16年前

AIを使用しないときはAI()使いません。Ruleのxとyの範囲ですけど番の外や石が置いてある所をクリックしても
変化なしですのでともに0~7だと思います。


AIを使用してないときは動きます。こちらのHP参考にしました
http://www.geocities.co.jp/SiliconValle ... index.html
関数名は違ってますが大体似たり寄ったりです。こちらにはミニマックス法がかかれていますが
よくわからなかったので自分でAI作ってみようってことになりました。

Mist

Re:オセロ前編

#15

投稿記事 by Mist » 16年前

m_Board[x][y]が0のときはそのマス目がどういう状態であることを表していますか?

あと、MASU_NUMとかの値がわからないので定数定義も載せてもらえますか?


このプログラムを眺めていると、目に見えるマスの外側に見えない使用禁止のマスを設けているような気がするんだけどなぁ。
コマを置いていいのは1~(MASU_NUM-2)の範囲に限定しているような気がするんですけど。

そうするとRule関数のつくりは納得できるんですが、AI関数のforの値範囲や
> 変化なしですのでともに0~7だと思います。
この回答と矛盾するんですよね。

ざこ

Re:オセロ前編

#16

投稿記事 by ざこ » 16年前

m_Board[x][y]が0とはm_Board[0][0]のことでしょうか?それともm_Board[x][y]=0のことかな?
m_BoardはBOOL変数でTRUEのときに黒石(ここではBLACK_STONE)です,FALSEのときは逆なので
後者なら、m_Board[x][y]=の値はBLACK_STONEかWHITE_STONEしかないと思います。

前者の場合m_Board[0][0]の値はフラグ(手番)によって変わります。

>>あと、MASU_NUMとかの値がわからないので定数定義も載せてもらえますか?

すいません載せてませんでした。
#define BLACK_STONE 1
#define WHITE_STONE -1
#define MASU_NUM 8 //マスの数のことです。8x8なので8
#define MASU_SIZE 50 //マスのサイズのことです。

Mist

Re:オセロ前編

#17

投稿記事 by Mist » 16年前

回答ありがとうございます。質問の意図は後者です。

> m_BoardはBOOL変数でTRUEのときに黒石(ここではBLACK_STONE)です,FALSEのときは逆なので

ますますわからなくなりました。
m_Boardはintで宣言されています。
BLACK_STONEは1、WHITE_STONEは-1で定義されています。
そして、Rule(引数4)には以下のコードがあり
> if(m_Board[x][y]==0)return(FALSE);
m_Board[x][y]==0には、石を置けないというルールが定められているように思います。

ざこさんの理解とソースコードは既に一致していないように思います。
まずはAIをどうするかよりも、もう一度原点に立ち返ってプログラムの理解を深められたほうがAIが動かない理由が見えてくるのではないでしょうか。

ざこ

Re:オセロ前編

#18

投稿記事 by ざこ » 16年前

あああ、すいません。何もない状態がm_Board[x][y]==0でした。
若干理解不足の所があるようです。

Mist

Re:オセロ前編

#19

投稿記事 by Mist » 16年前

2個のRule関数の戻り値の意味を明確にしてもらえますか?

Rule(引数2)
TRUE=
FALSE=

Rule(引数4)
TRUE=
FALSE=

ざこ

Re:オセロ前編

#20

投稿記事 by ざこ » 16年前

TRUEのときだけ実行される
FALSEのときは実行されない。4つのときも同じと思います。

Mist

Re:オセロ前編

#21

投稿記事 by Mist » 16年前

> 実行される

回答がちょっと不明瞭ですね。
「何が」実行される・されないですか?

私が欲しい回答は「TRUE(FALSE)のときx,yのマスは~~な状態を意味する」というような感じです。
ここが明確にならないとRule関数の処理は正しいのか、AIをどう作ればいいのかが明確になりません。

ざこ

Re:オセロ前編

#22

投稿記事 by ざこ » 16年前

なるほどそうでしたか。2つのほうは4つの方を方向指定してるだけですよね。


例えば
if(m_Board[x][y]==0)return(FALSE); ですが

進めた先が空白のとき押してもRuleからは外れます
つまりOnLButtonのif(Rule(x,y)から下の文は実行されない状態を意味する。(描写、リバース、手番変更、判定など)
TRUEのときのみそのx,y使ってOnLButtonのRuleから下の文を実行する状態を意味する。

Mist

Re:オセロ前編

#23

投稿記事 by Mist » 16年前

う~ん、ちょっと期待していた回答と違うかな。

> つまりOnLButtonのif(Rule(x,y)から下の文は実行されない状態を意味する。(描写、リバース、手番変更、判定など)
> TRUEのときのみそのx,y使ってOnLButtonのRuleから下の文を実行する状態を意味する。

それは、ソースそのままなので見ればわかります。
実行できる(できない)ということはそのマスがどういう状態にあるからなのかを知りたいのですが。

余り質問ばかりしていても長くなるだけなのでRuleとAI関数を範囲外アクセスしないように改造しました。
ざこさんが期待する動作をするかどうかわかりませんが(特にAI)、ソフトが落ちることは無いと思います。
BOOL COsero2Dlg::Rule(int x, int y, int v_x, int v_y)
{
    int put_stone;
    if(Frag==FALSE)
        put_stone=WHITE_STONE;
    else
        put_stone=BLACK_STONE;

    x+=v_x;
    y+=v_y;

    // ★範囲内チェック
    if (x>=0 && x<MASU_NUM) return(FALSE);  // ★
    if (y>=0 && y<MASU_NUM) return(FALSE);  // ★

    if(m_Board[x][y]==0)return(FALSE);
    if(m_Board[x][y]==put_stone)return(FALSE);

    x+=v_x;
    y+=v_y;

    while(x>=0 &&x<MASU_NUM && y>=0&& y<MASU_NUM){
        if(m_Board[x][y]==0)return(FALSE);
        if(m_Board[x][y]==put_stone)return(TRUE);

        x+=v_x;
        y+=v_y;
    }
    
    return FALSE;
}

void COsero2Dlg::AI()
{
    int x,y,X,Y;
    for(x=0;x<MASU_NUM;x++){
        for(y=0;y<MASU_NUM;y++){
            if(Rule(x,y)){
                X=x;
                Y=y;
                break;          // ★石を置く所が見つかったのだからループ終了
            }
        }
    }
    // ★置ける所があったかどうかのチェック
    if (x >= MASU_NUM) {
        // ★置ける場所がなかった場合に必要な処理があれば追加してください
        return;
    }
    m_Board[X][Y]=WHITE_STONE;
    Reverce( X,Y ); 
    Frag=!Frag;
    countALL++;
    OnPaint();
    End();
    nothing();
}

ざこ

Re:オセロ前編

#24

投稿記事 by ざこ » 16年前

>if (x>=0 && x<MASU_NUM) return(FALSE); // ★
if (y>=0 && y<MASU_NUM) return(FALSE); // ★


はおかしくないですか?x>0 x<MASU_NUMのときに条件を満たすんじゃないかと思います。
試してみましたがこれがあると自身が打てないですね。

プログラムがどうのじゃなくて中身がどうなってるってのはちょっと難しいですね・・
初心者の私には表面上のことしかわからないかも

Mist

Re:オセロ前編

#25

投稿記事 by Mist » 16年前

ごめんなさい、ちゃんと確認していなかった。

if (!(x>=0 && x<MASU_NUM))



if (x < 0 || x >= MASU_NUM)

です。(yも同様)

ざこ

Re:オセロ前編

#26

投稿記事 by ざこ » 16年前

if(x>=MASU_NUM){
return;
}

の所も何かおかしいですね。実行するとAIが作動しなくこのときのxは8になっていました。

Mist

Re:オセロ前編

#27

投稿記事 by Mist » 16年前

ループの中のbreakは追加されましたよね?

その上でそこに来るなら、最初の指摘どおりRuleから一度もTRUEが返ってきていないんじゃないですか?

> if(Rule(x,y)){
> X=x;
> Y=y;
> break; // ★石を置く所が見つかったのだからループ終了
> }

この部分はざこさんの元のソースにbreak追加しただけですが、Rule関数がTRUEになるときに白石を置ける場所のx,yが取得できるですよね?(ざこさんの説明だけでは私にはそこまで判断できませんでしたが)

ざこ

Re:オセロ前編

#28

投稿記事 by ざこ » 16年前

ちょっとデバッグしてみていますがRuleが0~8まで実行されてるんですよね。
おかしいな・・

Mist

Re:オセロ前編

#29

投稿記事 by Mist » 16年前

たびたびごめんなさい。

以下のように修正してみて。
for(x=0;x<MASU_NUM;x++){
        for(y=0;y<MASU_NUM;y++){
            if(Rule(x,y)){
                X=x;
                Y=y;
                break;          // ★石を置く所が見つかったのだからループ終了
            }
        }
        if (y < MASU_NUM)    break;
    }

ざこ

Re:オセロ前編

#30

投稿記事 by ざこ » 16年前

動く事は動きますが、やはり手番を変更しますの後にソフトが落ちますね。

Mist

Re:オセロ前編

#31

投稿記事 by Mist » 16年前

落ちる場所と落ちるときのXとYの値はわかりますか?

ざこ

Re:オセロ前編

#32

投稿記事 by ざこ » 16年前

さっき原因?がわかったんですがMistさんのご指摘通りXとYが-○○○○○になっており
X<0 X>MASU_NUMのときFALSEにするととりあえずエラーで落ちる事はなくなりましたが、
希望通りってわけにはいかなかったので少し取り組んでみます。長時間ありがとうございました。
またわからなかったらご質問させていただきますね。

Mist

Re:オセロ前編

#33

投稿記事 by Mist » 16年前

落ちることはなくなりましたか。
とりあえずですが良かったです。
こちらこそ途中で未確認のソース提示してしまいまして申し訳ありませんでした。

No:28563に追記されたHPアドレスに今気が付いて見てみました、私が指摘していたこと(範囲チェック)はHPのプログラムではきちんと導入されていますね(^^;
もう一度見直されてみるのもいいかもしれません。

閉鎖

“C言語何でも質問掲示板” へ戻る