ソースの分割について

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

ソースの分割について

#1

投稿記事 by 学生A » 14年前

今、c言語で300行程度のオセロのプログラムを書きました。
これから、AIの部分を作ろうとしていて、そのためにcomputerの思考の部分だけ別のヘッダファイル/ソースファイルに分離しようとしています。
しかし、私は複数のソースファイルでプログラムを組んだことがないので、どうしたら良いか分からずじまいです。
externや#ifdefがどうたらこうたらで、もう降参状態です\(^o^)/
以下にソースを貼り付けますので、どのように分割すればよいかご教授ください。
また、他に直したほうが良いところなどがあれば、指摘してくださいると嬉しいです。
(関数や変数のネーミングセンスが終わっているのは仕様です。。。)

コード:

#include <stdio.h>
//1=白
//2=黒
//0=空白
int board[8][8]={{0,0,0,0,0,0,0,0},
				 {0,0,0,0,0,0,0,0},
				 {0,0,0,0,0,0,0,0},
				 {0,0,0,1,2,0,0,0},
				 {0,0,0,2,1,0,0,0},
				 {0,0,0,0,0,0,0,0},
				 {0,0,0,0,0,0,0,0},
				 {0,0,0,0,0,0,0,0}};

int hyoukati[8][8]={{100,50 ,30 ,10 ,10 ,30 ,50 ,100},
				    {50 ,-50,20 ,-10,-10,20 ,-50,50 },
				    {30 ,20 ,40 ,20 ,20 ,40 ,20 ,30 },
				    {10 ,-10,20 ,0  ,0  ,20 ,-10,10 },
				    {10 ,-10,20 ,0  ,0  ,20 ,-10,10 },
				    {30 ,20 ,40 ,20 ,20 ,40 ,20 ,30 },
				    {50 ,-50,20 ,-10,-10,20 ,-50,50 },
				    {100,50 ,30 ,10 ,10 ,30 ,50 ,100}};

int turn=2;
int computer=1;

struct COUNTBOARD {
	int c0;
	int c1;
	int c2;
};
struct MASU {
	int x;
	int y;
	int ok;
};
void game(void);
void printboard(void);
void turn_change(void);
COUNTBOARD countboard(void);
char* numberintochara(int);
int checkcell(int,int);
int isoverboard(int,int);
void putkoma(int,int);
int canputkoma(void);
MASU computerthinking(int *b);

int main(void) {

	int temp;
	

	game();
	printf("オセロゲームを終了します。何かキーを押してEnterを押してください。\n");
	scanf("%d",&temp);

	return 0;
}

void game(void) {
	int p,q,skip;

skipflag:
	while(canputkoma()!=0) {
		skip=0;
		printboard();
		if (turn!=computer) {
			printf("置きたい場所を半角スペース区切りで入力してください。例:一番右上なら「0 7」\n>>");
			scanf("%d%d",&p,&q);
			while (checkcell(p,q)==0) {
				printf("そこには置けません\n");
				scanf("%d%d",&p,&q);
			}
		} else {
			MASU m=computerthinking(*board);
			if (m.ok==1) {
				p=m.x;
				q=m.y;
				printf(">>%d %d\n",p,q);
			} else {
				break;
			}
		}
		putkoma(p,q);
		turn_change();
	}
	skip++;
	if (skip==1) {
		printboard();
		printf("%sはスキップ!\n",numberintochara(turn));
		turn=3-turn;
		goto skipflag;
	}
	if (skip==2) {
		printboard();
		printf("%sはスキップ!\n",numberintochara(turn));
		printf("両者連続パスしたので、ゲームを終了します\n",numberintochara(turn));
	}
}

void printboard(void) {
	int i=0,j=0;
	printf("-------------------------------\n");
	printf("[Turn:%s]\n",numberintochara(turn));
	for (j=0;j<8;j++) {
		printf(" %d",j);
	}
	printf("\n");
	for (i=0;i<8;i++) {
		printf("%d",i);
		for (j=0;j<8;j++) {
			switch (board[i][j]) {
			case 0:
				printf("×");
				break;
			case 1:
				printf("○");
				break;
			case 2:
				printf("●");
				break;
			}
		}
		printf("\n");
	}
	COUNTBOARD cb=countboard();
	printf("   ○%d-%d●\n",cb.c1,cb.c2);
}

void turn_change(void) {

	turn=3-turn;

}

COUNTBOARD countboard(void) {
	int i=0,j=0,c0=0,c1=0,c2=0;
	COUNTBOARD cb;
	for (i=0;i<8;i++) {
		for (j=0;j<8;j++) {
			switch (board[i][j]) {
			case 0:
				c0++;
				break;
			case 1:
				c1++;
				break;
			case 2:
				c2++;
				break;
			}
		}
	}
	cb.c0=c0;
	cb.c1=c1;
	cb.c2=c2;
	return cb;
}

char* numberintochara(int c) {

	if (c==0) {
		return "blank";
	}
	if (c==1) {
		return "white";
	}
	if (c==2) {
		return "black";
	}

	return "unknown";
}

int checkcell(int p,int q) {
	int dx,dy,px,py,allcount=0,count;

	if (isoverboard(p,q)==1) {return 0;}
	if (board[p][q]!=0) {return 0;}
	for(dx=-1;dx<=1;dx++) {
		for(dy=-1;dy<=1;dy++) {
			if (dx==0 && dy==0) {continue;}
			px=p+dx;
			py=q+dy;
			count=0;
			while(isoverboard(px,py)==0 && board[px][py] == 3-turn) {
				px+=dx;
				py+=dy;
				count++;
			}
			if (isoverboard(px,py)==0 && board[px][py]==turn) {
				allcount+=count;
			}
		}
	}
	return allcount;
}

int isoverboard(int p,int q) {
	int ret;
	if (p<0 || p>7 || q<0 || q>7) {ret=1;} else {ret=0;}
	return ret;
}

void putkoma(int p ,int q) {
	board[p][q]=turn;
	int dx,dy,px,py;

	for(dx=-1;dx<=1;dx++) {
		for(dy=-1;dy<=1;dy++) {
			if (dx==0 && dy==0) {continue;}
			px=p+dx;
			py=q+dy;
			while(isoverboard(px,py)==0 && board[px][py] == 3-turn) {
				px+=dx;
				py+=dy;
			}
			if (isoverboard(px,py)==0 && board[px][py]==turn) {
				px=p+dx;
				py=q+dy;
				while(isoverboard(px,py)==0 && board[px][py] == 3-turn) {
					board[px][py]=turn;
					px+=dx;
					py+=dy;
				}
			}
		}
	}
}

int canputkoma(void) {
	int i,j,value=0;

	for(i=0;i<8;i++) {
		for(j=0;j<8;j++) {
			value+=checkcell(i,j);
		}
	}

	return value;
}

MASU computerthinking(int *b){
	int i,j,p,q,max=-1000;
	for(i=0;i<8;i++) {
		for(j=0;j<8;j++) {
			if (checkcell(i,j)!=0) {
				if (max<hyoukati[i][j]) {max=hyoukati[i][j];p=i;q=j;}
			}
		}
	}
	MASU m;
	m.x=p;
	m.y=q;
	if (max==-1000) {m.ok=0;} else {m.ok=1;}
	return m; 
}

学生A

Re: ソースの分割について

#2

投稿記事 by 学生A » 14年前

あ、↑はmain.cppのソースコードです。
コメント等が無く見づらいとは思いますが、どうかよろしくお願いします。

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: ソースの分割について

#3

投稿記事 by ookami » 14年前

まず、拡張子からしてC言語ではなくC++言語でしょうね。構文の異なる部分がかなりあるので、区別してくださいね。
あと、開発環境はなんですか?VisualStudio等... バージョンも併記してください。

> externや#ifdefがどうたらこうたらで、もう降参状態です
どう分からないのかいまいちですが、
どんな本やサイトを参考にしましたか?
http://www.geocities.jp/ky_webid/c/032.html
このあたりは参考になりますか?

学生A

Re: ソースの分割について

#4

投稿記事 by 学生A » 14年前

>まず、拡張子からしてC言語ではなくC++言語でしょうね。構文の異なる部分がかなりあるので、区別してくださいね。
>あと、開発環境はなんですか?VisualStudio等... バージョンも併記してください。
すみません。C言語は、C++言語の間違いです。また、開発環境はVisial Studio 2010 professionalです。

>どう分からないのかいまいちですが、
具体的に言うと、externの使いどころや、externと#ifdef~#endifの違いがよく分かりません、
サイトは参考にしましたが、どれも短いコード内での分割で、これくらいの長さのコードになると混乱してしまいます。

共通の変数・関数を管理する「Global.cpp」「Global.h」
ゲームの流れ、入出力等を管理する「main.cpp」「main.h」
コンピューターの思考専門の「computer.cpp」「computer.h」
くらいに分割してみようと思いましたが、二重定義エラー とか 識別子が見つかりませんでした というエラーが出てビルドさえ出来ません。
仮にビルドに成功しても、このような機能による分割でいいのかどうかも怪しくて、なかなか勧めません。

ookamiさん、返信ありがとうございました。

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

Re: ソースの分割について

#5

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

externは外部公開する変数=グローバル変数です。
まぁ、グローバル変数は良くない事なので引数で受け渡すのが望ましいです。
将来クラス化することを考慮するなら絶対避けるべきです。

「C言語編 第32章 ファイル分割」
http://www.geocities.jp/ky_webid/c/032.html
「C言語編 第30章 ポインタを引数や戻り値にする」
http://www.geocities.jp/ky_webid/c/030.html

>#ifdef~#endifの違いがよく分かりません、
これはヘッダの多重インクルード(二重定義エラー)を阻止するために使います。ヘッダの先頭と最後に記述するのが正しい使い方です。
クラス化もされていないでC言語のファイル分割法をご紹介します。

「C言語編 第60章 インクルードガード」
http://www.geocities.jp/ky_webid/c/060.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

学生A

Re: ソースの分割について

#6

投稿記事 by 学生A » 14年前

softya(ソフト屋)さん、ookamiさん、ありがとうございます。おそらく分割コンパイルらしきものが出来ました!!
結局、Gloval.cpp・Gloval.hは要らないということにして、main.cpp・main.h・computer.cpp・computer.hの4つのファイルに分割しました。
以下がコードです。

コード:

/* main.h */

#ifndef __MAIN__
#define __MAIN__

extern int board[8][8];
extern int hyoukati[8][8];
extern int turn;
extern int computer;

struct COUNTBOARD {
    int c0;
    int c1;
    int c2;
};
struct MASU {
    int x;
    int y;
    int ok;
};



void game(void);
void printboard(void);
void turn_change(void);
COUNTBOARD countboard(void);
char* numberintochara(int);
int checkcell(int,int);
int isoverboard(int,int);
void putkoma(int,int);
int canputkoma(void);

#endif

コード:

/* main.cpp */

#include <stdio.h>
#include "main.h"
#include "computer.h"

//1=白
//2=黒
//0=空白
int board[8][8]={{0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0},
                 {0,0,0,1,2,0,0,0},
                 {0,0,0,2,1,0,0,0},
                 {0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0}};
 
int hyoukati[8][8]={{100,-50,30 ,10 ,10 ,30 ,-50,100},
                    {-50,-50,20 ,-10,-10,20 ,-50,-50},
                    {30 ,20 ,40 ,20 ,20 ,40 ,20 ,30 },
                    {10 ,-10,20 ,0  ,0  ,20 ,-10,10 },
                    {10 ,-10,20 ,0  ,0  ,20 ,-10,10 },
                    {30 ,20 ,40 ,20 ,20 ,40 ,20 ,30 },
                    {-50,-50,20 ,-10,-10,20 ,-50,-50},
                    {100,-50,30 ,10 ,10 ,30 ,-50,100}};
 
int turn=2;
int computer=1;

extern struct COUNTBOARD;
extern struct MASU;

int main(void) {
 
    int temp;
    
 
    game();
    printf("オセロゲームを終了します。何かキーを押してEnterを押してください。\n");
    scanf("%d",&temp);
 
    return 0;
}
 
void game(void) {
    int p,q,skip;
 
skipflag:
    while(canputkoma()!=0) {
        skip=0;
        printboard();
        if (turn!=computer) {
            printf("置きたい場所を半角スペース区切りで入力してください。例:一番右上なら「0 7」\n>>");
            scanf("%d%d",&p,&q);
            while (checkcell(p,q)==0) {
                printf("そこには置けません\n");
                scanf("%d%d",&p,&q);
            }
        } else {
            MASU m=computerthinking(*board);
            if (m.ok==1) {
                p=m.x;
                q=m.y;
                printf(">>%d %d\n",p,q);
            } else {
                break;
            }
        }
        putkoma(p,q);
        turn_change();
    }
    skip++;
    if (skip==1) {
        printboard();
        printf("%sはスキップ!\n",numberintochara(turn));
        turn=3-turn;
        goto skipflag;
    }
    if (skip==2) {
        printboard();
        printf("%sはスキップ!\n",numberintochara(turn));
        printf("両者連続パスしたので、ゲームを終了します\n",numberintochara(turn));
    }
}
 
void printboard(void) {
    int i=0,j=0;
    printf("-------------------------------\n");
    printf("[Turn:%s]\n",numberintochara(turn));
    for (j=0;j<8;j++) {
        printf(" %d",j);
    }
    printf("\n");
    for (i=0;i<8;i++) {
        printf("%d",i);
        for (j=0;j<8;j++) {
            switch (board[i][j]) {
            case 0:
                printf("×");
                break;
            case 1:
                printf("○");
                break;
            case 2:
                printf("●");
                break;
            }
        }
        printf("\n");
    }
    COUNTBOARD cb=countboard();
    printf("   ○%d-%d●\n",cb.c1,cb.c2);
}
 
void turn_change(void) {
 
    turn=3-turn;
 
}
 
COUNTBOARD countboard(void) {
    int i=0,j=0,c0=0,c1=0,c2=0;
    COUNTBOARD cb;
    for (i=0;i<8;i++) {
        for (j=0;j<8;j++) {
            switch (board[i][j]) {
            case 0:
                c0++;
                break;
            case 1:
                c1++;
                break;
            case 2:
                c2++;
                break;
            }
        }
    }
    cb.c0=c0;
    cb.c1=c1;
    cb.c2=c2;
    return cb;
}

char* numberintochara(int c) {
 
    if (c==0) {
        return "blank";
    }
    if (c==1) {
        return "white";
    }
    if (c==2) {
        return "black";
    }
 
    return "unknown";
}
 
int checkcell(int p,int q) {
    int dx,dy,px,py,allcount=0,count;
 
    if (isoverboard(p,q)==1) {return 0;}
    if (board[p][q]!=0) {return 0;}
    for(dx=-1;dx<=1;dx++) {
        for(dy=-1;dy<=1;dy++) {
            if (dx==0 && dy==0) {continue;}
            px=p+dx;
            py=q+dy;
            count=0;
            while(isoverboard(px,py)==0 && board[px][py] == 3-turn) {
                px+=dx;
                py+=dy;
                count++;
            }
            if (isoverboard(px,py)==0 && board[px][py]==turn) {
                allcount+=count;
            }
        }
    }
    return allcount;
}
 
int isoverboard(int p,int q) {
    int ret;
    if (p<0 || p>7 || q<0 || q>7) {ret=1;} else {ret=0;}
    return ret;
}
 
void putkoma(int p ,int q) {
    board[p][q]=turn;
    int dx,dy,px,py;
 
    for(dx=-1;dx<=1;dx++) {
        for(dy=-1;dy<=1;dy++) {
            if (dx==0 && dy==0) {continue;}
            px=p+dx;
            py=q+dy;
            while(isoverboard(px,py)==0 && board[px][py] == 3-turn) {
                px+=dx;
                py+=dy;
            }
            if (isoverboard(px,py)==0 && board[px][py]==turn) {
                px=p+dx;
                py=q+dy;
                while(isoverboard(px,py)==0 && board[px][py] == 3-turn) {
                    board[px][py]=turn;
                    px+=dx;
                    py+=dy;
                }
            }
        }
    }
}
 
int canputkoma(void) {
    int i,j,value=0;
 
    for(i=0;i<8;i++) {
        for(j=0;j<8;j++) {
            value+=checkcell(i,j);
        }
    }
 
    return value;
}

コード:

/* computer.h */

#ifndef __COMPUTER__
#define __COMPUTER__

MASU computerthinking(int *b);

#endif

コード:

/* computer.cpp */

#include "main.h"

MASU computerthinking(int *b){
    int i,j,p,q,max=-1000;
    for(i=0;i<8;i++) {
        for(j=0;j<8;j++) {
            if (checkcell(i,j)!=0) {
                if (max<hyoukati[i][j]) {max=hyoukati[i][j];p=i;q=j;}
            }
        }
    }
    MASU m;
    m.x=p;
    m.y=q;
    if (max==-1000) {m.ok=0;} else {m.ok=1;}
    return m; 
}
こんな感じの分割で問題ないでしょうか。
たまたまビルドが通っているだけかも・・・
ご意見よろしくお願いします。

#追加質問
ソースを分割していて思ったのですが、

①私は" "や{ }で文字を囲むときに「文字よりも先に記号を書いてから、文字を書く」という順番で書いています。
 しかし、#include "" と入力した途端、例えば#include "main.h"などと勝手に保管されてしまいます。
 願わくば勝手に保管されないで欲しいのですが、解決法はありますか。(上記のとおり、当方の環境はVS2010 professionalです。)

②ソースファイル/ヘッダファイルを追加しているときに、例えば「computer.h」を追加したら自動的に「computer.cpp」が追加されるというような機能はVS2010にありますか。
 いちいち手動で追加するのがめんどくさいと思いました。

上記2点に対して解答してくださると嬉しいです。
長文失礼しました。

学生A

Re: ソースの分割について

#7

投稿記事 by 学生A » 14年前

この投稿をもって、このトピックは解決済みとさせていただきます。
チェックするのを忘れていました。

白い時空
記事: 18
登録日時: 14年前
住所: 埼玉県さいたま市

Re: ソースの分割について

#8

投稿記事 by 白い時空 » 14年前

私はVC2010ですが、

オプション→テキストエディタ→C/C++→詳細
に移動し、「#includeのオートコンプリートの無効化」をtrueにしたら出来ました。


プロジェクト→クラスの追加
でC++クラスを追加すると、クラス名と同名の.cppと.hの2つのファイルが追加されるんですが、できたファイルにクラスの雛形が勝手に書かれてます。
その後、それを消せばいいかと。
消す必要があるのでちょっと面倒かもしれませんが。

学生A

Re: ソースの分割について

#9

投稿記事 by 学生A » 14年前

白い時空さん、返信ありがとうございます。
無事に希望通りに設定することが出来ました。
これで少々ストレスも減りそうです。
ありがとうございました。

閉鎖

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