オセロで、石を反転する範囲の捜索の仕方がわかりません

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#61

投稿記事 by softya(ソフト屋) » 12年前

何処ら辺がわからないか書いてもらわないと返答しようがないのですが、再帰処理自体の仕組みは調べられましたか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#62

投稿記事 by sadora3 » 12年前

仕組み・・・は多分わからないと思います。
スタックという単語を見た覚えがあります。
10の階乗をやってみようと思ったのですが、何をどうすればいいのかさっぱり分かりませんでした。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#63

投稿記事 by softya(ソフト屋) » 12年前

sadora3 さんが書きました:仕組み・・・は多分わからないと思います。
スタックという単語を見た覚えがあります。
10の階乗をやってみようと思ったのですが、何をどうすればいいのかさっぱり分かりませんでした。
C言語のアルゴリズムの勉強をされたことはありますか?
結局ゲームは、C言語の様々なアルゴリズムや再帰処理などテクニックを使わないと組めない難易度が高くなりがちな分野です。
特にパズルやオセロなどは再帰処理を始めとして簡易なAIなど様々な知識を必要とします。
そこを勉強する気がなかったり、勉強する方法を見つけられないと前に進めないと思ってもらうしか無いのです。厳しい言い方かも知れませんが現実的にそうなのです。

階乗の答えでもありますが、参考サイトです。
「パズル問題解法のアルゴリズム」
http://www.ic-net.or.jp/home/takaken/pz/index.html
読んだ上で、見ずに階乗のプログラムを自分で組んでみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#64

投稿記事 by sadora3 » 12年前

なるほど。勉強になりました。

コード:

#include <stdio.h>
int F(int);
int main(){
        int a;
        a = F(10);
        printf("%d\n" , a);
        return 0;
}

int F(int N){
        int a;
        if( N == 1 ){ a = 1; }
        else a = N * F(N-1);
        return a;
}
10階乗はこうですね。
次はどうすればいいのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#65

投稿記事 by softya(ソフト屋) » 12年前

それじゃ練習として再帰で、オセロの(1,1)から(8,8)までのポイントに白を置く関数を書いてみて下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#66

投稿記事 by sadora3 » 12年前

すみません・・・。ヒント下さい・・・。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#67

投稿記事 by softya(ソフト屋) » 12年前

分からないにしても出来る限りのコードを書いてもらえないでしょうか。
ヒントは、今までの内容を見なおして下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
Tatu
記事: 445
登録日時: 15年前
住所: 北海道

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#68

投稿記事 by Tatu » 12年前

>>sadora3 さん

softya(ソフト屋) さんの書いた
再帰で、オセロの(1,1)から(8,8)までのポイントに白を置く関数について
どこまで考えられたでしょうか?

(1)この関数を呼び出したとき、どのポイントが白になればよいのでしょうか

(2)この関数の引数はどうなると思いますか

(3)あるポイントに白を置く処理はどう書きますか

(4)あるポイントに白を置いた次のポイントはどう表現しますか

(5)この関数の定義の中でこの関数を呼び出すかどうかをどう判定しますか

たいちう
記事: 418
登録日時: 15年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#69

投稿記事 by たいちう » 12年前

再帰の初歩的な使い方については、自分で考えろというのは酷ではないでしょうか。
階乗やフィボナッチ数列の例しか初心者には見つけられず、
それ以上の使い方を考えだせる人は少数派なのでは?

せめてアルゴリズムを日本語で説明するとかしないと、
知らない人には雲をつかむような話ではないかと思います。

このように私は考えますので、再帰で白を置く関数を書いてみました。
見るかどうかはsadora3さんが判断してください。
► スポイラーを表示

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#70

投稿記事 by sadora3 » 12年前

tatuさん。たいちうさん。ありがとうございます。
tatuさんのヒントを頼りに、たいちうさんのは見ずに頑張ってみようかと思います。

アバター
Tatu
記事: 445
登録日時: 15年前
住所: 北海道

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#71

投稿記事 by Tatu » 12年前

>>sadora3 さん
私の書いたことを頼りにするつもりでしたら

(1)この関数を呼び出したとき、どのポイントが白になればよいのでしょうか

についてどう考えているかを書いてください。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#72

投稿記事 by sadora3 » 12年前

全てのマスが白になればいいかと・・・。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#73

投稿記事 by softya(ソフト屋) » 12年前

sadora3 さんが書きました:全てのマスが白になればいいかと・・・。
そういう誤解の余地があるんですね。言葉が足りませんでした。
それでは、ルールを書き加えて(1,1)から(8,8)まで直線で白を置いて下さい。
(1,1),(2,2)・・・・(8,8)と白を置きます。
その他の盤面は何も置いていない状態とします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#74

投稿記事 by sadora3 » 12年前

コード:

WhiteLine(1);

void WhiteLine( int a ){
	if( a==9 ){ return; }
	BanData[ a ][ a ] = SIRO;
	WhiteLine( a+1 );
}
そういうことでしたかw
誤解してすみません。こうでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#75

投稿記事 by softya(ソフト屋) » 12年前

それでOKですよ。
じゃあ、今後のためにx,yは別引数にして、かつ盤面の外側が-1で埋まっていたはずですので、それを判断して止まるように変えてもらえますか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#76

投稿記事 by sadora3 » 12年前

出来ました。WALLは#defineで-1に置換しています

コード:

WhiteLine( 1 , 1 );

void WhiteLine( int y , int x ){
             if( BanData[ y ][ x ] == WALL ){ return; }
             BanData[ y ][ x ] = SIRO;
             WhiteLine( y+1 , x+1 );
}

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#77

投稿記事 by ISLe » 12年前

プログラミングのできるひとというのは、日本語でも抽象的な説明ができるひとだと思うんですよね。

経験としての話ですが…
プログラミングに慣れていないひとは、「どこ」と問われたら、具体的にマスの位置を答えようとします。
ひとつのマスに絞れないので結果から求めてしまう。
結果だけを求めているように見える。

プログラミングに慣れているひとは、この程度だと、引数x,yが示すマスを現在注目しているマスとする、とか、現在注目しているマスを引数x,yで示す、とかの設計や実装にあたる作業を無意識に一瞬で済ませてしまいます。
プログラミングに慣れていないひとは、「現在注目しているマス」という考え方からしてできない。
関数原型すら作れず手も足も出ない。

#書いてるうちに進んでた。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#78

投稿記事 by softya(ソフト屋) » 12年前

つづいて、これを改造していきます。
置く色を引数に追加しましょう。SIROの部分をWhiteLineの引数とするわけです。

ISLeさん、ありがとうございます。
やはり、抽象化がネックなんでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#79

投稿記事 by sadora3 » 12年前

コード:

WhiteLine( 1 , 1 , 1 );

void WhiteLine( int y , int x , int S ){
	if(BanData[ y ][ x ] == WALL ){ return; }
	BanData[ y ][ x ] = S;
	WhiteLine( y+1 , x+1 , 1 );
}
これであってますか?

追記;すみません。デバックせずに張ってました。修正しました。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#80

投稿記事 by ISLe » 12年前

softya(ソフト屋) さんが書きました:ISLeさん、ありがとうございます。
やはり、抽象化がネックなんでしょうか?
変数で何かを示すという基本的なところですけどね。

そういう意味では、動作が変わらなくても変数名にこだわることが重要かもしれません。
文章のように読める、読み易いコードにも繋がると思います。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#81

投稿記事 by softya(ソフト屋) » 12年前

せっかく引数にしたのに、WhiteLineの再帰呼び出し時に使っていませんね。これを直しましょう。
それとSの引数変数名はSIRO/KUROどちらでも使えるような変数名を考えてみて下さい。
最初の呼び出しもWhiteLine( 1 , 1 , SIRO );とすべきです。

あと今更ですが、WhiteLine( int y , int x ,よりはWhiteLine( int x , int y ,の方が後々混乱しないと思うので今のうちに直しましょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#82

投稿記事 by sadora3 » 12年前

コード:

WhiteLine( 1 , 1 , SIRO );

void WhiteLine( int x , int y , int C ){
    if(BanData[ y ][ x ] == WALL ){ return; }
    BanData[ y ][ x ] = C;
    WhiteLine( y+1 , x+1 , C );
}
こうでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#83

投稿記事 by softya(ソフト屋) » 12年前

コードとしてはOKだと思います。
ただ、Cは何かの略だと思いますが変数名として意味がわからないほど短い気がしますね。もっと良い名前を考えてみましょう。

次の改造は斜め以外に対応するために方向を追加しますが、前回苦しんでいるのでx,yの増加分を引数とする形にしようと思います。
y+1 , x+1 の+1をx,yで分けて引数にします。そうすれば、引数を変えるだけで好きな方向に白い線を引くことができますよね。

引数を追加した場合の最初の呼び出し。
WhiteLine( 1 , 1 , 1 , 1 , SIRO ); //右下へ
// いろんなパターン
WhiteLine( 1 , 1 , 1 , 0 , SIRO ); //右へ
WhiteLine( 1 , 1 , 0 , 1 , SIRO ); //下へ
WhiteLine( 4 , 4 , -1 , -1 , SIRO );//左上へ
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#84

投稿記事 by sadora3 » 12年前

コード:

WhiteLine( 1 , 1 , 1 , 1 , SIRO );

void WhiteLine( int x , int y , int Way_x , int Way_y , int Color ){
    if(BanData[ y ][ x ] == WALL ){ return; }
    BanData[ y ][ x ] = Color;
    WhiteLine( x + Way_x , y + Way_y , Way_x , Way_y , Color );
}
出来ました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#85

投稿記事 by softya(ソフト屋) » 12年前

それじゃ、またまた機能追加で何個置けたか戻り値で返すようにしましょうか。※ 今後のための機能です。
int WhiteLine( int x , int y , int Way_x , int Way_y , int Color, int count )
にしてcountで置けた数を再帰的にカウントアップして、returnで最終的に置けた個数を返しますが、再帰でうまくカウントされるようにしないと行けません。
それを考えてみて下さい。

最初の呼び出しは
int IshiCount = WhiteLine( 1 , 1 , 1 , 1 , SIRO, 0 );//初期のカウントは0個
となります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#86

投稿記事 by sadora3 » 12年前

コード:

int IshiCount = WhiteLine( 1 , 1 , 1 , 1 , SIRO, 0 );

int WhiteLine( int x , int y , int Way_x , int Way_y , int Color , int count){
    if(BanData[ y ][ x ] == WALL ){ return count; }
    BanData[ y ][ x ] = Color;
    WhiteLine( x + Way_x , y + Way_y , Way_x , Way_y , Color , count + 1 );
}
こうでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#87

投稿記事 by softya(ソフト屋) » 12年前

おしいですね。エラーになりませんかこれ?
再起した時の戻り値の処理がありませんよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#88

投稿記事 by sadora3 » 12年前

再起した時の戻り値とはなんでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#89

投稿記事 by softya(ソフト屋) » 12年前

再帰におけるWhiteLineの戻り値が処理されていないって事です。
あとプログラムの流れ次第でreturn 値;が無い流れがあるのも問題です。

コンパイラで警句が出るはずなんですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#90

投稿記事 by sadora3 » 12年前

うーん・・・コンパイル時、一瞬「値を返さない~」みたいなメッセージが出てきますが、その後ちゃんと実行されてました。戻り値は4行目のreturn count;があると思うのですが・・・。

Priest
記事: 123
登録日時: 12年前
住所: 愛知

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#91

投稿記事 by Priest » 12年前

sadora3 さんが書きました:

コード:

int IshiCount = WhiteLine( 1 , 1 , 1 , 1 , SIRO, 0 );

int WhiteLine( int x , int y , int Way_x , int Way_y , int Color , int count){
    if(BanData[ y ][ x ] == WALL ){ return count; }
    BanData[ y ][ x ] = Color;
    WhiteLine( x + Way_x , y + Way_y , Way_x , Way_y , Color , count + 1 );
}
こうでしょうか?
処理を追ってみましょう。
WhiteLine( 1 , 1 , 1 , 1 , SIRO, 0 ); BanData[1][1]に白が置かれます
再帰→ WhiteLine( 2 , 2 , 1 , 1 , SIRO, 1 ); BanData[2][2]に白が置かれます
再帰→ WhiteLine( 3 , 3 , 1 , 1 , SIRO, 2 ); BanData[3][3]に白が置かれます
……
再帰→ WhiteLine( 8 , 8 , 1 , 1 , SIRO, 7 ); BanData[8][8]に白が置かれます
再帰→ WhiteLine( 9 , 9 , 1 , 1 , SIRO, 8 ); BanData[9][9]に白を置こうとしますが、BanData[9][9]は壁なので8を返します。

WhiteLine( 8 , 8 , 1 , 1 , SIRO, 7 )の6行目に返ってきました。この返り値をWhiteLine( 7 , 7 , 1 , 1 , SIRO, 6 )に渡してあげたいですが、返り値を返せません。

コード:

#include <Priest.h>
int MyPolicy ( void ) { printf( "何事も楽しくね!" ); return 0; }

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#92

投稿記事 by softya(ソフト屋) » 12年前

実行はされると思います。警告ですから。

>戻り値は4行目のreturn count;があると思うのですが・・・。

4行目のreturnは、1つ前の関数に戻るだけです。
それ以前には戻りません。

じゃあ、勉強になると思うのでデバッガで4行目でブレークしてF10トステップトレースしてみて下さい。
流れがわかると思います。

「デバッガの使い方」
http://ext-web.edu.sgu.ac.jp/koike/semi/VC2005/c17.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#93

投稿記事 by sadora3 » 12年前

遅れてすみません。

コード:

int WhiteLine( int x , int y , int Way_x , int Way_y , int Color , int count){
	int a;
	if( BanData[ y ][ x ] == WALL ){ return count; }
		BanData[ y ][ x ] = Color;
		a = WhiteLine( x + Way_x , y + Way_y , Way_x , Way_y , Color , count + 1 );
	return a;
}
これであってますか?
デバッガ使うとプログラムの流れが凄くわかりやすくなりますね。
Priestさん回答ありがとうございました。
Priestさんの言っていることが少し理解できませんでしたが、デバッガを使って良く理解出来ました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#94

投稿記事 by softya(ソフト屋) » 12年前

okですが、インデントが変です。

コード:

int WhiteLine( int x , int y , int Way_x , int Way_y , int Color , int count){
    int a;
    if( BanData[ y ][ x ] == WALL ){ return count; }
    BanData[ y ][ x ] = Color;
    a = WhiteLine( x + Way_x , y + Way_y , Way_x , Way_y , Color , count + 1 );
    return a;
}
それと安易にaなどと名前をつけるのは止めましょう。

それとこう書く方法もあります。※ 弱点:戻り値をデバッグしにくい。

コード:

int WhiteLine( int x , int y , int Way_x , int Way_y , int Color , int count){
    if( BanData[ y ][ x ] == WALL ){ return count; }
    BanData[ y ][ x ] = Color;
    return  WhiteLine( x + Way_x , y + Way_y , Way_x , Way_y , Color , count + 1 );
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#95

投稿記事 by sadora3 » 12年前

分かりました。変数の名前は何か考えて変えておきます。
次は何をすればよろしいのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#96

投稿記事 by softya(ソフト屋) » 12年前

ちょっと思い出すのに時間がかかりました。
これで、任意の方向に石を置くだけの処理は出来ましたね。
既に白だけじゃないのでWhiteLine()でなくPutLine()が正しいかもしれませんが名前も考えておいて下さい。
関数名は動詞+名詞を基本とすることがお勧めです。

さて、次は置く場所の盤の状態を見て置くかどうか決める処理を追加します。
本物のオセロなら石をひっくり返すのですが、この場合は上書きしてしまいましょう。
基本的はWALLと同じですが、同じ色なら、違う色なら、空きならの条件を追加しましょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#97

投稿記事 by sadora3 » 12年前

コード:

int PutLine( int x , int y , int Way_x , int Way_y , int Color , int count){
	int BackValue;
	if( BanData[ y ][ x ] == WALL ){ return count; }
	else if( BanData[ y ][ x ] != Color ){ BanData[ y ][ x ] =Color; }
	else if( BanData[ y ][ x ] ==Color ){ return count; }
	else if( BanData[ y ][ x ] == BAN ){ return count; }
	BackValue = PutLine( x + Way_x , y + Way_y , Way_x , Way_y , Color , count + 1 );
	return BackValue;
}
こうでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#98

投稿記事 by softya(ソフト屋) » 12年前

その順番だとうまく行かないと思います。
テストプログラムを組んで試してみて下さい。
テストプログラムは、今後の動作確認のためにも必要です。

それとBackValueよりBackCountの方が良いですかね。
あるいはRetrunCountとかTotalCountとか。countであると言う意味は残っていたほうが良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
asd
記事: 319
登録日時: 15年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#99

投稿記事 by asd » 12年前

目の前にプログラムを実行し、デバッグする環境があるのですから、
作ってみたものに対してテストデータ(テスト用の盤面データ)を用意し、適当な引数を与えて関数を呼び出せば
自分が想定している動作をしているかどうかすぐに確認できると思います。

softyaさんも指摘していますが、自分で作ったものはまず自分でテストして確認してみましょう。
そのうえで動作がおかしい場合には、
1.想定している動作(こうなってほしい動作)
2.実際の動作(与えたパラメータ、結果)
を添えて質問するようにしないと、回答者のみなさんに公開デバッグをお願いするような形になってしまい
自分の身にならないですよ。

ちなみに、盤面データBanDataの初期化・宣言部分を#ifdefなどで
切り分けてテスト用盤面を用意しておくと、今後デバッグ、テストをするうえで
楽になりますよ^^

コード:

#ifdef DEBUG
//テスト用初期盤面
static int BanDate[10][10]={
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
    {-1,0,1,1,1,1,1,1,1,-1},
    {-1,2,1,0,0,0,0,0,2,-1},
    {-1,2,0,1,0,0,0,0,2,-1},
    {-1,2,0,0,1,2,0,0,2,-1},
    {-1,2,0,0,2,1,0,0,2,-1},
    {-1,2,0,0,0,0,1,0,2,-1},
    {-1,2,0,0,0,0,0,1,2,-1},
    {-1,2,1,1,1,1,1,1,0,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};
#else
//初期盤面
static int BanDate[10][10]={
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
    {-1,0,0,0,0,0,0,0,0,-1},
    {-1,0,0,0,0,0,0,0,0,-1},
    {-1,0,0,0,0,0,0,0,0,-1},
    {-1,0,0,0,1,2,0,0,0,-1},
    {-1,0,0,0,2,1,0,0,0,-1},
    {-1,0,0,0,0,0,0,0,0,-1},
    {-1,0,0,0,0,0,0,0,0,-1},
    {-1,0,0,0,0,0,0,0,0,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};
#endif
こうしておくとプロプロセッサ(ビルドオプション)でDEBUGというシンボルが定義(#define DEBUGでも可)されているときは、初期盤面がテスト用の盤面に置き換わります。
本当の初期盤面からテストすると望んだ状況を作るのは難しいので、こういう方法で考えられる石の配置を自分で用意して
それにたいして関数を呼び出して望んだ動作をしてくれるか確認するといいですよ。

ちなみに上のテスト盤面では左上は白も黒も1個も取れない場所、右下は白も黒も裏返すことができる場所になっています。
Advanced Supporting Developer
無理やりこじつけ(ぉ

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#100

投稿記事 by sadora3 » 12年前

うーん・・・。何をすればいいのか分からなくなってきました。
「置く場所の盤の状態を見て置くかどうか決める処理」とはなんでしょうか?
この処理は何が出来るようになるのでしょうか?
asdさんのテスト用の盤面の左上からどちらも裏返せますか?

それと公開デバッグみたいになっていてすみませんでした。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#101

投稿記事 by softya(ソフト屋) » 12年前

> 「置く場所の盤の状態を見て置くかどうか決める処理」とはなんでしょうか?

別の色の石なら石をひっくり返します。それ以外なら処理を止めてひっくり返せた数を返します。つまりオセロの処理の根幹です。
これは無意識にオセロで人間がやっていることを明文化し、コンピュータに分かるようにすることそのものです。
こういう事がプログラミングをすると言うことで、人の無意識な部分を含めて明文化しないといけません。

それと今更かもしれませんが、オセロをプログラミングするのが苦手な人がいます。
アクションとか動くものを創るほうが楽しい人ですね。
なので、オセロを絶対にやる必然はありません。
将棋やチェスなどAI系が好きな人には凄く好まれる題材ではありますけどね。

【補足】
「全く知らない人にも分かるオセロ入門」と言うマニュアルを文章だけで書くのに等しいので、オセロの説明文が文章でスラスラ出てくるぐらい頭の中で整理されている必要があります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ただの屍のようだ

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#102

投稿記事 by ただの屍のようだ » 12年前

ゲーム作りはなかなか楽しいよね・・・
初心者の自分からすると、盤面が二次元配列である以上。
二次元配列(盤面)、白1、黒2、空0、壁-1、自分のスコア(int)、相手のスコア(int)、終了条件(int)
置く判定
1.0である。
2.置いた場合、スコアが伸びる
反転の判定
1.隣に他の色がある、自分の色にぶつかったら間にある色をかえる、壁にぶつかったらなにもしない
2.8方向調べて、スコアの伸び数を返す
パス:置かずにターンを終了させる
終了判定:互いがパスを選んだらゲーム終了。(*空のマスがあっても終了させる)
これなら、構造体やら再帰やらめんどうなことしなくてすむと思う。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#103

投稿記事 by sadora3 » 12年前

if( BanData[ y ][ x ] != Color ){
これですと、もしcolorが1なら1以外という意味になってしまいますよね。
1ならば2、2ならば1という風にしなければなりませんよね。
この処理はどうすればいいのでしょうか?

ただの屍のようださんのやり方ですが、私一人だとそれでも書けない気がします・・・。
ソフト屋さんが一から教えて下さっているので、その方法でやろうと思います。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#104

投稿記事 by softya(ソフト屋) » 12年前

sadora3 さんが書きました:if( BanData[ y ][ x ] != Color ){
これですと、もしcolorが1なら1以外という意味になってしまいますよね。
1ならば2、2ならば1という風にしなければなりませんよね。
この処理はどうすればいいのでしょうか?
そこを上手く行かせるために処理の順番が重要なんですね。
単一の答えしか無い==で処理できるものを先に処理して、複数の値が該当してしまう!=は一番最後です。
そうすれば、変な条件分岐は起きないはずですよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#105

投稿記事 by sadora3 » 12年前

コード:

int PutLine( int x , int y , int Way_x , int Way_y , int Color , int count){
    if( BanData[ y ][ x ] == BAN ){ return count; }
    else if( BanData[ y ][ x ] == Color ){ return count; }
    else if( BanData[ y ][ x ] == WALL ){ return count; }
    else if( BanData[ y ][ x ] != Color ){ BanData[ y ][ x ] = Color; }
    return PutLine( x + Way_x , y + Way_y , Way_x , Way_y , Color , count + 1 );
}
おおおお!なるほど!こういうことですね?
戻り値はPutLine関数をそのまま書くことにしました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#106

投稿記事 by softya(ソフト屋) » 12年前

ごめんなさい。
話の間が開いたので、どこからの続きの話になるか探せてませんので、このママ強引に続けさせてもらうとして、この関数を呼び出す形で指定した場所から8方向に置く処理を作ってみてください。その時、置ける数のトータルもカウントしてください。

8つの方向は構造体配列を使うと簡単に作れます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
asd
記事: 319
登録日時: 15年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#107

投稿記事 by asd » 12年前

sadora3 さんが書きました: asdさんのテスト用の盤面の左上からどちらも裏返せますか?
回答が遅くなってしまったので今更感満載ですが、左上はおけそうだけど、どちらもおけない場所です。
白も黒も両方置けるのは右下ですよー(*´ヮ`)
Advanced Supporting Developer
無理やりこじつけ(ぉ

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#108

投稿記事 by sadora3 » 12年前

理解力が乏しくてすみません。
「この関数を呼び出す形で指定した場所から8方向に置く処理」とありますが、PutLine関数の中は書き換わりますか?また、「置く処理」とは、色を反転させるのですよね?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#109

投稿記事 by softya(ソフト屋) » 12年前

置く処理は自分の色を置いて、その時に自分の色に挟まれた逆の色を自分の色にひっくり返すことです。オセロの基本的なルールですよね?[追記・補正]
反転がない=置けない場合は置いたことを取り消する処理も出来れば入れてください。

PutLine関数の中は書き換わりますか? → 書き換える必要はないはずです。

度々質問されますが、オセロのルールを逸脱した機能を作ろうとした事はありません。
全てオセロのルールですので再確認をお願いします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#110

投稿記事 by sadora3 » 12年前

コード:

void AllWayPut(){
    int StoneCount = 0;
    struct AllWay{
        int X;
        int Y;
    } Cheak[] = {
        { 0 , -1 }, { 1 , -1 }, { 1 , 0 }, { 1 , 1 },
        { 0 , 1 }, {-1 , 1 }, { -1 , 0 }, { -1 , - 1 },
    };
    if( BanData[ masuY ][ masuX ] == BAN ){
        BanData[ masuY ][ masuX ] = KURO;
        for(int i = 0; i < 8; i++ ){
    StoneCount += PutLine( masuX + Cheak[i].X , masuY + Cheak[i].Y , Cheak[i].X , Cheak[i].Y , SIRO , 0 );
        }
    }
}
こんな感じでしょうか?
「置けない場合は置いたことを取り消する処理」はPutLine関数の中を書き換えますか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#111

投稿記事 by softya(ソフト屋) » 12年前

置けない場合というのはどういう場合でしょうか?
「置けない場合は置いたことを取り消する処理」はPutLine関数の中を書き換えますか? → ほんとうに必要になりますか?
オセロの基本的なルールですが、「置けない場合は置いたことを取り消す場合」とはどういう場合にどの石に発生するのでしょうか?

【補足】
asdさんも書いてくれていますが、動作確認を自分でしてください。
私がOKだしたらOKだと思っているなら間違いです。
自分で動作確認して自信があったら「出来ました」であり、上手く行かなかったら「こういう問題があります」と書いてください。
テスト方法も考えて、テストルーチンも添えて掲載してもらったほうが良いでしょう。

私に任せすぎて思考停止していなか心配になって来ました。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#112

投稿記事 by sadora3 » 12年前

コード:

void AllWayPut(){
    int StoneCount = 0;
    struct AllWay{
        int X;
        int Y;
    }Cheak[] = {
        { 0 , -1 }, { 1 , -1 }, { 1 , 0 }, { 1 , 1 },
        { 0 , 1 }, {-1 , 1 }, { -1 , 0 }, { -1 , - 1 },
    };
    if( BanData[ masuY ][ masuX ] == BAN ){
        BanData[ masuY ][ masuX ] = SIRO;
        for( int i = 0 ; i < 8 ; i++ ){
        StoneCount += PutLine( masuX + Cheak[i].X , masuY + Cheak[i].Y , Cheak[i].X , Cheak[i].Y , SIRO , 0 );
        }
    }
}
すみません。勘違いをしていました。
>反転がない=置けない場合は置いたことを取り消する処理も出来れば入れてください。
まず八方向に反転した後に、白石で挟まれていなかった場合の反転された石を黒石に戻すと思っていましたが、そもそも反転出来ない場合はその方向には反転しないのですね。
取り消す石は、白石で挟むために最初に置く白石一個だけですね。

これで八方向に石を置き、その置いた石の総数をカウントします。
反転出来ない方向の模索の仕方はどうすればいいのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#113

投稿記事 by softya(ソフト屋) » 12年前

インデントが間違っていますが、プログラムとしてはOKだと思います。
ただ、上にも書いた通りテストコード込みでお願いしたいです。
あと取り消す処理がないので、次のバージョンでは置けないときは取り消す処理と、ひっくり返した総数をAllWayPutの戻り値で返すようにしてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#114

投稿記事 by sadora3 » 12年前

すみません、インデントはどこがおかしいのでしょうか?
あとテストコードとはなんでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#115

投稿記事 by softya(ソフト屋) » 12年前

beatleさん作成の「投稿前チェックリスト チェック3 : インデントを揃えよう」を御覧ください。
「mixcpp/投稿前チェックリスト - PukiWiki」
http://uchan.net/w/index.php?mixcpp%2F% ... 5%B9%A5%C8
空白4個の字下げはタブ1個でも構いません。

>あとテストコードとはなんでしょうか?

asdさんが書いてくれたコードでメインを含めて動作確認するためのコードです。
動作確認のためには余分なコードもなく良いと思うのですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#116

投稿記事 by sadora3 » 12年前

コード:

static int BanData[ BAN_TATE ][ BAN_YOKO ] =
{
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
    {-1,0,1,1,1,1,1,1,1,-1},
    {-1,2,0,0,0,0,0,0,2,-1},
    {-1,2,0,0,0,0,0,0,2,-1},
    {-1,2,0,0,0,0,0,0,2,-1},
    {-1,2,0,0,0,0,0,0,2,-1},
    {-1,2,0,0,0,0,0,0,2,-1},
    {-1,2,0,0,0,0,0,0,2,-1},
    {-1,2,1,1,1,1,1,1,0,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
    };

while(ProcessLoop() == 0){
    DrawBoard();
    MouseRelate();
    ScreenFlip();
}


int MouseRelate(){
    int mouseX = 0;
    int mouseY = 0;
    GetMousePoint(&mouseX, &mouseY);
    masuX = mouseX / BAN_SIZE;
    masuY = mouseY / BAN_SIZE;
    if((GetMouseInput() & MOUSE_INPUT_LEFT) != 0){    AllWayPut();    }
    return 0;
}

int PutLine(int x, int y, int Way_x, int Way_y, int Color, int count){
    if(BanData[ y ][ x ] == BAN){    return count;    }
    else if(BanData[ y ][ x ] == Color){    return count;     }
    else if(BanData[ y ][ x ] == WALL){    return count;    }
    else if(BanData[ y ][ x ] != Color){BanData[ y ][ x ] = Color;}
    return PutLine(x + Way_x, y + Way_y, Way_x, Way_y, Color, count + 1);
}

int AllWayPut(){
    int StoneCount = 0;
    struct AllWay{
        int X;
        int Y;
    }Cheak[] = {
        {0, -1}, {1, -1}, {1, 0}, {1, 1 },
        {0, 1}, {-1, 1}, {-1, 0}, {-1, - 1},
    };
    if(BanData[ masuY ][ masuX ] == BAN){
        BanData[ masuY ][ masuX ] = SIRO;
        for(int i = 0; i < 8; i++){
        StoneCount += PutLine(masuX + Cheak[i].X, masuY + Cheak[i].Y, Cheak[i].X, Cheak[i].Y, SIRO, 0);
        }
        if(StoneCount == 0){BanData[ masuY ][ masuX ] = BAN;}
    }
    return StoneCount;
}
出来ました。テストコードというのがいまいち分かりません・・・。
こういうことですか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#117

投稿記事 by softya(ソフト屋) » 12年前

起動するだけで、動作確認が出来るソースコードと言う意味でテストコードと呼んでます。
asdさんもテスト用の盤面データを用意すると書いていますよね。

凝ったものなら、指定したパターンで置いてひっくり返した結果と事前に手作業で用意した結果データを付きあわせて異常がないかまでテストできると完璧です。

インデントに関しては、何故か全角空白文字になっていますがわざわざ変換していませんか?
ここの投稿は、そのまま受け付けてくれるはずです。

あとインデントのミスですが。

コード:

        for(int i = 0; i < 8; i++){
        StoneCount += PutLine(masuX + Cheak[i].X, masuY + Cheak[i].Y, Cheak[i].X, Cheak[i].Y, SIRO, 0); ← ここです。
        }
{}では1つ下げるが行われないといけません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#118

投稿記事 by sadora3 » 12年前

なんどもすみません。まだテストコードというものが理解できません。具体的な例を見せてくれませんか?

>asdさんが書いてくれたコードでメインを含めて動作確認するためのコード
メインとはメインループのことですよね?

Rom
記事: 25
登録日時: 15年前
住所: 日本

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#119

投稿記事 by Rom » 12年前

テストコードってのは要するに「それをコピーペーストしてコンパイルすればすぐさま実行できるもの」ということだと思うよ
例えば上でsadora3さんが書いた

コード:

void AllWayPut(){
    int StoneCount = 0;
    struct AllWay{
        int X;
        int Y;
    }Cheak[] = {
        { 0 , -1 }, { 1 , -1 }, { 1 , 0 }, { 1 , 1 },
        { 0 , 1 }, {-1 , 1 }, { -1 , 0 }, { -1 , - 1 },
    };
    if( BanData[ masuY ][ masuX ] == BAN ){
        BanData[ masuY ][ masuX ] = SIRO;
        for( int i = 0 ; i < 8 ; i++ ){
        StoneCount += PutLine( masuX + Cheak[i].X , masuY + Cheak[i].Y , Cheak[i].X , Cheak[i].Y , SIRO , 0 );
        }
    }
}
っていうのが本当に正しいか確かめようと思っても↑だけでは動作しないからいちいち他の部分まで作らないとダメだよねってことだと思うよ

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#120

投稿記事 by sadora3 » 12年前

なるほど。ありがとうございます。

コード:

int AllWayPut(){
	int StoneCount = 0;
	struct AllWay{
		int X;
		int Y;
	}Cheak[] = {
		{0, -1}, {1, -1}, {1, 0}, {1, 1 },
		{0, 1}, {-1, 1}, {-1, 0}, {-1, - 1},
	};
	if(BanData[ masuY ][ masuX ] == BAN){
		BanData[ masuY ][ masuX ] = SIRO;
		for(int i = 0; i < 8; i++){
			StoneCount += PutLine(masuX + Cheak[i].X, masuY + Cheak[i].Y, Cheak[i].X, Cheak[i].Y, SIRO, 0);
		}
		if(StoneCount == 0){BanData[ masuY ][ masuX ] = BAN;}
	}
	return StoneCount;
}
これが置けないときは取り消す処理と、戻り値にひっくり返した総数をAllWayPutの戻り値で返すようにしたプログラムです。

コード:

#include "DxLib.h"

#define BAN_SIZE 64
#define WALL -1
#define BAN 0
#define SIRO 1
#define KURO 2
#define BAN_YOKO 10
#define BAN_TATE 10

void DrawInit();
void DrawBoard();
int MouseRelate();
int PutLine(int, int, int, int, int, int);
int AllWayPut();

static int GH_HAIKEI;
static int GH_SIRO;
static int GH_KURO;
static int GH_BAN;
static int masuX;
static int masuY;

static int BanData[ BAN_TATE ][ BAN_YOKO ] =
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
	{-1,0,1,1,1,1,1,1,1,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,1,1,1,1,1,1,0,-1},
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};

int ProcessLoop(){
	if(ProcessMessage() != 0){	return -1;	}
	if(ClearDrawScreen() != 0){	return -1;	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
	ChangeWindowMode(TRUE);
	SetGraphMode(640, 640, 32); 
	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_BACK) != 0){	return -1;	}
	DrawInit();
	while(ProcessLoop() == 0){
		DrawBoard();
		MouseRelate();
		ScreenFlip();
	}
	DxLib_End();
	return  0;
}


void DrawInit(){
    GH_HAIKEI = LoadGraph( "画像/背景.png" );
    GH_SIRO = LoadGraph( "画像/白.png" );
    GH_KURO = LoadGraph( "画像/黒.png" );
    GH_BAN = LoadGraph( "画像/将棋板.png" );
}

void DrawBoard(){
	int x,y;
	DrawGraph(0, 0, GH_HAIKEI, FALSE);
	for(x = 1; x < BAN_YOKO; x++){
		for(y = 1; y < BAN_TATE; y++){
			switch(BanData[ y ][ x ]){
				case BAN:
					DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_BAN, TRUE);
					break;
				case SIRO:
					DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_BAN, TRUE);
					DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_SIRO, TRUE);
					break;
				case KURO:
					DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_BAN, TRUE);
					DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_KURO, TRUE);
				break;
			}
		}
	}
}

int MouseRelate(){
	int mouseX = 0;
	int mouseY = 0;
	GetMousePoint(&mouseX, &mouseY);
	masuX = mouseX / BAN_SIZE;
	masuY = mouseY / BAN_SIZE;
	if((GetMouseInput() & MOUSE_INPUT_LEFT) != 0){	AllWayPut();	}
	return 0;
}

int PutLine(int x, int y, int Way_x, int Way_y, int Color, int count){
	if(BanData[ y ][ x ] == BAN){	return count;	}
	else if(BanData[ y ][ x ] == Color){	return count;	}
	else if(BanData[ y ][ x ] == WALL){		return count;	}
	else if(BanData[ y ][ x ] != Color){BanData[ y ][ x ] = Color;}
	return PutLine(x + Way_x, y + Way_y, Way_x, Way_y, Color, count + 1);
}

int AllWayPut(){
	int StoneCount = 0;
	struct AllWay{
		int X;
		int Y;
	}Cheak[] = {
		{0, -1}, {1, -1}, {1, 0}, {1, 1 },
		{0, 1}, {-1, 1}, {-1, 0}, {-1, - 1},
	};
	if(BanData[ masuY ][ masuX ] == BAN){
		BanData[ masuY ][ masuX ] = SIRO;
		for(int i = 0; i < 8; i++){
			StoneCount += PutLine(masuX + Cheak[i].X, masuY + Cheak[i].Y, Cheak[i].X, Cheak[i].Y, SIRO, 0);
		}
		if(StoneCount == 0){BanData[ masuY ][ masuX ] = BAN;}
	}
	return StoneCount;
}
テストコードとはこういうことですね。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#121

投稿記事 by softya(ソフト屋) » 12年前

お疲れ様でした。基本的な所は出来ていると思います。
と思ったらバグっています。ほんとにテストされましたか?
私が悪いところもあるんですが、テストしていなとしたら一番いけません。テストしていて問題が有り報告していないもの良くないです。
テスト結果を教えて欲しいと書いたはずです。

【補足】怒っているんじゃないですよ、テストが大事だということを分かって貰いたいだけです。
今回のように私もミスしますし、誰だってミスはあります。
ただ、プログラミングは仕様分析・設計・コーディング・テスト・デバッグの何れかが抜けても完成しません。
どれも大事なんです。そこを理解して欲しいのです。

PutLine()でひっくり返しの終端に相手石がなかったら、ひっくり返しの取り消しを入れ忘れてましたね。当方のオオボケでした。
途中で、そんな話もあったのに見逃してしまいました。
と言うことで改善案を検討してみてください。

それと画像がなくても実行できるようにお願いします。

コード:

void DrawBoard(){
	int x,y;
//	  DrawGraph(0, 0, GH_HAIKEI, FALSE);
	for(x = 1; x < BAN_YOKO; x++){
		for(y = 1; y < BAN_TATE; y++){
			DrawBox(x * BAN_SIZE, y * BAN_SIZE, x * BAN_SIZE+BAN_SIZE-1, y * BAN_SIZE+BAN_SIZE-1, GetColor(128,128,0), TRUE );
			switch(BanData[ y ][ x ]){
				case BAN:
			//		  DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_BAN, TRUE);
					break;
				case SIRO:
			//		  DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_BAN, TRUE);
			//		  DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_SIRO, TRUE);
					DrawCircle(x*BAN_SIZE+BAN_SIZE/2, y*BAN_SIZE+BAN_SIZE/2, BAN_SIZE/2, GetColor(255,255,255), TRUE );
					break;
				case KURO:
			//		  DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_BAN, TRUE);
			//		  DrawGraph(x * BAN_SIZE, y * BAN_SIZE, GH_KURO, TRUE);
					DrawCircle(x*BAN_SIZE+BAN_SIZE/2, y*BAN_SIZE+BAN_SIZE/2, BAN_SIZE/2, GetColor(0,0,0), TRUE );
				break;
			}
		}
	}
}
【テストコードとは】
テストコードは出来れば、自動でテストが行われるのが望ましいんです。
なので、自動で置いて結果を表示して、作っておいた結果と等しいかチェックを繰り返してくれるとコードの正当性が評価しやすくなります。
あとテキストファイルに結果をログとして残す必要もありますし、DXライブラリでの表示も不要だったります。
今回は、そこまでしなくて良いですが、AI搭載など機能アップを測るのならぜひ作って欲しい所です。
付記。
※ MouseRelateと言う名前が意味がわかりません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#122

投稿記事 by sadora3 » 12年前

コード:

#include "DxLib.h"

#define WALL -1
#define BAN 0
#define SIRO 1
#define KURO 2

void DrawBoard();
void DrawCount();
int CeackLine(int, int, int, int, int, int);
int PutLine(int, int, int, int, int, int);
int AllWayPut();

static int Count;

static int BanData[ 10 ][ 10 ] =
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
	{-1,0,1,1,1,1,1,1,1,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,1,1,1,1,1,1,0,-1},
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};

int ProcessLoop(){
	if(ProcessMessage() != 0){  return -1;  }
	if(ClearDrawScreen() != 0){ return -1;  }
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
	ChangeWindowMode(TRUE);
	SetGraphMode(640, 640, 32); 
	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_BACK) != 0){   return -1;  }
	while(ProcessLoop() == 0){
		DrawBoard();
		DrawCount();
		ScreenFlip();
	}
	DxLib_End();
	return  0;
}


void DrawBoard(){
	int x,y;
	DrawBox( 0, 0, 640, 640, GetColor( 255, 200, 140 ), TRUE ) ;
	for(x = 1; x < 9; x++){
		for(y = 1; y < 9; y++){
			switch(BanData[ y ][ x ]){
				case BAN:
					DrawBox( x * 64, y * 64, x * 64 + 64, y * 64 + 64, GetColor( 0, 0, 0 ), FALSE );
					break;
				case SIRO:
					DrawBox( x * 64, y * 64, x * 64 + 64, y * 64 + 64, GetColor( 0, 0, 0 ), FALSE );
					DrawCircle( x * 64 + 32, y * 64 + 32, 25, GetColor( 255, 255, 255 ), TRUE );
					break;
				case KURO:
					DrawBox( x * 64, y * 64, x * 64 + 64, y * 64 + 64, GetColor( 0, 0, 0 ), FALSE );
					DrawCircle( x * 64 + 32, y * 64 + 32, 25, GetColor( 0, 0, 0 ), TRUE );
				break;
			}
		}
	}
}

void DrawCount(){
	Count += AllWayPut();
	DrawFormatString( 0, 0, 0, "%d", Count ) ;
}

int CheakLine(int x, int y, int Way_x, int Way_y, int Color, int EnemyColor){
	if(BanData[ y ][ x ] == EnemyColor){
		if(BanData[ y + Way_y ][ x + Way_x ] == Color){	return 1;	}
		if(BanData[ y + Way_y ][ x + Way_x ] == EnemyColor){
			CheakLine(x + Way_x, y + Way_y, Way_x, Way_y, Color, EnemyColor);
		}
		else{	return 0;	}
	}
	else{	return 0;	}
	return CheakLine(x + Way_x, y + Way_y, Way_x, Way_y, Color, EnemyColor);
}

int PutLine(int x, int y, int Way_x, int Way_y, int Color, int count){
	if(BanData[ y ][ x ] == BAN){   return count;   }
	else if(BanData[ y ][ x ] == Color){	return count;   }
	else if(BanData[ y ][ x ] == WALL){	 return count;   }
	else if(BanData[ y ][ x ] != Color){BanData[ y ][ x ] = Color;}
	return PutLine(x + Way_x, y + Way_y, Way_x, Way_y, Color, count + 1);
}

int AllWayPut(){
	int StoneCount = 0;
	struct AllWay{
		int X;
		int Y;
	}Cheak[] = {
		{0, -1}, {1, -1}, {1, 0}, {1, 1 },
		{0, 1}, {-1, 1}, {-1, 0}, {-1, - 1},
	};
	if(BanData[ 1 ][ 1 ] == BAN){
		BanData[ 1 ][ 1 ] = SIRO;
		for(int i = 0; i < 8; i++){
			if(CheakLine(8 + Cheak[i].X, 8 + Cheak[i].Y, Cheak[i].X, Cheak[i].Y, SIRO, KURO) == 1){
			StoneCount += PutLine(8 + Cheak[i].X, 8 + Cheak[i].Y, Cheak[i].X, Cheak[i].Y, SIRO, 0);
			}
		}
		if(StoneCount == 0){BanData[ 1 ][ 1 ] = BAN;}
	}
	return StoneCount;
}
バグが分かりません・・・。テストはしてました。
自動でテストが行われるというのはこういうことでしょうか?
これで石をひっくり返している途中に相手の石がなければひっくり返らなくなりました。
バグとはマウス関係のものでしたか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#123

投稿記事 by softya(ソフト屋) » 12年前

前回は石を挟んでいないのにひっくり返す場合がありました。これはバグですね。
説明がありませんが、CheakLine()でガードしたという事でしょうか?
それでOKだと思います。
※ PutLine()だけで済ます方法もありますが、今回はこのままいきましょう。

で、テストに関しては何処をテストしたのか分かりづらいのでなんとかして欲しい所ですがsadora3さんには高難度になりそうなので今回は止めておきます。
テストを自動するということのイメージがどうにも伝わっていない様です。
なので、このプログラムをマウス操作で普通に置けるようにしてみてください。あと石を置けなかったらMessageBox()で置けませんとメッセージを出すことにしましょう。
それでバグがなければ終了ということでよろしいですか?

コード:

MessageBox(
	GetMainWindowHandle(),
	"ここには石は置けません。",
	"警告",
	MB_OK);
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#124

投稿記事 by sadora3 » 12年前

コード:

#include "DxLib.h"

#define WALL -1
#define BAN 0
#define SIRO 1
#define KURO 2

void DrawBoard();
void MouseOperation();
int CeackLine(int, int, int, int, int, int);
int PutLine(int, int, int, int, int, int);
int AllWayPut();

static int Count;
static int masuX;
static int masuY;

static int BanData[ 10 ][ 10 ] =
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
	{-1,0,1,1,1,1,1,1,1,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,0,0,0,0,0,0,2,-1},
	{-1,2,1,1,1,1,1,1,0,-1},
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
};

int ProcessLoop(){
	if(ProcessMessage() != 0){  return -1;  }
	if(ClearDrawScreen() != 0){ return -1;  }
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
	ChangeWindowMode(TRUE);
	SetGraphMode(640, 640, 32); 
	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_BACK) != 0){   return -1;  }
	while(ProcessLoop() == 0){
		DrawBoard();
		MouseOperation();
		ScreenFlip();
	}
	DxLib_End();
	return  0;
}


void DrawBoard(){
	int x,y;
	DrawBox( 0, 0, 640, 640, GetColor( 255, 200, 140 ), TRUE ) ;
	for(x = 1; x < 9; x++){
		for(y = 1; y < 9; y++){
			switch(BanData[ y ][ x ]){
				case BAN:
					DrawBox( x * 64, y * 64, x * 64 + 64, y * 64 + 64, GetColor( 0, 0, 0 ), FALSE );
					break;
				case SIRO:
					DrawBox( x * 64, y * 64, x * 64 + 64, y * 64 + 64, GetColor( 0, 0, 0 ), FALSE );
					DrawCircle( x * 64 + 32, y * 64 + 32, 25, GetColor( 255, 255, 255 ), TRUE );
					break;
				case KURO:
					DrawBox( x * 64, y * 64, x * 64 + 64, y * 64 + 64, GetColor( 0, 0, 0 ), FALSE );
					DrawCircle( x * 64 + 32, y * 64 + 32, 25, GetColor( 0, 0, 0 ), TRUE );
				break;
			}
		}
	}
}


int CheakLine(int x, int y, int Way_x, int Way_y, int Color, int EnemyColor){
	if(BanData[ y ][ x ] == EnemyColor){
		if(BanData[ y + Way_y ][ x + Way_x ] == Color){	return 1;	}
		if(BanData[ y + Way_y ][ x + Way_x ] == EnemyColor){
			CheakLine(x + Way_x, y + Way_y, Way_x, Way_y, Color, EnemyColor);
		}
		else{	return 0;	}
	}
	else{	return 0;	}
	return CheakLine(x + Way_x, y + Way_y, Way_x, Way_y, Color, EnemyColor);
}

int PutLine(int x, int y, int Way_x, int Way_y, int Color, int count){
	if(BanData[ y ][ x ] == BAN){   return count;   }
	else if(BanData[ y ][ x ] == Color){	return count;   }
	else if(BanData[ y ][ x ] == WALL){	 return count;   }
	else if(BanData[ y ][ x ] != Color){BanData[ y ][ x ] = Color;}
	return PutLine(x + Way_x, y + Way_y, Way_x, Way_y, Color, count + 1);
}

int AllWayPut(){
	int StoneCount = 0;
	struct AllWay{
		int X;
		int Y;
	}Cheak[] = {
		{0, -1}, {1, -1}, {1, 0}, {1, 1 },
		{0, 1}, {-1, 1}, {-1, 0}, {-1, - 1},
	};
	if(BanData[ masuY ][ masuX ] == BAN){
		BanData[ masuY ][ masuX ] = SIRO;
		for(int i = 0; i < 8; i++){
			if(CheakLine(masuX + Cheak[i].X, masuY + Cheak[i].Y, Cheak[i].X, Cheak[i].Y, SIRO, KURO) == 1){
			StoneCount += PutLine(masuX + Cheak[i].X, masuY + Cheak[i].Y, Cheak[i].X, Cheak[i].Y, SIRO, 0);
			}
		}
		if(StoneCount == 0){
			BanData[ masuY ][ masuX ] = BAN;
			MessageBox(GetMainWindowHandle(), "ここには石は置けません", "警告", MB_OK);
		}
	}
	return StoneCount;
}

void MouseOperation(){
	int mouseX = 0;
	int mouseY = 0;
	GetMousePoint(&mouseX, &mouseY);
	masuX = mouseX / 64;
	masuY = mouseY / 64;
	if((GetMouseInput() & MOUSE_INPUT_LEFT) != 0){  Count += AllWayPut();	}
	DrawFormatString( 0, 0, 0, "%d", Count );
}
出来ました。マウス操作で置けるようにして、置けなければメッセージを出すようにしました。
ところで、なぜ置けませんとメッセージを出すようにしたのでしょうか?
また、「それでバグがなければ終了ということでよろしいですか?」と、ありますが、終了とはなんでしょうか?
何を終了するのですか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#125

投稿記事 by softya(ソフト屋) » 12年前

>出来ました。マウス操作で置けるようにして、置けなければメッセージを出すようにしました。
>ところで、なぜ置けませんとメッセージを出すようにしたのでしょうか?

はい。テストOKだと思います。
なぜか?ですがメッセージを出さないと、なぜ置かれなかったのか明示されない事になります。
つまりテスト出来ないのです。
まぁ、ゲームとしても問題ありますよね。

>また、「それでバグがなければ終了ということでよろしいですか?」と、ありますが、終了とはなんでしょうか?
>何を終了するのですか?

このトピックのタイトルからして質問としては、これで終わりだと思っていたのですが、どうなんでしょうか?
今後、sadora3さんが、このオセロにどういう機能を追加するにしてもこのトピックとしては長くなったので一旦終了したほうが良いかなと思った次第です。
まだ、聞きたいことがあれば整理してもらって別トピックを立ちあげてもらった方が良いでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sadora3
記事: 175
登録日時: 13年前

Re: オセロで、石を反転する範囲の捜索の仕方がわかりません

#126

投稿記事 by sadora3 » 12年前

そうですね。分かりました。
長い間本当にありがとうございました。
また、なにかあればよろしくお願いします。

閉鎖

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