初質問/ゲームの移動用関数に苦戦しています

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
C言語初心者のがくせい

初質問/ゲームの移動用関数に苦戦しています

#1

投稿記事 by C言語初心者のがくせい » 3週間前

初質問です。4月からC言語を習い始めました。
あらかじめ作られたゲームの穴埋めと追加の機能を加えて提出する課題が出されました。
一部取り組んでみましたが、上下左右の移動用の関数の部分が空白になっていて苦戦しています。
ヒントとしてキャラクタの現在の座標を増減させ、成功と失敗とでそれぞれ1と0を返すと示されていました。
また、追加の機能として、斜めの移動等を考えていますがよりよいものがあれば教えていただきたいです。
協力お願いします。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// 敵の数の指定
#define ENEMYS	10

// 可視領域 ( 範囲 )
#define VISIBLE_AREA	20

// 表示に使用する文字色の宣言
#define	BLACK	"\x1b[30m"
#define	RED		"\x1b[31m"
#define	GREEN	"\x1b[32m"
#define	YELLOW	"\x1b[33m"
#define	BLUE	"\x1b[34m"
#define	MAGENTA	"\x1b[35m"
#define	CYAN	"\x1b[36m"
#define	WHITE	"\x1b[37m"

// 表示に使用する文字の背景色の宣言
#define	BACKGROUNDGRAY	"\x1b[47m"
#define	BACKGROUNDBLACK	"\x1b[40m"

// 表示に使用する文字の太さを宣言
#define	BOLD	"\x1b[1m"
#define	DEFAULT	"\x1b[0m"

// キャラクタ用の構造体
typedef struct CHARACTER {
	int x;		// キャラクタのx座標→右に移動するほど増える
	int y;		// キャラクタのy座標→下に移動するほど増える
}CHARACTER;

// 迷路の生成
char field[20][20] = { {'+', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '+'}, 
					   {'|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|'}, 
					   {'|', ' ', '+', '-', '-', '-', '-', '-', '-', ' ', ' ', '-', '-', '-', '-', '-', '-', '+', ' ', '|'}, 
					   {'|', ' ', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', '|'}, 
					   {'|', ' ', '|', ' ', '+', '-', ' ', ' ', '-', '-', '-', '-', ' ', ' ', '-', '+', ' ', '|', ' ', '|'}, 
					   {'|', ' ', ' ', ' ', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', '|', ' ', '|'}, 
					   {'|', '-', '|', ' ', '|', ' ', '+', '-', '-', ' ', ' ', '-', '-', '+', ' ', '|', ' ', '|', ' ', '|'}, 
					   {'|', ' ', ' ', ' ', '|', ' ', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', '|', ' ', '|'}, 
					   {'|', ' ', '|', ' ', '|', ' ', '|', ' ', '+', '-', '-', '+', ' ', '|', ' ', '|', ' ', ' ', ' ', '|'}, 
					   {'|', ' ', '|', ' ', '|', ' ', '|', ' ', ' ', ' ', ' ', '|', ' ', '|', ' ', '|', '-', '|', ' ', '|'}, 
					   {'|', ' ', '|', ' ', ' ', ' ', '|', ' ', '|', ' ', ' ', ' ', ' ', '|', ' ', '|', ' ', '|', ' ', '|'}, 
					   {'|', ' ', '|', ' ', '|', '-', '|', ' ', '+', '-', '-', '+', ' ', '|', ' ', ' ', ' ', '|', '-', '|'}, 
					   {'|', ' ', '|', ' ', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', '|', ' ', '|', ' ', '|'}, 
					   {'|', ' ', '|', ' ', '|', ' ', '+', '-', '-', ' ', ' ', '-', '-', '+', ' ', '|', ' ', '|', ' ', '|'}, 
					   {'|', '-', '|', ' ', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', ' ', ' ', '|'}, 
					   {'|', ' ', '|', ' ', '+', '-', ' ', ' ', '-', '-', '-', '-', ' ', ' ', '-', '+', ' ', '|', ' ', '|'}, 
					   {'|', ' ', '|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', '|'}, 
					   {'|', ' ', '+', '-', '-', '-', '-', '-', '-', '-', ' ', ' ', '-', '-', '-', '-', '-', '+', ' ', '|'}, 
					   {'|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|'}, 
					   {'+', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '+'} };
					   
				
// 上移動用関数
int Up( CHARACTER *object ) {

	return 1;
}

// 下移動用関数
int Down( CHARACTER *object ) {
   if(field[][]=' '){
      object y +=1;
	return 1;
}else{
   return 0;
}
}
// 左移動用関数
int Left( CHARACTER *object ) {
	return 1;
}

// 右移動用関数
int Right( CHARACTER *object ) {
	return 1;
}//上移動用関数からここまでを取り組む

// ユーザに指定された方向へキャラクタを移動させる関数
int Move(int num, CHARACTER *character) {
	int res;

	switch(num) {
		case 2:
			res = Down(character);
			break;
		case 4:
			res = Left(character);
			break;
		case 6:
			res = Right(character);
			break;
		case 8:
			res = Up(character);
			break;
	}
	return res;
}

// 敵をランダムに移動させると共に,プレーヤと敵が重なったかどうか(ゲーム終了)を判定する関数
int Enemy(CHARACTER player, CHARACTER enemys[]) {
	int rnum, res;
	int i;
	
	for( i=0; i<ENEMYS; i++ ) {
		do{
			rnum = 1 + rand()%4;							// 移動方向を指定する数値を乱数で決定 ( 1:下,2:左,3:右,4:上 )
			res = Move(rnum*2, &enemys[i]);		// 移動方向を示す数値を2倍することで値を2:下,4:左,6:右,8:上に変換
		}while( res == 0 );
		if( player.x == enemys[i].x && player.y == enemys[i].y ) {
			printf("敵に見つかりました... 残念...\n");
			return 1;
		}
	}
	return 0;
}
// 現在の状況を表示する関数
void ShowField(CHARACTER player, CHARACTER enemys[], int res) {
	int i, j, k;
	int flag_e;

	// 表示領域 ( 端末の内容 ) をクリア
	system("clear");
	if( res == 0 )	printf("\n移動できない方向が指定されました.\n");
	
	printf("%s", BOLD);
	
	for( j=0; j<20; j++ ) {
		for( i=0; i<20; i++ ) {
			flag_e = 0;
			for( k=0; k<ENEMYS; k++ ) {
				if( j == enemys[k].y && i == enemys[k].x 
					&& player.y-VISIBLE_AREA <= j && j <= player.y+VISIBLE_AREA 			// 敵が可視領域にいるかどうかのチェック
					&& player.x-VISIBLE_AREA <= i && i <= player.x+VISIBLE_AREA ) {		// 敵が可視領域にいるかどうかのチェック
					flag_e = 1;
					break;
				}
			}
			
			if( j == player.y && i == player.x ) {		// プレーヤを黄色で表示する
				printf("%s", YELLOW);
				printf("P");
				printf("%s", WHITE);
			} else if( flag_e == 1 ) {					// 敵を赤色で表示する
				printf("%s", RED);
				printf("E");
				printf("%s", WHITE);
			} else if (field[j][i] == 'G' ) {			// ゴールを緑色で表示する
				printf("%s", GREEN);
				printf("%c", field[j][i]);
				printf("%s", WHITE);
			} else if( field[j][i] != ' ' ) {			// 壁の背景色を灰色にする
				printf("%s", BACKGROUNDGRAY);
				printf("%c", field[j][i]);
				printf("%s", BACKGROUNDBLACK);
			} else {
				printf("%c", field[j][i]);
			}
		}
		printf("\n");
	}
	printf("%s", DEFAULT);
}

int main(void) {
	int num, i, res, end = 0;
	CHARACTER player = {1, 1};		// プレーヤーの位置(x座標,y座標)を保存する変数 ( 初期位置はx:1,  y:1 )
	CHARACTER enemys[ENEMYS];		// 敵の位置(x座標,y座標)を保存する配列
	CHARACTER goal;					// ゴールの位置(x座標,y座標)を保存する変数
	
	// 乱数の初期化 ( 毎回異なる乱数を発生するために必要 )
	srand(time(NULL));
	
	// 敵の位置をランダムに決定する
	for( i=0; i<ENEMYS; i++ ) {
		do{
			enemys[i].x = 1 + rand() % 19;		// 1〜18までの乱数を発生させる ( 0と19は壁)
			enemys[i].y = 1 + rand() % 19;		// 1〜18までの乱数を発生させる ( 0と19は壁 )
		}while( field[enemys[i].y][enemys[i].x] == '|' || field[enemys[i].y][enemys[i].x] == '-' || field[enemys[i].y][enemys[i].y] == '+' );
	}	
	
	// ゴールの位置をランダムに決定する
	do{
		goal.x = 10 + rand() % 9;				// 10〜18までの乱数を発生させる ( 19は壁)
		goal.y = 10 + rand() % 9;				// 10〜18までの乱数を発生させる ( 19は壁)
	}while( field[goal.y][goal.x] == '|' || field[goal.y][goal.x] == '-' || field[goal.y][goal.x] == '+' );
	
	field[goal.y][goal.x] = 'G';
	
	// 初期状態を表示
	ShowField(player, enemys, 1);
	
	// ゴールに到達するか敵と接触するまで繰り返す
	do{
		printf("移動する方向の数字を入力してください. (下:2, 左:4, 右:6, 上: 8)\n");
		scanf("%d", &num);
		
		// プレーヤを指定された方向へ移動させる
		res = Move(num, &player);
		
		// 敵をランダムに移動させ,敵に見つかったかどうかを調べる
		end = Enemy(player, enemys);
		
		// 敵に見つかった場合 → ゲーム終了
		if( end == 1 )	return 1;
			
		ShowField(player, enemys, res);
		
	}while( player.x != goal.x || player.y != goal.y );
	
	printf("ゴールしました!! おめでとう!!\n");

	return 0;
}

かずま

Re: 初質問/ゲームの移動用関数に苦戦しています

#2

投稿記事 by かずま » 3週間前

面白そうなので書いてみました。

コード:

#include <stdio.h>   // printf, scanf
#include <stdlib.h>  // srand, rand, system
#include <string.h>  // strchr
#include <time.h>    // time

#define ENEMYS  10 // 敵の数の指定

#define VISIBLE_AREA  20 // 可視領域 (範囲)

// 表示位置の移動
#define UP    "\x1b[A"
#define DOWN  "\x1b[B"
#define RIGHT "\x1b[C"
#define LEFT  "\x1b[D"

// 表示に使用する文字色
#define BLACK   "\x1b[30m"
#define RED     "\x1b[31m"
#define GREEN   "\x1b[32m"
#define YELLOW  "\x1b[33m"
#define BLUE    "\x1b[34m"
#define MAGENTA "\x1b[35m"
#define CYAN    "\x1b[36m"
#define WHITE   "\x1b[37m"

// 表示に使用する文字の背景色
#define BACKGROUNDGRAY  "\x1b[47m"
#define BACKGROUNDBLACK "\x1b[40m"

// 表示に使用する文字の太さ
#define BOLD    "\x1b[1m"
#define DEFAULT "\x1b[0m"

// キャラクタ用の構造体
typedef struct CHARACTER {
	int x;  // キャラクタのx座標→右に移動するほど増える
	int y;  // キャラクタのy座標→下に移動するほど増える
} CHARACTER;

char *field[20] = { // 迷路
	"+------------------+",
	"|                  |",
	"| +------  ------+ |",
	"| |              | |",
	"| | +-  ----  -+ | |",
	"|   |          | | |",
	"|-| | +--  --+ | | |",
	"|   | |        | | |",
	"| | | | +--+ | |   |",
	"| | | |    | | |-| |",
	"| |   | |    | | | |",
	"| | |-| +--+ |   |-|",
	"| | |        | | | |",
	"| | | +--  --+ | | |",
	"|-| |          |   |",
	"| | +-  ----  -+ | |",
	"| |              | |",
	"| +-------  -----+ |",
	"|                  |",
	"+------------------+"
};

int Wall(CHARACTER *object)  // 壁判定
{
	return strchr("|-+", field[object->y][object->x]) != NULL;
}

int Up(CHARACTER *object) // 上移動用関数
{
	if (object->y <= 1) return 0; 
	object->y--;
	if (Wall(object)) { object->y++; return 0; }
	printf(UP);
	return 1;
}

int Down(CHARACTER *object) // 下移動用関数
{
	if (object->y >= 18) return 0; 
	object->y++;
	if (Wall(object)) { object->y--; return 0; }
	printf(DOWN);
	return 1;
}

int Left(CHARACTER *object) // 左移動用関数
{
	if (object->x <= 1) return 0; 
	object->x--;
	printf(LEFT);
	if (Wall(object)) { object->x++; return 0; }
	return 1;
}

int Right(CHARACTER *object) // 右移動用関数
{
	if (object->x >= 18) return 0;
	object->x++;
	if (Wall(object)) { object->x--; return 0; }
	printf(RIGHT);
	return 1;
}

// ユーザに指定された方向へキャラクタを移動させる関数
int Move(int num, CHARACTER *character)
{
	int res;

	switch (num) {
	case 2: res = Down(character); break;
	case 4: res = Left(character); break;
	case 6: res = Right(character); break;
	case 8: res = Up(character); break;
	}
	return res;
}

// 敵をランダムに移動させると共に,プレーヤと敵が重なったかどうか(ゲーム終了)を判定する関数
int Enemy(CHARACTER player, CHARACTER enemys[])
{
	int rnum, res;

	for (int i = 0; i < ENEMYS; i++) {
		do {
			// 移動方向を指定する数値を乱数で決定 (1:下,2:左,3:右,4:上)
			rnum = 1 + rand() % 4;
			// 移動方向を示す数値を2倍することで値を 2:下,4:左,6:右,8:上に変換
			res = Move(rnum * 2, &enemys[i]);
		} while (res == 0);
		if (player.x == enemys[i].x && player.y == enemys[i].y) {
			printf("敵に見つかりました... 残念...\n");
			return 1;
		}
	}
	return 0;
}

// 現在の状況を表示する関数
void ShowField(CHARACTER player, CHARACTER enemys[], int res)
{
	int i, j, k;
	int flag_e;

	system("clear"); // 表示領域 (端末の内容) をクリア
	printf("%s", BOLD);

	for (j = 0; j < 20; j++) {
		for (i = 0; i < 20; i++) {
			flag_e = 0;
			for (k = 0; k < ENEMYS; k++) {
				if (j == enemys[k].y && i == enemys[k].x  //
						&& player.y - VISIBLE_AREA <= j   // 敵が可視領域に
						&& j <= player.y + VISIBLE_AREA   // いるかどうかの
						&& player.x - VISIBLE_AREA <= i   // チェック
						&& i <= player.x + VISIBLE_AREA) {
					flag_e = 1;
					break;
				}
			}

			if (j == player.y && i == player.x)  // プレーヤを黄色で表示する
				printf("%sP%s", YELLOW, WHITE);
			else if (flag_e == 1)  // 敵を赤色で表示する
				printf("%sE%s", RED, WHITE);
			else if (field[j][i] == 'G')  // ゴールを緑色で表示する
				printf("%s%c%s", GREEN, field[j][i], WHITE);
			else if (field[j][i] != ' ')  // 壁の背景色を灰色にする
				printf("%s%c%s", BACKGROUNDGRAY, field[j][i], BACKGROUNDBLACK);
			else
				printf("%c", field[j][i]);
		}
		printf("\n");
	}
	if (res == 0) printf("\n移動できない方向が指定されました.\n");
	printf("%s", DEFAULT);
}

int main(void)
{
	int num, i, res, end = 0;
	CHARACTER player = { 1, 1 };  // プレーヤーの位置(x座標,y座標)
	CHARACTER enemys[ENEMYS];  // 敵の位置(x座標,y座標)
	CHARACTER goal;            // ゴールの位置(x座標,y座標)

	srand(time(NULL)); // 乱数の初期化

	for (i = 0; i < ENEMYS; i++) { // 敵の位置をランダムに決定する
		do {
			enemys[i].x = 1 + rand() % 19;  // 1から18までの乱数を発生させる(0と19は壁)
			enemys[i].y = 1 + rand() % 19;  // 1から18までの乱数を発生させる(0と19は壁)
		} while (Wall(&enemys[i]));
	}
	do { // ゴールの位置をランダムに決定する
		goal.x = 10 + rand() % 9;  // 10から18までの乱数を発生させる(19は壁)
		goal.y = 10 + rand() % 9;  // 10から18までの乱数を発生させる(19は壁)
	} while (Wall(&goal));

	field[goal.y][goal.x] = 'G';
	ShowField(player, enemys, 1); // 初期状態を表示

	do { // ゴールに到達するか敵と接触するまで繰り返す
		printf("移動する方向の数字を入力してください. (下:2, 左:4, 右:6, 上: 8)\n");
		scanf("%d", &num);
		res = Move(num, &player); // プレーヤを指定された方向へ移動させる
		end = Enemy(player, enemys); // 敵をランダムに移動させ,敵に見つかったかどうかを調べる
		if (end == 1) return 1;  // 敵に見つかった場合 → ゲーム終了

		ShowField(player, enemys, res);
	} while (player.x != goal.x || player.y != goal.y);

	printf("ゴールしました!! おめでとう!!\n");
	return 0;
}
これを参考に斜めの移動も考えてみてください。

かずま

Re: 初質問/ゲームの移動用関数に苦戦しています

#3

投稿記事 by かずま » 3週間前

壁判定だけでよいので、if (object0>y <= 1) return 0; などの
範囲チェックは不要でした。

C言語初心者のがくせい

Re: 初質問/ゲームの移動用関数に苦戦しています

#4

投稿記事 by C言語初心者のがくせい » 3週間前

回答ありがとうございます。
実行はできたもののメッセージがたくさん表示されました、、
このままで大丈夫でしょうか?

コード:

return strchr("|-+", field[object->y][object->x]) != NULL;
         ^~~~~~
prog-C-15-1.c:64:9: warning: incompatible implicit declaration of built-in function ‘strchr’
prog-C-15-1.c:64:9: note: include ‘<string.h>’ or provide a declaration of ‘strchr’
prog-C-15-1.c: In function ‘Up’:
prog-C-15-1.c:72:11: warning: passing argument 1 of ‘printf’ from incompatible pointer type [-Wincompatible-pointer-types]
    printf(Up);
           ^~
In file included from prog-C-15-1.c:6:0:
/usr/include/stdio.h:318:12: note: expected ‘const char * restrict’ but argument is of type ‘int (*)(CHARACTER *) {aka int (*)(struct CHARACTER *)}’
 extern int printf (const char *__restrict __format, ...);
            ^~~~~~
prog-C-15-1.c:72:11: warning: format not a string literal and no format arguments [-Wformat-security]
    printf(Up);
           ^~
prog-C-15-1.c: In function ‘Down’:
prog-C-15-1.c:80:11: warning: passing argument 1 of ‘printf’ from incompatible pointer type [-Wincompatible-pointer-types]
    printf(Down);
           ^~~~
In file included from prog-C-15-1.c:6:0:
/usr/include/stdio.h:318:12: note: expected ‘const char * restrict’ but argument is of type ‘int (*)(CHARACTER *) {aka int (*)(struct CHARACTER *)}’
 extern int printf (const char *__restrict __format, ...);
            ^~~~~~
prog-C-15-1.c:80:11: warning: format not a string literal and no format arguments [-Wformat-security]
    printf(Down);
           ^~~~
prog-C-15-1.c: In function ‘Left’:
prog-C-15-1.c:88:11: warning: passing argument 1 of ‘printf’ from incompatible pointer type [-Wincompatible-pointer-types]
    printf(Left);
           ^~~~
In file included from prog-C-15-1.c:6:0:
/usr/include/stdio.h:318:12: note: expected ‘const char * restrict’ but argument is of type ‘int (*)(CHARACTER *) {aka int (*)(struct CHARACTER *)}’
 extern int printf (const char *__restrict __format, ...);
            ^~~~~~
prog-C-15-1.c:88:11: warning: format not a string literal and no format arguments [-Wformat-security]
    printf(Left);
           ^~~~
prog-C-15-1.c: In function ‘Right’:
prog-C-15-1.c:97:11: warning: passing argument 1 of ‘printf’ from incompatible pointer type [-Wincompatible-pointer-types]
    printf(Right);
           ^~~~~
In file included from prog-C-15-1.c:6:0:
/usr/include/stdio.h:318:12: note: expected ‘const char * restrict’ but argument is of type ‘int (*)(CHARACTER *) {aka int (*)(struct CHARACTER *)}’
 extern int printf (const char *__restrict __format, ...);
            ^~~~~~
prog-C-15-1.c:97:11: warning: format not a string literal and no format arguments [-Wformat-security]
    printf(Right);
           ^~~~~

かずま

Re: 初質問/ゲームの移動用関数に苦戦しています

#5

投稿記事 by かずま » 3週間前

いったい何をコンパイルしているんですか?

#2 のプログラムには、#include <string.h> がちゃんとありますし、
printf(UP); はあっても、printf(Up); なんてありません。
UP は define された文字列ですが、Up は関数でしょう。
警告が出て当然です。

そんな間違いがあって、とても実行できるとは思えません。

C言語初心者のがくせい

Re: 初質問/ゲームの移動用関数に苦戦しています

#6

投稿記事 by C言語初心者のがくせい » 3週間前

できました。defineの部分が抜けていました。
ありがとうございました。

返信

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