前へ 一覧 次へ
第四課 置けるか否か


ついに来てしまいました……オセロでかなり面倒臭い部分。

置けるかどうかの条件ってなんでしょう?
とりあえず絶対条件としては「そのマスが空である」というものがありますね。
今から置こうって場所にコマが既にあっては置くことができませんから。
あとは「ある方向に相手側のコマが1個以上続いた後に自分のコマがある」ですね。
この2点を抑えれば置けるかどうかの確認は可能です。

さて、1点目は簡単に確認することができますが、2点目はどうすればいいでしょうか。
とりあえず、上を確認する関数、右上を、右を、……、左上を確認すると8種類作りますか?

……勿論、こんな無駄なことはしません。
下の図を見てください。

今、board[y][x]にコマを置くことを考えるとします。
この場合一つ上のマスの座標は[y-1][x]と表せます。
特定の方向を確認したい場合は、
現在の座標に図の対応する方向の数値を加算することで座標を得ることができます。

そこで、一次元配列vec_x[8],vec_y[8]をグローバル変数で用意して、
数値の増分を上方向から時計回りに代入していきます。
vec_y[]={-1,-1,0,1,1,-1,0,-1};
vec_x[]={0,1,1,1,0,-1,-1,-1};
これで、関数の一本化がぐっとらくになりました。
例えば、右を確認したければvec_y[2]とvec_x[2]の値、
下ならvec_y[4],vec_x[4]といった風に添字を変えるだけで向きを変えることができます。

あ、大事なことを忘れていました。
現在どっちの手番かということも重要な情報です。
というか、これがないとどうにもならないですね。
変数turnを宣言して、これが0なら黒、1なら白の手番ということにします。

では、いよいよ実際にコードを書いていきます。


vec_y[] = {-1,-1,0,1,1,1,0,-1};
vec_x[] = {0,1,1,1,0,-1,-1,-1};

//vecで指定された向きについてひっくり返るコマがあるか確認する
int checkFlip(int y,int x,int turn,int vec)
{
	int flag = 0;
	while(1){
		y += vec_y[vec];
		x += vec_x[vec];
		
		//盤面の外に出ていたら終了
		if( x < 0 || y < 0 || x > BOARDSIZE-1 || y > BOARDSIZE-1) return 0;
		
		//空きマスだったら終了
		if(board[y][x] == NONE) return 0;
		
		//相手のコマがあったらフラグを立てる
		if(board[y][x] == (turn ? BLACK : WHITE)){
			flag = 1;
			continue;
		}
		
		//もしフラグがたっていればループ脱出。いなければ終了
		if(flag == 1) break;
		return 0;
	}
	return 1;
}


さて、何をやっているかわかるでしょうか?
ループの最初で、まず指定の方向に1マス進みます。
その時点で盤面の外に出てしまった場合、それ以降の探索を止めて0を返します。
空きマスだった場合も同様です。
この2パターンの場合、どう転んでもその方向にあるコマをひっくり返すことができません。

盤面内である、そして空きマスでもない。次に確認しているのは相手のコマかどうかです。
赤い部分に注目してください。条件演算子が使われています。
簡易if文みたいなものです。turnが0ならWHITEが、turnが1ならBLACKが使われます。
先ほど0なら黒の、1なら白の手番と決めましたから、きちんと相手の色がでてますね。
で、相手のコマだった場合は、flagを立ててループの最初に戻ります。

そして上記のどれでもなかった場合は、そこには自分のコマがあるということになります。
このとき、flagが1ならば置こうとしている場所から
今確認している場所の手前まで相手のコマが1個以上続いていることなので、
ループを抜けて1を返します。
flagが0なら自分のコマが連続していただけということで、0を返します。

これで、確認作業は大体終了です。
checkFlip関数が1を返してきた場合、
その方向に返せるコマがある=置くことができる、ということになります。

もう一つ関数を作れば、置けるかどうかの確認は終了です。

//その場所に置くことができるかを確認する関数
int check(int y,int x,int turn)
{
	int vec;
	
	//どれか一方向でもひっくり返るか確認
	for(vec = 0 ; vec < 8 ; ++vec){
		if(checkFlip(y,x,turn,vec) == 1) return 1;
	}
	
	return 0;
}


これは指定された場所について
上から時計回りの順番でひっくり返せるか確認して、
返せることが分かった時点で1を返す。
返せなければ0を返す関数です。

これでやっと、ひっくり返せるか確認する関数ができました。
ここが一番の難所なので、理解できれば後はサクサク進めるかと思います。

第五課へ
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送