5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C言語で実装する「陣取りゲームプログラム」と「迷路生成・最短経路探索プログラム」

Last updated at Posted at 2021-07-26

はじめに

初めての投稿になります!
C言語で記述した
「陣取りゲーム」と「迷路生成・最短経路探索」
のソースコードを記載します!

陣取りゲーム

陣取りゲームのルールは
①8×8の盤面で先手☆と後手★が盤面を塗り合い、終了時自色のマスが多い方が勝利。
②自色のマスの数はそのままスコアとなるが、自駒と連結している(自色のマスを辿れば自駒にたどり着ける)マスのみカウントされ、自駒から孤立してる自色マスはカウントされない。
③ゲームの進め方は☆の移動→☆が色を塗る→★の移動→★が色を塗るというサイクルの繰り返し。
④移動は(+1,+2),(+1,-2),(+2,+1),(+2,-1), (-1,+2),(-1,-2),(-2,+1),(-2,-1)の8種類から選択する。
⑤色塗りは上下左右斜め8方向に塗れるマスまで全マス塗る。しかし相手のコマは塗れず、相手の色のマスを上書きして塗った場合はそれ以降のマスは塗られない。(→複雑ですが動かしてみると理解できると思います!)

②のルールがあるため自駒からたどり着けるマスのみを数えることになるが、この関数に再帰を用いています。
ソースコード上部のrowやcolumnの値を変えれば任意のマスで陣取りゲームができるので色々いじって遊んでみてください!

jintori.c
# include<stdio.h>
# include<stdlib.h>

# define row  8
# define column 8

typedef struct square{
	int type; /*そのマスの種類*/
	int flag; /*走査の際、そのマスは既に調べられているかどうかの判別に使用*/
} masu;


/*フィールドを表示する関数 (0:□ 1:☆ 2:○ 3:★ 4:●)*/
void Field(masu s[row][column]){
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < column; j++)
		{
			if (s[i][j].type == 0)
				printf("□");
			else if (s[i][j].type == 1)
				printf("☆");
			else if (s[i][j].type == 2)
				printf("○");
			else if (s[i][j].type == 3)
				printf("★");
			else printf("●");
		}

		printf("\n");
	}
	return;
}


/*☆が色を塗る関数*/
void WhitePaint(int i,int j, masu s[row][column]){


	for (int k = i+1; k < row; k++) /*下に塗る*/
	{
		if (s[k][j].type == 4) /*塗るマスが相手の塗ったマス*/
		{
			s[k][j].type = 2;
			break;
		}
		else if(s[k][j].type == 3) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][j].type = 2;
		}
	}

	for (int k = i-1; k >= 0; k--) /*上に塗る*/
	{
		if (s[k][j].type == 4) /*塗るマスが相手の塗ったマス*/
		{
			s[k][j].type = 2;
			break;
		}
		else if(s[k][j].type == 3) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][j].type = 2;
		}
	}

	for (int k = j+1; k < column; k++) /*右に塗る*/
	{
		if (s[i][k].type == 4) /*塗るマスが相手の塗ったマス*/
		{
			s[i][k].type = 2;
			break;
		}
		else if(s[i][k].type == 3) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[i][k].type = 2;
		}
	}

	for (int k = j-1; k >= 0; k--) /*左に塗る*/
	{
		if (s[i][k].type == 4) /*塗るマスが相手の塗ったマス*/
		{
			s[i][k].type = 2;
			break;
		}
		else if(s[i][k].type == 3) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[i][k].type = 2;
		}
	}	

	for (int k = i+1, l = j+1 ; k < row && l < column ; k++, l++) /*右下に塗る*/
	{
		if (s[k][l].type == 4) /*塗るマスが相手の塗ったマス*/
		{
			s[k][l].type = 2;
			break;
		}
		else if(s[k][l].type == 3) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][l].type = 2;
		}
	}

	for (int k = i-1, l = j-1 ; k >= 0 && l >=0 ; k--, l--) /*左上に塗る*/
	{
		if (s[k][l].type == 4) /*塗るマスが相手の塗ったマス*/
		{
			s[k][l].type = 2;
			break;
		}
		else if(s[k][l].type == 3) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][l].type = 2;
		}
	}

	for (int k = i-1, l = j+1 ; k >= 0 && l < column ; k--, l++) /*右上に塗る*/
	{
		if (s[k][l].type == 4) /*塗るマスが相手の塗ったマス*/
		{
			s[k][l].type = 2;
			break;
		}
		else if(s[k][l].type == 3) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][l].type = 2;
		}
	}

	for (int k = i+1, l = j-1 ; k < row && l >= 0 ; k++, l--) /*左下に塗る*/
	{
		if (s[k][l].type == 4) /*塗るマスが相手の塗ったマス*/
		{
			s[k][l].type = 2;
			break;
		}
		else if(s[k][l].type == 3) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][l].type = 2;
		}
	}
}


/*★が色を塗る関数*/
void BlackPaint(int i,int j, masu s[row][column]){


	for (int k = i+1; k < row; k++) /*下に塗る*/
	{
		if (s[k][j].type == 2) /*塗るマスが相手の塗ったマス*/
		{
			s[k][j].type = 4;
			break;
		}
		else if(s[k][j].type == 1) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][j].type = 4;
		}
	}

	for (int k = i-1; k >= 0; k--) /*上に塗る*/
	{
		if (s[k][j].type == 2) /*塗るマスが相手の塗ったマス*/
		{
			s[k][j].type = 4;
			break;
		}
		else if(s[k][j].type == 1) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][j].type = 4;
		}
	}

	for (int k = j+1; k < column; k++) /*右に塗る*/
	{
		if (s[i][k].type == 2) /*塗るマスが相手の塗ったマス*/
		{
			s[i][k].type = 4;
			break;
		}
		else if(s[i][k].type == 1) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[i][k].type = 4;
		}
	}

	for (int k = j-1; k >= 0; k--) /*左に塗る*/
	{
		if (s[i][k].type == 2) /*塗るマスが相手の塗ったマス*/
		{
			s[i][k].type = 4;
			break;
		}
		else if(s[i][k].type == 1) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[i][k].type = 4;
		}
	}	

	for (int k = i+1, l = j+1 ; k < row && l < column ; k++, l++) /*右下に塗る*/
	{
		if (s[k][l].type == 2) /*塗るマスが相手の塗ったマス*/
		{
			s[k][l].type = 4;
			break;
		}
		else if(s[k][l].type == 1) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][l].type = 4;
		}
	}

	for (int k = i-1, l = j-1 ; k >= 0 && l >=0 ; k--, l--) /*左上に塗る*/
	{
		if (s[k][l].type == 2) /*塗るマスが相手の塗ったマス*/
		{
			s[k][l].type = 4;
			break;
		}
		else if(s[k][l].type == 1) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][l].type = 4;
		}
	}

	for (int k = i-1, l = j+1 ; k >= 0 && l < column ; k--, l++) /*右上に塗る*/
	{
		if (s[k][l].type == 2) /*塗るマスが相手の塗ったマス*/
		{
			s[k][l].type = 4;
			break;
		}
		else if(s[k][l].type == 1) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][l].type = 4;
		}
	}

	for (int k = i+1, l = j-1 ; k < row && l >= 0 ; k++, l--) /*左下に塗る*/
	{
		if (s[k][l].type == 2) /*塗るマスが相手の塗ったマス*/
		{
			s[k][l].type = 4;
			break;
		}
		else if(s[k][l].type == 1) /*塗るマスが相手の駒のマス*/
		{
			break;
		}
		else /*それ以外のマス*/
		{
			s[k][l].type = 4;
		}
	}
}



/*コマ☆を動かす関数*/
void WhiteMove(masu s[row][column],int *x,int *y){

	int n;
	int flag = 0;

	while(1){

		printf("\n☆の動き方\n□8□1□\n7□□□2\n□□☆□□\n6□□□3\n□5□4□\n\n");
		Field(s);
		printf("先手☆:動かす場所を決めてください。\n");
		scanf("%d",&n);


		for (int i = 0; i < row; ++i)
		{
			for (int j = 0; j < column; ++j)
			{
				if(s[i][j].type == 1){ /*そのマスが☆だった場合*/

					if(n == 1){
						if(i > 1 && j < column-1){ /*そのマスが移動可能*/
							if(s[i-2][j+1].type != 3){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 2;
								s[i-2][j+1].type = 1;
								flag = 1;
								*x = i-2;
								*y = j+1;
								break;
							}
							else{
								printf("そのマスは★コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 2){
						if(i > 0 && j < column-2){ /*そのマスが移動可能*/
							if(s[i-1][j+2].type != 3){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 2;
								s[i-1][j+2].type = 1;
								flag = 1;
								*x = i-1;
								*y = j+2;
								break;
							}
							else{
								printf("そのマスは★コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 3){
						if(i < row-1 && j < column-2){ /*そのマスが移動可能*/
							if(s[i+1][j+2].type != 3){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 2;
								s[i+1][j+2].type = 1;
								flag = 1;
								*x = i+1;
								*y = j+2;
								break;
							}
							else{
								printf("そのマスは★コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 4){
						if(i < row-2 && j < column-1){ /*そのマスが移動可能*/
							if(s[i+2][j+1].type != 3){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 2;
								s[i+2][j+1].type = 1;
								flag = 1;
								*x = i+2;
								*y = j+1;
								break;
							}
							else{
								printf("そのマスは★コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 5){
						if(i < row-2 && j > 0){ /*そのマスが移動可能*/
							if(s[i+2][j-1].type != 3){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 2;
								s[i+2][j-1].type = 1;
								flag = 1;
								*x = i+2;
								*y = j-1;
								break;
							}
							else{
								printf("そのマスは★コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 6){
						if(i < row-1 && j > 1){ /*そのマスが移動可能*/
							if(s[i+1][j-2].type != 3){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 2;
								s[i+1][j-2].type = 1;
								flag = 1;
								*x = i+1;
								*y = j-2;
								break;
							}
							else{
								printf("そのマスは★コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 7){
						if(i > 0 && j > 1){ /*そのマスが移動可能*/
							if(s[i-1][j-2].type != 3){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 2;
								s[i-1][j-2].type = 1;
								flag = 1;
								*x = i-1;
								*y = j-2;
								break;
							}
							else{
								printf("そのマスは★コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 8){
						if(i > 1 && j > 0){ /*そのマスが移動可能*/
							if(s[i-2][j-1].type != 3){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 2;
								s[i-2][j-1].type = 1;
								flag = 1;
								*x = i-2;
								*y = j-1;
								break;
							}
							else{
								printf("そのマスは★コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else{
						printf("誤った入力です。\nもう一度選択しなおしてください。\n");
					}

				}

			}

			if(flag == 1) break;
		}

		if(flag == 1) break;
	}
}

/*コマ★を動かす関数*/
void BlackMove(masu s[row][column],int *x,int *y){

	int n;
	int flag = 0;

	while(1){


		printf("\n★の動き方\n□8□1□\n7□□□2\n□□★□□\n6□□□3\n□5□4□\n\n");
		Field(s);
		printf("後手★:動かす場所を決めてください。\n");
		scanf("%d",&n);


		for (int i = 0; i < row; ++i)
		{
			for (int j = 0; j < column; ++j)
			{
				if(s[i][j].type == 3){ /*そのマスが★だった場合*/

					if(n == 1){
						if(i > 1 && j < column-1){ /*そのマスが移動可能*/
							if(s[i-2][j+1].type != 1){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 4;
								s[i-2][j+1].type = 3;
								flag = 1;
								*x = i-2;
								*y = j+1;
								break;
							}
							else{
								printf("そのマスは☆コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 2){
						if(i > 0 && j < column-2){ /*そのマスが移動可能*/
							if(s[i-1][j+2].type != 1){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 4;
								s[i-1][j+2].type = 3;
								flag = 1;
								*x = i-1;
								*y = j+2;
								break;
							}
							else{
								printf("そのマスは☆コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 3){
						if(i < row-1 && j < column-2){ /*そのマスが移動可能*/
							if(s[i+1][j+2].type != 1){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 4;
								s[i+1][j+2].type = 3;
								flag = 1;
								*x = i+1;
								*y = j+2;
								break;
							}
							else{
								printf("そのマスは☆コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 4){
						if(i < row-2 && j < column-1){ /*そのマスが移動可能*/
							if(s[i+2][j+1].type != 1){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 4;
								s[i+2][j+1].type = 3;
								flag = 1;
								*x = i+2;
								*y = j+1;
								break;
							}
							else{
								printf("そのマスは☆コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 5){
						if(i < row-2 && j > 0){ /*そのマスが移動可能*/
							if(s[i+2][j-1].type != 1){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 4;
								s[i+2][j-1].type = 3;
								flag = 1;
								*x = i+2;
								*y = j-1;
								break;
							}
							else{
								printf("そのマスは☆コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 6){
						if(i < row-1 && j > 1){ /*そのマスが移動可能*/
							if(s[i+1][j-2].type != 1){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 4;
								s[i+1][j-2].type = 3;
								flag = 1;
								*x = i+1;
								*y = j-2;
								break;
							}
							else{
								printf("そのマスは☆コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 7){
						if(i > 0 && j > 1){ /*そのマスが移動可能*/
							if(s[i-1][j-2].type != 1){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 4;
								s[i-1][j-2].type = 3;
								flag = 1;
								*x = i-1;
								*y = j-2;
								break;
							}
							else{
								printf("そのマスは☆コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else if(n == 8){
						if(i > 1 && j > 0){ /*そのマスが移動可能*/
							if(s[i-2][j-1].type != 1){ /*そのマスが相手の駒じゃない*/
								s[i][j].type = 4;
								s[i-2][j-1].type = 3;
								flag = 1;
								*x = i-2;
								*y = j-1;
								break;
							}
							else{
								printf("そのマスは☆コマです。\nもう一度選択しなおしてください。\n");
							}
						}
						else{
							printf("そのマスには動けません。\nもう一度選択しなおしてください。\n");
						}
					}

					else{
						printf("誤った入力です。\nもう一度選択しなおしてください。\n");
					}

				}	

			}

			if(flag == 1) break;
		}

		if(flag == 1) break;
	}
}


void WhiteCount(int i,int j,masu s[row][column],int *n) /*白のマスを数える関数*/
{		
    s[i][j].flag = 1; 
    (*n)++;

    if(i+1<row && s[i+1][j].type==2 && s[i+1][j].flag==0) WhiteCount(i+1,j,s,n);
    if(j+1<column && s[i][j+1].type==2 && s[i][j+1].flag==0) WhiteCount(i,j+1,s,n);
    if(i-1>=0 && s[i-1][j].type==2 && s[i-1][j].flag==0) WhiteCount(i-1,j,s,n);
    if(j-1>=0 && s[i][j-1].type==2 && s[i][j-1].flag==0) WhiteCount(i,j-1,s,n);
}

void BlackCount(int i,int j,masu s[row][column],int *n) /*黒のマスを数える関数*/
{
    s[i][j].flag = 1; 
    (*n)++;

    if(i+1<row && s[i+1][j].type==4 && s[i+1][j].flag==0) BlackCount(i+1,j,s,n);
    if(j+1<column && s[i][j+1].type==4 && s[i][j+1].flag==0) BlackCount(i,j+1,s,n);
    if(i-1>=0 && s[i-1][j].type==4 && s[i-1][j].flag==0) BlackCount(i-1,j,s,n);
    if(j-1>=0 && s[i][j-1].type==4 && s[i][j-1].flag==0) BlackCount(i,j-1,s,n);
}


void FlagZero(masu s[row][column]){ /*フラッグを初期化する関数、Count関数を実行する前に必要になる。*/
	for (int i = 0; i < row; ++i)
		{
			for (int j = 0; j < column; ++j)
			{
				s[i][j].flag = 0;
			}
		}
}


int main(void)
{
	int WhitePoint,BlackPoint;
	int WhiteX,WhiteY,BlackX,BlackY;

	masu s[row][column];

	for (int i = 0; i < row; ++i) /*初期化*/
		{
			for (int j = 0; j < column; ++j)
			{
				s[i][j].type = 0;
			}
		}

	s[0][0].type = 1; /*初期化*/
	s[row-1][column-1].type = 3;

	WhiteX = 0;
	WhiteY = 0;
	BlackX = row-1;
	BlackY = column-1;

	for (int i = 0; i < 5; ++i)
	{
		printf("\nターン%d\n",i+1);

		WhitePoint = 0;
		BlackPoint = 0;
		WhiteMove(s,&WhiteX,&WhiteY); /*☆コマを動かす*/
		WhitePaint(WhiteX,WhiteY,s); /*☆が色を塗る*/
		printf("\n\n現在の得点\n");
		Field(s);
		FlagZero(s);
		WhiteCount(WhiteX,WhiteY,s,&WhitePoint); /*☆の得点を数える*/
		FlagZero(s);
		BlackCount(BlackX,BlackY,s,&BlackPoint); /*★の得点を数える*/
		printf("☆:%d  %d:★\n",WhitePoint,BlackPoint);


		WhitePoint = 0;
		BlackPoint = 0;
		BlackMove(s,&BlackX,&BlackY); /*★コマを動かす*/
		BlackPaint(BlackX,BlackY,s); /*★が色を塗る*/
		printf("\n\n現在の得点\n");
		Field(s);
		FlagZero(s);
		WhiteCount(WhiteX,WhiteY,s,&WhitePoint); /*☆の得点を数える*/
		FlagZero(s);
		BlackCount(BlackX,BlackY,s,&BlackPoint); /*★の得点を数える*/
		printf("☆:%d  %d:★\n",WhitePoint,BlackPoint);
	}

	printf("\nそこまで!\n");
	if(WhitePoint > BlackPoint) printf("☆の勝ち!\n");
	else if(WhitePoint < BlackPoint) printf("★の勝ち!\n");
	else printf("引き分け!\n");

	return 0;
}

迷路生成・最短経路探索

上記の陣取りゲームの再帰アルゴリズムを応用した最短経路探索プログラムを記載します!
プログラムを実行すると自動で迷路を生成し、自分でゴールの座標を設定することができます。
こちらで実装した最短経路探索は厳密には「最短経路の探索」は行っていません。
どういうことかと言うと、このアルゴリズムでは深さ優先探索でゴールにたどり着くまでとにかく経路を探すというものになっています。そのためゴールまでの経路が複数ある場合、発見された経路が最短なのかの保証はありません。
しかしここで生成される迷路はゴールまでの経路が1通りしかないものとなっているので「最短経路探索」と言っています。
こちらもコードのmax_xやmax_yの値を変えることで任意の大きさの迷路を作成できます。色々な値に変えて遊んでみてください〜
それではコードを示したいと思います!

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


//どちらも5以上の奇数にすること。
# define max_x 35 //盤面の横幅
# define max_y 35 //盤面の縦幅


//マスの情報を取り扱う構造体
typedef struct square{
	int type; //マスの種類
	int flag; //そのマスは既に調べられているかどうかの判別に使用
} masu;


//迷路を作成する関数
void make_maze(masu field[max_y][max_x]){
  int x,y;
  int r; //乱数の値
  srand((unsigned)time(NULL)); //乱数の仕組みを初期化

  //通路(0)の生成
  for(y=0; y<max_y; y=y+1) //フィールドの縦幅の分だけループする
  {
    for(x=0; x<max_x; x=x+1) //フィールドの横幅の分だけループする
    {
      field[y][x].type = 0;
    }
  }

  //上下の外壁(1)の生成
  for(x=0; x<max_x; x=x+1) //フィールドの横幅の分だけループする
  {
    field[0][x].type = 1;
    field[max_y-1][x].type = 1;
  }

  //左右の外壁(1)の生成
  for(y=0; y<max_y; y=y+1) //フィールドの縦幅の分だけループする
  {
    field[y][0].type = 1;
    field[y][max_x-1].type = 1;
  }

  //棒倒し法を使った壁(1)の生成(1行めのみ)
  y = 2; //1行め
  for(x=2; x<max_x-1; x=x+2) //xの要素番号2から要素番号max_x-1まで、1マス飛ばしで棒倒し
  {
    r = (rand()%12) + 1; //乱数生成(r = 1から12のランダムな値)
    field[y][x].type = 1; //中心から……
    if(r>=1 && r<=3) //rが1から3のとき
    {
      if(field[y-1][x].type==0) //上に棒(壁)がなければ
      {
        field[y-1][x].type = 1; //上に棒を倒す
      }
      else if(field[y-1][x].type==1) //上に棒(壁)があれば
      {
        x = x - 2; //棒を倒さずに、乱数生成をやり直す
      }
    }
    if(r>=4 && r<=6) //rが4から6のとき
    {
      if(field[y+1][x].type==0) //下に棒(壁)がなければ
      {
        field[y+1][x].type = 1; //下に棒を倒す
      }
      else if(field[y+1][x].type==1) //下に棒(壁)があれば
      {
        x = x - 2; //棒を倒さずに、乱数生成をやり直す
      }
    }
    if(r>=7 && r<=9) //rが7から9のとき
    {
      if(field[y][x-1].type==0) //左に棒(壁)がなければ
      {
        field[y][x-1].type = 1; //左に棒を倒す
      }
      else if(field[y][x-1].type==1) //左に棒(壁)があれば
      {
        x = x - 2; //棒を倒さずに、乱数生成をやり直す
      }
    }
    if(r>=10 && r<=12) //rが10から12のとき
    {
      if(field[y][x+1].type==0) //右に棒(壁)がなければ
      {
        field[y][x+1].type = 1; //右に棒を倒す
      }
      else if(field[y][x+1].type==1) //右に棒(壁)があれば
      {
        x = x - 2; //棒を倒さずに、乱数生成をやり直す
      }
    }
  }
	
  //棒倒し法を使った壁(1)の生成(2行め以降)
  for(y=4; y<max_y-1; y=y+2) //yの要素番号4から要素番号max_y-1まで、1マス飛ばしで棒倒し
  {
    for(x=2; x<max_x-1; x=x+2) //xの要素番号2から要素番号max_x-1まで、1マス飛ばしで棒倒し
    {
      r = (rand()%12) + 1; //乱数生成(r = 1から12のランダムな値)
      field[y][x].type = 1; //中心から……
      if(r>=1 && r<=4) //rが1から4のとき
      {
        if(field[y+1][x].type==0) //下に棒(壁)がなければ
        {
          field[y+1][x].type = 1; //下に棒を倒す
        }
        else if(field[y+1][x].type==1) //下に棒(壁)があれば
        {
          x = x - 2; //棒を倒さずに、乱数生成をやり直す
        }
      }
      if(r>=5 && r<=8) //rが5から8のとき
      {
        if(field[y][x-1].type==0) //左に棒(壁)がなければ
        {
          field[y][x-1].type = 1; //左に棒を倒す
        }
        else if(field[y][x-1].type==1) //左に棒(壁)があれば
        {
          x = x - 2; //棒を倒さずに、乱数生成をやり直す
        }
      }
      if(r>=9 && r<=12) //rが9から12のとき
      {
        if(field[y][x+1].type==0) //右に棒(壁)がなければ
        {
          field[y][x+1].type = 1; //右に棒を倒す
        }
        else if(field[y][x+1].type==1) //右に棒(壁)があれば
        {
          x = x - 2; //棒を倒さずに、乱数生成をやり直す
        }
      }
    }
  }
	
  field[0][1].type = 0; //スタート地点の壁を撤去する
}


//迷路の表示を行う関数
void hyouji(masu field[max_y][max_x])
{
	int x,y;

	//列番号表示
	//0~9は1文字のため全角、10以降は半角にしないと表示がずれる
	for (x=0; x < max_x ; x++)
	{
		if(x==0)
		{
			printf("0");
		}
		else if(x==1)
		{
			printf("1");
		}
		else if(x==2)
		{
			printf("2");
		}
		else if(x==3)
		{
			printf("3");
		}
		else if(x==4)
		{
			printf("4");
		}
		else if(x==5)
		{
			printf("5");
		}
		else if(x==6)
		{
			printf("6");
		}
		else if(x==7)
		{
			printf("7");
		}
		else if(x==8)
		{
			printf("8");
		}
		else if(x==9)
		{
			printf("9");
		}
		else
		{
			printf("%d",x);
		}
	}
	printf("\n");

	for(y=0; y<max_y; y++) //フィールドの縦幅の分だけループする
	{
		for(x=0; x<max_x; x++) //フィールドの横幅の分だけループする
		{
			if(field[y][x].type==0) //通路なら
			{
				printf("%2s","  "); //空白で表す
			}
			else if(field[y][x].type==1) //壁なら
			{
				printf("%2s","■"); //四角形で表す
			}
			else if(field[y][x].type==2)//ゴールなら
			{
				printf("%2s","〇"); //〇で表す
			}
			else if(field[y][x].type==3)//経路なら
			{
				printf("%2s","×"); //×で表す
			}
		}
		printf("%d",y); //行番号表示
		printf("\n"); //行の終了時点で改行する
	}
}


//指定された座標までの最短経路を返す関数
int saitan(int y,int x,masu field[max_y][max_x],int *n,int *m){

	(*n)++;

	if(field[y][x].type == 2) //ゴールだったら1を返して関数終了
	{
		return 1;
	}

	if( x >= 0 && x < max_x && y >= 0 && y < max_y) //迷路上のマスである場合
	{
		field[y][x].flag = 1; //このマスは調べたというflag、これを設定することで何度も同じマスを調べることを防ぐ

		if(field[y][x+1].flag == 0 && field[y][x+1].type != 1 && saitan(y,x+1,field,n,m) == 1) //右のマスが調べられてなく、壁でなく、正解の道である場合
		{
			field[y][x].type = 3; //このマスのtypeを3にして
			(*m)++;
			return 1; //1を返して関数終了
		}

		if(field[y+1][x].flag == 0 && field[y+1][x].type != 1 && saitan(y+1,x,field,n,m) == 1) //下のマスが調べられてなく、壁でなく、正解の道である場合
		{
			field[y][x].type = 3; //このマスのtypeを3にして
			(*m)++;
			return 1; //1を返して関数終了
		}

		if(field[y][x-1].flag == 0 && field[y][x-1].type != 1 && saitan(y,x-1,field,n,m) == 1) //左のマスが調べられてなく、壁でなく、正解の道である場合
		{
			field[y][x].type = 3; //このマスのtypeを3にして
			(*m)++;
			return 1; //1を返して関数終了
		}

		if(field[y-1][x].flag == 0 && field[y-1][x].type != 1 && saitan(y-1,x,field,n,m) == 1) //上のマスが調べられてなく、壁でなく、正解の道である場合
		{
			field[y][x].type = 3; //このマスのtypeを3にして
			(*m)++;
			return 1; //1を返して関数終了
		}

	}

	return 0; //調べる必要がなかったら0を返して関数終了
}


//フラッグを初期化する関数
void flag_zero(masu field[max_y][max_x])
{
	for (int y = 0; y < max_y; y++)
    {
		for (int x = 0; x < max_x; x++)
		{
			field[y][x].flag = 0;
		}
	}
}



//main関数
int main(void)
{
 	masu field[max_y][max_x]; //フィールド(0が通路、1が壁、2が現在位置、3が経路)
	int GoalX; //目標地点のx座標
	int GoalY; //目標地点のy座標

	int count_saitan=0;
	int count_hosu=0;

	make_maze(field); //迷路の作成
	field[0][1].type = 2; //初期位置の設定
	hyouji(field); //迷路の表示

  	//目標地点を設定するループ
  	while(1){
	 	printf("〇が現在の位置です。目標地点の座標を入力してください。\n");
	 	printf("x:");
	 	scanf("%d",&GoalX);
	 	printf("y:");
	 	scanf("%d",&GoalY);

		if(GoalY>0 && GoalY<max_y-1 && GoalX>0 && GoalX<max_x-1 && field[GoalY][GoalX].type == 0)
		{
			field[GoalY][GoalX].type = 2;
			field[0][1].type = 0;
			break; //目標が決まったらループを抜ける
		}
		else
		{
			printf("その地点へは行けません。\n");
			continue; //目標にできない座標だった場合もう1度ループ
		}
	}

	flag_zero(field); //すべてのマスのflagを0に初期化
	saitan(0,1,field,&count_saitan,&count_hosu); //初期位置(1,0)を指定して最短経路探索開始
	printf("最短経路は以下の通りです。\n\n");
	hyouji(field); //最短経路が描かれた迷路を表示して終了

	printf("関数が呼び出された回数は%d回でした。\n",count_saitan);
	printf("目標地点までにかかる歩数は%d歩でした。\n",count_hosu);

	return(0);
}

おわりに

以上なります!
初投稿で拙い部分もあったかと思いますがご容赦ください<(_ _)>
ここまでお読みいただきありがとうございました!

5
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?