すみません。ソースは添付できないんですね.....(^^;
#include<stdio.h>
// 概要
// check()関数から呼び出しされるサブ関数
// 指定されたbord[y][x]から隣接するxx,yy方向の駒を
// ひっくり返せるかチェック。
// xx,yyはそれぞれ -1,0,1の何れかであることが大前提
//
// 返値 0:存在無し、1:存在する
int check_sub(int *bord,int x,int y,int xx,int yy,int player)
{
int c,flag;
flag=0; //ひっくり返したかどうかフラグ(^-^;
for (;;) {
//x,yのxx,yy方向に移動
x+=xx;
y+=yy;
//x,yが盤の範囲外に出たらそのxxyy方向にはひっくり返せない
if (x<0 || y <0 || x>7 || y>7) return 0;
c=bord[y*8+x];
//x,y上に駒がなければひっくり返せない。
if(c==0) return 0;
//自分の駒を見つけた時
if( c == player+1 ) {
if(flag==0) return 0; // 隣は自分の駒でした。
else return 1; // ひっくり返せる駒があった!
}else flag=1; // 相手の駒を見つけたときはフラグを立てる
}
}
//
// 概要
// check_sub()関数を使用して隣接する8方向にひっくり返せる
// パターンがあるかどうかをチェック
// 左上から時計回りにチェックし、下位ビットからそのパターン有無
// 結果をセットする。
//
// 返値 0~255(0:置けない、255:全方向ひっくり返る)
int check(int *bord,int x,int y,int player)
{
int houkou;
//houkouをリセット
houkou=0;
if(check_sub(bord,x,y,-1,-1,player)) houkou |= 1; // 1.左上方向チェック
if(check_sub(bord,x,y, 0,-1,player)) houkou |= 2; // 2.上方向チェック
if(check_sub(bord,x,y, 1,-1,player)) houkou |= 4; // 3.右上方向チェック
if(check_sub(bord,x,y, 1, 0,player)) houkou |= 8; // 4.右方向チェック
if(check_sub(bord,x,y, 1, 1,player)) houkou |= 16; // 5.右下方向チェック
if(check_sub(bord,x,y, 0, 1,player)) houkou |= 32; // 6.下方向チェック
if(check_sub(bord,x,y,-1, 1,player)) houkou |= 64; // 7.左下方向チェック
if(check_sub(bord,x,y,-1, 0,player)) houkou |=128; // 8.左上方向チェック
return houkou;
}
//
// 概要
// xx,yy方向にて指定された方向をひっくり返す。
// 自分の駒を見つけるまで繰り返し実行する。
//
// 返値 無し
void reverse_sub(int *bord,int x,int y,int xx,int yy,int player)
{
int c;
for (;;) {
//x,yのxx,yy方向に移動
x += xx;
y += yy;
//自分の駒を見つけた時
if( bord[y*8+x] == player+1 ) return; // ひっくり返し完了
//ひっくり返し実行
bord[y*8+x] = player+1;
}
}
//
// 概要
// reverse_sub()関数を使用してフラグにて指定された方向をひっくり返す。
// フラグはcheck()関数で得られたものを使用することが大前提。
// そのため、この関数の中ではエラーチェックは行わない。
//
// 返値 無し
void reverse(int *bord,int x,int y,int player,int flag)
{
if(flag & 1) reverse_sub(bord, x, y,-1,-1, player); // 1.左上方向ひっくり返し
if(flag & 2) reverse_sub(bord, x, y, 0,-1, player); // 2.上方向ひっくり返し
if(flag & 4) reverse_sub(bord, x, y, 1,-1, player); // 3.右上方向ひっくり返し
if(flag & 8) reverse_sub(bord, x, y, 1, 0, player); // 4.右方向ひっくり返し
if(flag & 16) reverse_sub(bord, x, y, 1, 1, player); // 5.右下方向ひっくり返し
if(flag & 32) reverse_sub(bord, x, y, 0, 1, player); // 6.下方向ひっくり返し
if(flag & 64) reverse_sub(bord, x, y,-1, 1, player); // 7.左下方向ひっくり返し
if(flag & 128) reverse_sub(bord, x, y,-1, 0, player); // 8.左上方向ひっくり返し
}
int main (void)
{
char *tate[8]={"0","1","2","3","4","5","6","7"};
char end;
int bord[8][8];
int x,y;
int i,j,flag,cnt;
int player;
// 0.ボードの初期化
for(i=0;i<8;i++)
for(j=0;j<8;j++)
bord[i][j]=0;
bord[3][3]=1;
bord[4][4]=1;
bord[3][4]=2;
bord[4][3]=2;
cnt=4; //既に4つ置かれている
player=0;
for(;cnt <64;){
// 1.盤の表示
printf(" 01234567\n");
for(i=0;i<8;i++){
printf(tate[i]);
for(j=0;j<8;j++){
if(bord[i][j] == 0) printf("*");
else if(bord[i][j] == 1) printf("●");
else printf("○");
}
printf("\n");
}
// 2.メッセージ出力&値入力
if(player%2==0) printf("白の番です。\n");
else printf("黒の番です。\n");
printf("y座標とx座標どちらも100と入力すると相手のターンにします。(-1で終了)\n");
printf("y座標を入力してください。(縦軸)");
scanf_s("%d", &y);
printf("x座標を入力してください。(横軸)");
scanf_s("%d", &x);
// 3.終了処理
if(x==-1&&y==-1) {
printf("終了コマンドが入力されました。本当に終了しますか?(Y or N)");
for(;;) {
end=getchar();
if(end == 'y' || end == 'Y' || end == 'n' || end == 'N') break;
}
if(end=='y' || end=='Y') {
printf("処理を終了します。\n");
break;
}
if(end=='n' || end=='N') {
printf("処理を続行します。\n");
continue;
}
}
// 4.x=100,y=100の場合、石を置く権利を相手に移す
if(x==100 && y==100) {
printf("\n石を置く権利を相手に渡します。\n\n");
player ^= 1; // 相手変更 0←→1
continue;
}
// 5.エラー処理(入力された数字が許容範囲外)
if(x<0 || x>=8 || y<0 || y>=8 )
{
printf("\n許容範囲外です。\n");
printf("もう一度入力してください。\n\n");
}
// 6.エラー処理(同じところには置けない)
if(bord[y][x]!=0) {
printf("\n置かれてるよ!\n");
continue;
}
// 7.ひっくり返せるかチェック
flag=check(&bord[0][0], x, y, player); // flagには方向が入る
if(flag==0){
// 6-1.ひっくり返せない場合はメッセージ
printf("\nそこには置けないんだな\n\n");
continue;
}else {
bord[y][x]=player+1;
reverse(&bord[0][0], x, y, player, flag);
player ^= 1; // 相手変更 0←→1
cnt++; // 置いた駒の数カウントアップ
}
} //loop終了地点
printf("終わり!\n");
return 0;
}
お礼
またまた回答ありがとうございます。 >グローバル変数は一見、非常に便利に見えますが、プログラムが >大きくなるとどこでどう値が変化しているか検討がつかなく >なる可能性があります。 なんだって!そんなこと本には書いてなかったぞ! そうなんですか・・・勉強になりました。 iやjなどはローカル変数にするべきなんですね。 >基本的にmain()関数はコンパクトにまとめるべきです。 >私のサンプルでも長いくらいで、ゲーム本体は別関数にまとめるべき>だったなぁと反省してます。 main関数はコンパクトにですか。 これも頭に刻んでおきます。 ではmain関数はほかの関数の呼び出しとちょこっとの機能だけでいいんですね。勉強になります・・・ >1.bord[][]をグローバル変数化する。 >2.縦・横それぞれ8ですが、「#define XMAX 8」「#define YMAX >8」等としてdefine文による定数を使用、直接数値を使用しないよう>する。 >3.ゲーム実行部分の関数化 >4.ゲーム盤表示部分の関数化 >5.行き詰まり自動判定 >6.両者行き詰まり判定 >7.勝敗表示 2.ですが私も最初はマクロを使おうと思ったんですが「マクロ」と聞くだけでどうしても苦手意識が・・・ 5,6,7は時間をかけてじっくりしていきます。 これ以上世話になると将来プログラマを目指している私として何か大事なものが欠けそうな気がするので、オセロの件での質問は終了とさせていただきます。ソースを書いてくださったり初心者相手にとてもわかりやすく回答してくれました。 本当にありがとうございました。 またお世話になるかもしれませんがそのときはよろしくお願いします。 ※サンプルソースは、大事な参考として使わせていただきます。 ありがとうございました。