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

学生向けにプログラミングを解説。Java、C++、Ruby、PHP、データベース

C++プログラミング入門その18 関数の宣言

<<前  [TOP]  次>>


Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。


Game1.cpp 直

#include <iostream>
#include <stdlib.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( );

/* 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;

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);

	for(;;) {

		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 << "階段があった。下に降りますか? ";

			if(yesno() == 1) {

				map_create();
				enemy_create();
				current_point();
				std::cout << std::endl << std::endl << "地下 " << map_floor << "階に降りた。" << std::endl << std::endl;
			}
		}
		if (pos_compare(hero_x,hero_y, enemy_x,enemy_y)) {

			int point=hero_point;
			fight();

			if(point < hero_point) {

				enemy_create();
			}
		}
	}
}

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 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 ) {

	if(suit==1) {
		hero_offence = hero_offence - hero_sword + strong;
		hero_sword = strong;
	}
	else if(suit==2) {
		hero_defence = hero_defence - hero_buckler + strong;
		hero_buckler = strong;
	}
	else if(suit==3) {
		hero_defence = hero_defence - hero_armer + strong;
		hero_armer = strong;
	}
	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;

		if(enemy_item_suit==1) {

			std::cout << "剣:level " << enemy_item_strong << std::endl;
		}

		else if( enemy_item_suit==2) {

			std::cout << "盾:level " << enemy_item_strong << std::endl;
		}
		else if(enemy_item_suit==3) {

			std::cout << "鎧:level " << enemy_item_strong ;
		}

		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;
	
	for(;;) {

		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 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;
}

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;

	for(;;){

		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 {

			if(input=='y' || input=='Y') {

				return !0;
			}

			else if (input=='n' || input=='N') {

				return 0;
			}
		}
	}
}



まず、このゲームの内容について説明します。


主人公は地下のダンジョンを冒険し、より深い地下に降りていくのが使命です。
地下の階はある広さがあり、主人公の位置は(7,4)のように座標で表示されます。
敵は1人だけしか一度には出てきませんが、敵を殺すと新たな敵が現れます。
敵は動けませんが、強さや装甲の堅さは乱数で決まります。
主人公が敵と同じマス目にはいると戦闘が始まります。
逃げることも出来ますが、逃走が成功するかどうかも乱数で決まります。
勝って勝利すると、敵が持っている強化アイテムを手に入れられます。(持っていないときもあります。)
また、マップには薬が必ず落ちています。
薬には主人公の生命力を回復させる働きがあり、その度合いにより強さがあり、薬を拾うとその強さが加算されています。
薬を使うと薬はなくなってしまいます。
敵の位置はわかりません。
また、地下への階段がどこかに必ずあります。


まず、以前説明した関数の定義をもう一度書いておきます。

返り値の型 関数名 ( 引数, 引数, ・・・・){ 

     実行文;
}



ここで、返り値の型を指定すると関数の返り値を整数以外にとることができます。

例 文字の整数値を与えると対応する文字を返す

    char mojikansuu(int a) {
        char c;
        c = a;
        return c;
    }

この例では、関数の名前の前にcharがあるので、関数mojikansuu()は文字型の関数となり、返り値は文字型でなければなりません。


もう一つ例をあげます。

例 ポインタを返す

    char *string() {
        char *s = "this is a test.";
        return s;
    }

この例は、アドレスを返す関数の例です。
[型]* はポインタを意味していますので、返り値はアドレスでなくてはなりません。
例では、"this is a test."という文字列のアドレスを返しています。


関数の宣言について説明します。


関数を作ったときに、積極的にコンパイラにその関数の型や引数を教えてあげると、コンパイラはもし間違った関数の呼び出しをしたときにきちんとその旨を知らせてくれます。
このように、コンパイラに関数の仕様を知らせるために、関数の仕様を書くことを関数の宣言といいます。
関数の宣言は、ファイルの先頭、すなわち#include文の後に書いておくと良いでしょう。

関数の型 関数名 ( 引数, 引数, ・・・・);


char mojikansuu(int a);

char *string(void);



もし、関数に引数がある場合は、引数の型もちゃんと宣言しなければなりません。
ただし、引数の変数名は、完全なダミーなので名前を変えることもできますし、省略することもできます。

char mojikansuu(int num);
char mojikansuu(int);



また、宣言の最後にセミコロン(;)をつけることを忘れないようにしなければなりません。


関数の引数がない場合は、voidを使ってください。
これにより、コンパイラは「この関数には引数がない」を理解できます。
ただしchar *string();というように、voidは省略して宣言することもできます。


関数の宣言がない場合はコンパイルエラーがおこりますので、かならずmain関数の前に関数の記述しておく癖をつけておいてください。


関数には引数としてアドレスを渡すことができます。
関数は結果を一つしか返すことができないので、複数の結果を返したいときは変数のアドレスを渡すことで、直接その値を操作することができます。

void str(char *add) ;

 void main() {

    char *s="this is a test.";
    str(s);
    std::cout << s << std::endl;
 }

 void str( char *add) {

    char *p= add;
    for ( ; *p != '\0'; p++) {
        if( *p == ' ' ) {
            *p = ':';
        }
    }
 }

この例の場合、main()で宣言している文字列"this is a test."のアドレスを関数str()に渡しています。
もちろん、関数str()でもそのアドレスを受け取ることができるように、引数の宣言にchar *addを用いている点に注意してください。
その結果、addには先の"this is a test"のアドレスが代入されることになります。
従って、この文字列を直接変更するので、main()関数での文字列出力でも、"this:is:a:test."に変更されています。


文字型ポインタでは、このプログラムで std::cout << *s << std::endl;とすると、"t"のみが出力されます。
この違いを覚えておいてください。


グローバル変数について少し書いておきます。


これまで学習してきた変数はすべて関数の中のみで有効でしたが、他の関数からも見ることができるような変数を作ることもできます。
このような変数をグローバル変数といいます。
C言語では、グローバル変数は2種類あり、同じプログラムソースにあるものと、違うプログラムソースにあるグローバル変数とは違う扱いになりますが、ここでは、同じプログラムソースにあるグローバル変数の宣言の仕方を学びます。
ファイル内で有効なグローバル変数を宣言するには、関数の外側、ファイルの最初のところで宣言すればよいです。

グローバル変数の例

#include <iostream>

 int gloval = 1;    /*グローバル変数*/

void test() {
    std::cout << "グローバル変数" << gloval << std::endl;
 }

 void main() {

    std::cout << "グローバル変数" << gloval << std::endl;
    gloval++;
    test();
 }

この例では、最初にグローバル変数は、1に設定されていて、main()野中で表示するときは1になっています。
つぎにその値を2に増やして、関数testを呼ぶと、関数testの中で表示しても確かに2になっています。


最後に、文字リテラルについて説明します。
ダブルコーテーション(””)で囲こみ、出力させる文字列の中に「¥t」や「¥b」というのを使用しています。
これを文字リテラルといいます。
文字リテラルは以下のように変換されます。

  • ¥n  改行
  • ¥t  水平タブ
  • ¥v  垂直タブ
  • ¥b  バックスペース
  • ¥¥ 円記号


    サンプルプログラムをビルドしてデバッグしてみましょう。
    最初の入力だけクリアがうまくいかないので、2回続けて入力してください。





    <<前  [TOP]  次>>