学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

C++プログラミング入門その21 モジュールと分割コンパイル2

>>この記事には書き直した新しいページがあります。<<


<<前  [TOP]  次>>


Visual Studioで新規プロジェクトを作り、以下の2つのcppファイル、1つのヘッダーファイルを作成して下さい。


【Game_head.h】

/* header file : Game_head.h */

int yesno();

void current_point();

void enemy_create();

void hero_create();

int escape();

void calc_parameter(int suit, int strong);

void hero_die();

void show_status();

void map_create();

void get_drug(int exist, int strong);

int pos_compare(int a_x, int a_y, int b_x, int b_y);

void walk_arround(char move);

void use_drug();

void get_enemyitem();

void fight();

void command();

#ifdef MAIN

/* enemy */

int enemy_x;
int enemy_y;
int enemy_life;
int enemy_offence;
int enemy_defence;
int enemy_item_suit;
int enemy_item_strong;

/* map */

int map_wide_x;
int map_wide_y;
int map_ent_x;
int map_ent_y;
int map_floor = 0;
int map_item_exist;
int map_item_strong;
int map_item_x;
int map_item_y;

/* hero */

int hero_point;
int hero_x;
int hero_y;
int hero_life;
int hero_life_upper;
int hero_offence;
int hero_defence;
int hero_drug;
int hero_sword;
int hero_buckler;
int hero_armer;

#else

/* enemy */

extern int enemy_x;
extern int enemy_y;
extern int enemy_life;
extern int enemy_offence;
extern int enemy_defence;
extern int enemy_item_suit;
extern int enemy_item_strong;

/* map */

extern int map_wide_x;
extern int map_wide_y;
extern int map_ent_x;
extern int map_ent_y;
extern int map_item_exist;
extern int map_item_strong;
extern int map_item_x;
extern int map_item_y;
extern int map_floor;

/* hero */

extern int hero_point;
extern int hero_x;
extern int hero_y;
extern int hero_life;
extern int hero_life_upper;
extern int hero_offence;
extern int hero_defence;
extern int hero_drug;
extern int hero_sword;
extern int hero_buckler;
extern int hero_armer;

#endif



【Game_main.cpp】

#include <iostream>
#include <stdlib.h>

#define MAIN

#include "Game_head.h"

void main() {

	int input;

        hero_create();
        map_create();
        current_point();

        std::cout << "Input senario Number => ";
		std::cin >> input;
		std::cin.clear();
		std::cin.ignore();
		
        srand(input);

        while(true) {

                if(enemy_life <= 0) {

                        enemy_create( );
                }

				std::cout << "現在位置 (" << hero_x << "," << hero_y << "):地下 " << map_floor << "階" << std::endl << std::endl;

                command();

                if( pos_compare(map_item_x,map_item_y,hero_x,hero_y)){

                        get_drug(map_item_exist, map_item_strong);
                        map_item_exist=0;
                }

                if( pos_compare(map_ent_x,map_ent_y, hero_x,hero_y)) {

					std::cout << "階段があった。下に降りますか? ";

                        switch(yesno()) {

                                case 1: map_create();
                                        enemy_create();
                                        current_point();
										std::cout << std::endl << std::endl << "地下 " << map_floor << "階に降りた。" << std::endl << std::endl;
                                        break;

			}

                }

                if (pos_compare(hero_x,hero_y, enemy_x,enemy_y)) {

                        int point=hero_point;
                        fight();

                        if(point < hero_point) {

                                enemy_create();
                        }
                }
        }

}

void show_status( ) {

	std::cout << std::endl << "現在の状況:" << std::endl;
	std::cout << "体力: " << hero_life << "/" << hero_life_upper << "\t攻撃力:" << hero_offence << "\t守備力:" << hero_defence << std::endl;

	std::cout << "\t経験値:" << hero_point << std::endl;
	std::cout << std::endl;
	std::cout << "持ち物のレベル" << std::endl;
	std::cout << "剣:" << hero_sword << "\t盾:" << hero_buckler << "\t鎧:" << hero_armer << std::endl << std::endl;

	std::cout << "薬の回復力:" << hero_drug << std::endl << std::endl << std::endl;
	return;
}

void hero_die( ) {

	std::cout << "Hero is died at floor " << map_floor << "." << std::endl;
	std::cout << std::endl;
	std::cout << "status" << std::endl;
	std::cout << "hero level " << hero_point/10 << std::endl;
	std::cout << std::endl;
	std::cout << "Game Over" << std::endl;
	exit(0);
}

void calc_parameter( int suit, int strong ) {

	switch(suit) {

                case 1: hero_offence = hero_offence - hero_sword + strong;
                        hero_sword = strong; break;

                case 2: hero_defence = hero_defence - hero_buckler + strong;
                        hero_buckler = strong; break;

                case 3: hero_defence = hero_defence - hero_armer + strong;
                        hero_armer = strong; break;
        }

        return;

}

void use_drug( ) {

	if(hero_drug > 0) {

		hero_life += hero_drug;

		if(hero_life_upper < hero_life) {

			hero_life = hero_life_upper;
		}

		hero_drug=0;
		std::cout << std::endl << "\t薬を使った。\b" << std::endl << std::endl;
		show_status();
	}

	else {

		std::cout << std::endl << "\t薬は今持ってない。" << std::endl << std::endl;
	}
}

void get_enemyitem( ) {

	if ( enemy_item_suit!=0 ) {

                show_status();

				std::cout << "\t敵はアイテムを持っていた。" << std::endl;

                switch(enemy_item_suit) {

                        case 1: std::cout << "剣:level " <<enemy_item_strong << std::endl;
                                break;

                        case 2: std::cout << "盾:level " <<enemy_item_strong << std::endl;
                                break;

                        case 3: std::cout << "鎧:level " << enemy_item_strong << std::endl;
                                break;
                }

                std::cout << "装備するか?";

                if(yesno()) {

					std::cout << "\tヒーローの状態が変わった。\b" << std::endl<< std::endl;
                        calc_parameter(enemy_item_suit, enemy_item_strong);
                        show_status();
                }

                else {

					std::cout << "\tアイテムを捨てた!" << std::endl << std::endl;
                }
        }
        else {

			std::cout << "\t敵はアイテムを持っていなかった。" << std::endl << std::endl;
        }
        return;

}

int escape() {

	int x, y;

	x = rand()%10;
	y = rand()%10;

	if( x < y ) {

		return !0;
	}

	else {

		return 0;
	}
}

void fight() {

	int dum;

        while(true) {
                show_status( );
				std::cout <<"敵と戦いますか?";

                if ( yesno()==0 && escape() == 1){
					std::cout << "\t敵から逃げました。" << std::endl << std::endl;
                        break;
                }
                else {
					std::cout << "\t敵と戦います。" << std::endl << std::endl;
                }
				std::cout << "Heroの攻撃:";
                dum = (hero_offence*(rand()%10)) / (enemy_defence+1);
                enemy_life -= dum;
				std::cout << "敵に " << dum << "のダメージ" << std::endl << std::endl;

                if(enemy_life -= dum){
					std::cout << "\t敵を倒した!\b" << std::endl << std::endl;
                        hero_point ++;
                        hero_life_upper+=10;
						std::cout << "\tレベルが上がった。\b" << std::endl << std::endl;
                        get_enemyitem( );
                        break;
                }
				std::cout << "敵の攻撃:";
                dum = (enemy_offence*(rand()%10)) / (hero_defence+1);
                hero_life -= dum;
				std::cout << dum << "のダメージを受けた!" << std::endl << std::endl;

		if (hero_life <=0) {
                        hero_die();
                }
        }
        return;

}

void command() {
	char input;
	std::cout << "Command mode" << std::endl;
	std::cout << "         up:   k" << std::endl;
	std::cout << "left:h  status:s          right:l" << std::endl;
	std::cout << "          down: j" << std::endl << std::endl;
	std::cout << "use drug:d         Quit:q" << std::endl;
	for(;;) {
		std::cout << std::endl << "comand input => ";
		std::cin.clear();
		std::cin.ignore();
		std::cin >> input;

		if(!std::cin) {
			std::cout << "Error:";
		}
		else {
			if (input=='d') {
				use_drug();
				break;
			}
			else if (input == 's' ) {
				show_status();
				break;
			}
			else if (input=='j' || input=='k' || input=='l' || input=='h') {
				walk_arround(input);
				break;
			}
			else if(input=='q') {
				exit(0);
			}
		}
	}
	return;
}

/* move  lower j:  left l:  right h:  upper k */
void walk_arround( char move ) {
	if(move=='l') {
		if( hero_x == map_wide_x) {
			std::cout << "その方向には歩けません!" << std::endl;
			return;
		}
		hero_x++;
	}
	else if(move=='k') {
		if(hero_y == map_wide_y) {
			std::cout << "その方向には歩けません!" << std::endl;
			return;
		}
		hero_y++;
	}
	else if (move=='h'){
		if(hero_x == 0) {
			std::cout << "その方向には歩けません!" << std::endl;
			return;
		}
		hero_x--;
	}
	else if (move=='j') {
		if(hero_y == 0) {
			std::cout << "その方向には歩けません!" << std::endl;
			return;
		}
		hero_y--;
	}
	return;
}

int pos_compare(int a_x, int a_y, int b_x, int b_y) {

	if ( a_x == b_x && a_y == b_y ) {

		return !0;
	}
	else {

		return 0;
	}
}

void get_drug(int exist, int strong) {

	if(exist == 1) {

		std::cout << std::endl;
		std::cout << "\t薬(" << strong << ")を拾った!\b" << std::endl << std::endl;
		hero_drug+=strong;
	}
	return;
}

void current_point() {

	hero_x = rand()%map_wide_x;
	hero_y = rand()%map_wide_y;
	return;
}

int yesno() {

	char input;

        while(true){
			std::cout << "yes or no (y/n) => ";
			std::cin.clear();
			std::cin.ignore();
			std::cin >> input;

                if(!std::cin) {
					std::cout << "Error:" << std::endl << std::endl;
                }
                else {
                        switch(input) {
                                case 'y':
                                case 'Y': return !0;
                                          break;
                                case 'n':
                                case 'N': return 0;
                                          break;
                        }
                }
        }

}



【Game_create.cpp】

/* file : Game_create.cpp */

#include <iostream>
#include <stdlib.h>

#include "Game_head.h"

void map_create( ) {

        map_floor++;
        map_wide_x = rand()%( 2 + map_floor) + 10;
        map_wide_y = rand()%( 2 + map_floor) + 10;
        map_ent_x = rand()%map_wide_x;
        map_ent_y = rand()%map_wide_y;
        map_item_exist=1;
        map_item_strong= rand()%( 10+10*map_floor) + 30;
        map_item_x=rand()%map_wide_x;
        map_item_y=rand()%map_wide_y;
        return;
}

void hero_create() {

        hero_point = 0;
        hero_life_upper = 100 + rand()%10;
        hero_life = hero_life_upper;
        hero_x = 0;
        hero_y = 0;
        hero_offence = rand()%5 + 5;
        hero_defence = rand()%5 + 5;

        hero_drug = 0;

        hero_sword = rand()%3 +1;
        hero_buckler=rand()%3;
        hero_armer = rand()%2 +1;
        return;
}

void enemy_create() {

        int i;

        enemy_x = rand() % map_wide_x;
        enemy_y = rand() % map_wide_y;
        enemy_life = rand() % 100 + map_floor*50;
        enemy_offence=rand() % 10 + map_floor;
        enemy_defence=rand() % (map_floor+2);

        if ( rand() % 2 == 1 ) {

                i=rand()%3+1;
                enemy_item_suit=i;

                if(i==1) {

                        enemy_item_strong = rand()%(10 + map_floor);
                }

                else if ( i==2) {

                        enemy_item_strong = rand() % (5 + map_floor);
                }

                else {

                        enemy_item_strong = rand() % (7 + map_floor);
                }

        }

        else {

                enemy_item_suit = 0;
                enemy_item_strong = 0;
        }

        return;
}



前に作成したダンジョンゲームを、create()関数と、そのほかの関数、ヘッダファイルに分割しました。


外部変数は関数の外側で宣言した変数です。
外部変数はその性質上、プログラムの起動時に生成され、プログラムの終了まで消滅することはありません。
有効範囲は、すべてのモジュールにわたり、extern宣言を行うことで、他のモジュールから外部変数を参照することが可能になります。
他のモジュールで、外部変数として確保された変数は、以下のようにして別のモジュールから参照可能になります。

extern 変数の型 変数名;

extern宣言は、「どこか別の場所でその変数が定義されているものを使う」という宣言ですので、別の場所でexternなしの変数を作成する必要があります。


C言語では、プリプロセッサという機能が用意されています。
プリプロセッサとは、簡単に言うと前処理のことであり、前に出てきた#include機能もその一つです。

#define 記号定数名 値

このように宣言します。
ここで、文の終わりに ; は必要ありません。
この宣言は、コンパイルされる前にプリプロセッサによって処理され、実際にコンパイルされるときにはコンパイラーから見れば存在しない文となります。
この宣言は、標準ヘッダーでも使われています。


例えば、

#define EOF (-1)

と宣言しておけば、プログラムの中で EOF と書くと -1 となります。


define文には、もう一つ別の機能があります。
それがこのマクロ機能です。


マクロ機能は次のようにして使います。

#define マクロ名(引数) 引数を含む文字列

例えば、

#define sq (x) ((x)*(x))

のように宣言すれば、関数と同じようにsq(x)を使うことができます。
引数の型の宣言は必要ありません。
プログラム上でsq(3)とすれば、計算値 9を返してくれます。


プリプロセッサにおける条件文として、「#ifdef文」があります。


これは、以下のように使います。

#define DEBUG

・・・・・

#ifdef DEBUG

    std::cout << "Debug: hensuu = " << hensuu << std::endl;

#endif

つまり、DEBUGというマクロが定義されていたならば、#ifdefと#endifの間の行が有効になります。
もし、最初の行に #define DEBUG がなければ、この#ifdefと#endifの間の行はないものとしてプリプロセッサに処理されます。


この#ifdef文を使って外部変数をうまく使うことができます。

#ifdef THIS_MODULE

    int common;    /* このモジュールで使います */

 #else

    extern int common;    /* 他のモジュールから見ます */

 #endif

common変数を主に使いたいモジュールの先頭で、#define THIS_MODULEを定義して、このファイルをインクルードしておけば良いわけです。
もし、#define THIS_MODULEの定義がなければ、#elseの後の記述が読み込まれます。


では、サンプルプログラムの説明を少しします。


メイン関数のあるGame_main.cppの最初には define MAIN の記述がありますので、ヘッダファイルの#ifdefから#elseの手前までが処理されます。
create()関数のあるGame_create.cppには define MAIN の記述がありませんので、#elseから#endifまでの記述が処理されます。
Game_create.cppでは、externが用いられますので、Game_main.cppで使われた変数を参照する形になっています。
後の記述は前と同じです。実行結果も前と同じです。





<<前  [TOP]  次>>