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

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

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

#101

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

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

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

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

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

ただの屍のようだ

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

#102

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

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

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

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

#103

投稿記事 by sadora3 » 11年前

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

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

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

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

#104

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

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

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

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

#105

投稿記事 by sadora3 » 11年前

コード:

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
登録日時: 13年前
住所: 東海地方
連絡を取る:

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

#106

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

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

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

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

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

#107

投稿記事 by asd » 11年前

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

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

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

#108

投稿記事 by sadora3 » 11年前

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

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

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

#109

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

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

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

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

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

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

#110

投稿記事 by sadora3 » 11年前

コード:

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
登録日時: 13年前
住所: 東海地方
連絡を取る:

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

#111

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

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

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

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

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

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

#112

投稿記事 by sadora3 » 11年前

コード:

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
登録日時: 13年前
住所: 東海地方
連絡を取る:

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

#113

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

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

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

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

#114

投稿記事 by sadora3 » 11年前

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

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

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

#115

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

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

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

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

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

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

#116

投稿記事 by sadora3 » 11年前

コード:

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
登録日時: 13年前
住所: 東海地方
連絡を取る:

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

#117

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

起動するだけで、動作確認が出来るソースコードと言う意味でテストコードと呼んでます。
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
登録日時: 11年前

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

#118

投稿記事 by sadora3 » 11年前

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

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

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

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

#119

投稿記事 by Rom » 11年前

テストコードってのは要するに「それをコピーペーストしてコンパイルすればすぐさま実行できるもの」ということだと思うよ
例えば上で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
登録日時: 11年前

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

#120

投稿記事 by sadora3 » 11年前

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

コード:

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
登録日時: 13年前
住所: 東海地方
連絡を取る:

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

#121

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

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

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

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
登録日時: 11年前

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

#122

投稿記事 by sadora3 » 11年前

コード:

#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
登録日時: 13年前
住所: 東海地方
連絡を取る:

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

#123

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

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

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

コード:

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

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

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

#124

投稿記事 by sadora3 » 11年前

コード:

#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
登録日時: 13年前
住所: 東海地方
連絡を取る:

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

#125

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

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

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

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

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

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

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

#126

投稿記事 by sadora3 » 11年前

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

閉鎖

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