オセロ

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

オセロ

#1

投稿記事 by ざこ » 16年前

現在VisualC++でオセロを作成しております。お手数ですがこちらをごらんください。

http://www.geocities.co.jp/SiliconValle ... ero-5.html
こちらを参考にしてます。
BOOL COseroView::CanDropDown( int x, int y, int vect_x, int vect_y )
{
    int put_stone;

    if( m_FlagForWhite )put_stone = WHITE_STONE;//m_FlagForWhiteはbool変数
    else put_stone = BLACK_STONE;

    x += vect_x;
    y += vect_y;
    if( x < 0 || x >= MASU_NUM || y < 0 || y >= MASU_NUM )return( FALSE );
    if( m_Board[x][y] == put_stone )return( FALSE );
    if( m_Board[x][y] == BLANK )return( FALSE );

    x += vect_x;
    y += vect_y;
    while( x >= 0 && x < MASU_NUM  &&  y >= 0 && y < MASU_NUM  )//MASU_NUMはマス数
    {
        if( m_Board[x][y] == BLANK )return( FALSE );
        if( m_Board[x][y] == put_stone )return( TRUE );
        x += vect_x;
        y += vect_y;
    }
    return( FALSE );
}
これは八方向にひっくり返せる石があるか調べるプログラムなんですが
①1進める
8方向に1だけ進み
空白があればFALSE 
同じ色の石があればFALSE

②さらに1進める

同方向に1だけ進み
空白があればFALSE(終了)
同じ色の石があればTRUE(続ける)

③これをマス目超えるまで繰り返す
④FALSEを返す

それでこの結果をこちらで使うんですけど
BOOL COseroView::CanDropDown( int x, int y )
{
    if( x >= MASU_NUM || y >= MASU_NUM )return( FALSE );
    if( m_Board[x][y] != BLANK )return( FALSE );

    if( CanDropDown( x, y,  1,  0 ) )return( TRUE );    //右
    if( CanDropDown( x, y,  0,  1 ) )return( TRUE );    //下
    if( CanDropDown( x, y, -1,  0 ) )return( TRUE );    //左
    if( CanDropDown( x, y,  0, -1 ) )return( TRUE );    //上
    if( CanDropDown( x, y,  1,  1 ) )return( TRUE );    //右下
    if( CanDropDown( x, y, -1, -1 ) )return( TRUE );    //左上
    if( CanDropDown( x, y,  1, -1 ) )return( TRUE );    //右上
    if( CanDropDown( x, y, -1,  1 ) )return( TRUE );    //左下

       return( FALSE );
}
として使ってます。オセロのルールですね。

画面外と石が置いてある場所には置けない
ひっくり返せないとこには置けないの2つ組み込んでます。

内容は書いてあるんでわかるのですが
プログラムがよくわかりません。
(a)上のプログラムではFALSEを返してますよね。でも②のときに空白があれば 例えば→方向(打ち手黒)とすると
○●[ ] 現在この状態ですよね。ここに置く事ができるからそこで終了ってなってるんだとは思いますが
置けない場合のFALSEとゴチャゴチャになってしまって結局何を返してるのかわからなくなってます・・

(b)下のプログラムがどうなってるのかがさっぱりです。TRUEとFALSEがどうなってるのかなど

(a),(b)について教えてください。

バグ

Re:オセロ

#2

投稿記事 by バグ » 16年前

1:これから検査しようとしているX座標、Y座標のどちらかがオセロ盤の外に指定された場合はFALSEを返す
2:これから検査しようとしている箇所が空白(黒でも白でもない)だったらFALSEを返す(検査する意味がない)
3:8方向を調べて、1方向でもコマを置く事が可能(上のCanDropDown関数の戻り値がTRUE)ならば、TRUEを返す
4:8方向を調べてみたが、置ける箇所が無いので、FALSEを返す

以上です。

ようするに、TRUEが返る場合は、その座標にコマを置くことができ、FALSEの場合は置けないという事ですね。

バグ

Re:オセロ

#3

投稿記事 by バグ » 16年前

(a)についてですが、whileループの中で、FALSEではなくTRUEを返すパターンは存在しています。

ざこ

Re:オセロ

#4

投稿記事 by ざこ » 16年前

修正多くて申し訳ないです。スレ内容を若干修正してあります。

その部分だけとりあげますと
①→②に進むには→方向で打ち手黒の場合
○● 現在この状態ですよね

もう1個→に進み
○●( ) 現在( )の位置にいます。
この場合置けますよね。

>ようするに、TRUEが返る場合は、その座標にコマを置くことができ、FALSEの場合は置けないという事ですね。

ならばここはTRUEになるのでは?と思ってしまいます。

おそらく戻り値のFALSE,TRUEがよくわかっていないんだとおもいますが
上のプログラムの戻り値FALSEをTRUEにしても同じ結果でした。
下のプログラムの戻り値をFALSEをTRUEにしたら正常にできてませんでした。これはわかります。
上は何故でしょうか?

それが>>(a)についてですが、whileループの中で、FALSEではなくTRUEを返すパターンは存在しています
ということでしょうか?

バグ

Re:オセロ

#5

投稿記事 by バグ » 16年前

ごめんなさい、前の書き込みは間違いです。ちょっと勘違いしていました。
ソースにコメント入れてみたので、これで流れを追いかけてみてください。
// 置ける場所かどうかの判定を行う関数
// x = 判定を行う場所のX座標
// y = 判定を行う場所のY座標
BOOL COseroView::CanDropDown( int x, int y )
{
	// 引数で指定されたX座標、Y座標のどちらかがMASU_NUM(おそらく8じゃないかと)以上ならば、オセロ盤の外が指定されたと判断し、FALSEを返す
	if( x >= MASU_NUM || y >= MASU_NUM )return( FALSE );

	// 指定された場所が空白ではない(既に白か黒のコマが置かれている状態)場合、検査しても意味がないので、FALSEを返す
	if( m_Board[x][y] != BLANK )return( FALSE );

	// 8方向のうち、1箇所でも置ける方向があった場合はTRUEを返す
	if( CanDropDown( x, y,  1,  0 ) )return( TRUE );    //右
	if( CanDropDown( x, y,  0,  1 ) )return( TRUE );    //下
	if( CanDropDown( x, y, -1,  0 ) )return( TRUE );    //左
	if( CanDropDown( x, y,  0, -1 ) )return( TRUE );    //上
	if( CanDropDown( x, y,  1,  1 ) )return( TRUE );    //右下
	if( CanDropDown( x, y, -1, -1 ) )return( TRUE );    //左上
	if( CanDropDown( x, y,  1, -1 ) )return( TRUE );    //右上
	if( CanDropDown( x, y, -1,  1 ) )return( TRUE );    //左下

	// 置ける方向が見つからなかったので、この場所には置けないと判断し、FALSEを返す
	return( FALSE );
}

// 指定された1方向に関して、置けるかどうかを判断する関数
// x = 判定を行う場所のX座標
// y = 判定を行う場所のY座標
// vect_x = 次の判定を行う場所へ移動する際の横方向の移動量
// vect_y = 次の判定を行う場所へ移動する際の縦方向の移動量
BOOL COseroView::CanDropDown( int x, int y, int vect_x, int vect_y )
{
	// 今、置こうとしているコマの色情報を格納する変数
	int put_stone;

	// m_FlagForWhiteがTRUEの場合はput_stoneを白、そうでない場合は黒とする
	if( m_FlagForWhite )put_stone = WHITE_STONE;//m_FlagForWhiteはbool変数
	else put_stone = BLACK_STONE;

	// 1マス進める
	x += vect_x;
	y += vect_y;

	// 1マス進めた結果、オセロ盤の外へ移動してしまった場合は、FALSEを返す
	if( x < 0 || x >= MASU_NUM || y < 0 || y >= MASU_NUM )return( FALSE );

	// 1マス進めた場所がこれから置こうとするコマと同じ色だった場合は、置けない場所だと判断して、FALSEを返す
	if( m_Board[x][y] == put_stone )return( FALSE );

	// 1マス進めた場所が空白の場合は、置けない場所だと判断して、FASLSEを返す
	if( m_Board[x][y] == BLANK )return( FALSE );

	// 更にもう1マス進める
	x += vect_x;
	y += vect_y;

	// 検査場所がオセロ盤の範囲内にある限りループを続ける
	while( x >= 0 && x < MASU_NUM  &&  y >= 0 && y < MASU_NUM  )//MASU_NUMはマス数
	{
		// 検査場所が空白の場合はFALSEを返す
		if( m_Board[x][y] == BLANK )return( FALSE );

		// 検査場所がこれから置こうとするコマと同じ色ならば、TRUEを返す
		if( m_Board[x][y] == put_stone )return( TRUE );

		// 空白でも同じ色でもないという事は、違う色が存在しているので、1マス進める
		x += vect_x;
		y += vect_y;
	}

	// 置ける場所が見つからなかったので、FALSEを返す
	return( FALSE );
}

ざこ

Re:オセロ

#6

投稿記事 by ざこ » 16年前

ありがとうございました。

ざこ

Re:オセロ

#7

投稿記事 by ざこ » 16年前

もう1つだけ教えて下さい。
void COseroView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたは……

    int x, y;

    x = point.x / MASU_SIZE;
    y = point.y / MASU_SIZE;

    if( CanDropDown( x, y ) ) DropDownStone( x, y );

    CDC* pDC = GetDC();                //画面を再描画
    DrawBoard( pDC );
    ReleaseDC( pDC );

    CView::OnLButtonDown(nFlags, point);
}
なんですがpoint.xでマウスがクリックしたところのx座標ってのはわかるんですが
x=point.x/MASU_SIZEってのがよくわかりません。
例えば■があった場合この白い部分を左クリックすれば実行される となってます。(64マスある一番左上端の1マスをとりだしている)

このときのxは0~7までの8個ですよね。すると上記の例ではx=0です
わからないのはこの白い■のどこをクリックしてもx=0と見なされるのがわからないのです。
point.xは浮動少数ならそれこそ無限にあります。整数でもたくさんあるはずです。


つまり一番上の行のマスを取り出してみて
①②③④⑤⑥⑦⑧
■■■■■■■■ この正方形が1辺10だとすると

1~10までの座標とy=0の座標の範囲をクリックすれば①のプログラムが(石配置)が行われます。
この範囲指定を行っているプログラムが見当たらないんですが教えてもらえませんか?


非常にわかりずらい質問になってしまいましたが要は
どっからどこまでの範囲をクリックすればそのマス目のプログラムが実行されるのか
その設定はどこでやっているのか などが質問です。

バグ

Re:オセロ

#8

投稿記事 by バグ » 16年前

マウスがクリックされた時点のマウスカーソルの座標をオセロ盤の座標に変換しているんです。

例えば、仮にウインドウのサイズが横320、縦320ピクセル、オセロ盤の1マスを横40、縦40ピクセルだとします。

そして、マウスがクリックされたのがX=100、Y=100の位置だとします。

この場合、マウスがクリックされたのはオセロ盤のどの場所(左から何マス目、上から何マス目か?)になるかを計算するにはどうすれば良いでしょうか?

そのプログラムでは、これと同じ作業を行なっています。

ざこ

Re:オセロ

#9

投稿記事 by ざこ » 16年前

100÷40だから2,5 上からも2,5マス目かな?この場合3と3になってるので浮動少数は
切り上げということでしょうか。

バグ

Re:オセロ

#10

投稿記事 by バグ » 16年前

そういうことです(^-^)
ただし、C++の配列インデックスは0から始まりますので、プログラム上で使用する際は、小数点以下を切り捨てた値を使用してください。

ざこ

Re:オセロ

#11

投稿記事 by ざこ » 16年前

成る程です。しかし始めからそのようになってるのでしょうか?原因はわかりましたが仕組みの方があまり。。
次に五目並べを作ってみようと思ってます。五目並べの場合頂点クリックですから
切り上げされるとできないですよね。

バグ

Re:オセロ

#12

投稿記事 by バグ » 16年前

頂点をクリックした場合のみを有効にしたいのならば、1マス40ピクセルのグリッドが描かれていたとすると、X・Y座標ともに、40で割って余りが0の場所のみ有効となりますね。

toyo

Re:オセロ

#13

投稿記事 by toyo » 16年前

頂点クリックだと判定がシビアすぎて使いにくそうですね
判定は同じでいいと思います
ますの画像を□から+に変えるだけでいいでしょう

閉鎖

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