C言語ゲーム - シンプルなマインスイーパ

序文

この記事では主に、C 言語学習の初期段階にある総合的な小規模ゲーム、つまりマインスイーパの簡易版を紹介します。
筆者はこのゲームを学ぶことで、初級段階のC言語の知識の定着と復習が比較的しっかりできると感じています!参考にしていただけます。
作成者は、ゲームを 3 つのファイル (実装用に game.h、game.c、test.c) にカプセル化します。game.h には、
必要なヘッダー ファイル、定義された配列長のマクロ、およびゲーム プロセス関数を実装するための関数宣言が含まれています。

1. ゲーム構成

いくつかの関数を使用して、ゲーム機能の各ステップを実現できます。
このように分割します。
1. ゲームメニュー
2. ゲームテスト
3. ボードを配置し、ボードを初期化します
4. 必要に応じて地雷の数を初期化します
5. ボードを印刷します
6. プレイヤーが地雷除去を開始します
7. ゲームをプレイします各機能別 ゲーム機能
8、game.hのヘッダファイル表示
9、終了したゲーム表示


次に、各機能の具体的な実装

1. メニュー機能

コードは以下のように表示されます:

`void menu()
{
    
    
	printf("*****************************************\n");
	printf("**************   1、play!   *************\n");
	printf("**************   0、exit!   *************\n");
	printf("*****************************************\n");
}`
菜单就用printf函数打印出对应选项就可以实现

2. ゲームのテスト

コードは次のとおりです(例)。

int main()
{
    
    

	srand((unsigned int)time(NULL));//调用生成随机数

	int input = 0;

	do
	{
    
    
		menu();
		printf("请输入你的选择>\n");
		scanf("%d",&input);
		switch (input)
		{
    
    
		case 1:
			game();
			break;
		case 0:
			printf("结束游戏!\n");
			break;
		default :
			printf("输入有误,重新输入!\n");

		}
	} while (input);
	return 0;
}

メニュー バーによると、いくつかのオプションがあります。選択して実装するには switch ステートメントを使用します。これをループに入れると、各ゲームの後に確実に選択を続けることができます。srand((unsigned int)time(NULL));
callこの関数は、乱数を生成するときに、その乱数が毎回異なることを保証できます。


3. チェス盤を配置し、チェス盤を初期化する

チェス盤を配置する際には様々なチェス盤を選択することができますが、ここでは筆者は9+9のチェス盤を選択しています。
チェッカーボードを渡したい任意の文字に初期化したいと考えています。
作成者はチェッカーボードが '
' で初期化されていることを示しているため、チェッカーボードの 2 次元配列は文字タイプとして定義されます。
コードは次のとおりです。

void InitBoard(char Mine[Rows][Cols], int rows, int cols,char ch)
{
    
    //字符ch是我们想要将棋盘格初始化为什么样子,就传入什么字符
	int i = 0, j = 0;
	for (i = 0; i < rows; i++)
	{
    
    
		for (j = 0; j < cols; j++)
		{
    
    
			Mine[i][j] = ch;
		}
	}
}

配列の長さは、game.h ヘッダー ファイルで定義された定数マクロによって表されます。これは、将来のゲームの保守と更新に非常に便利で、マクロが定義されている場所を変更するだけで済むため、作業負荷が軽減されます。 。


4. ニーズに応じて地雷の数を初期化します。

マインスイーパー ゲームでは地雷の各列の後に周囲 8 つの位置にある地雷の数の合計が表示されるため、ボードを定義するときに 2 つを定義する必要があります。1 つは地雷の配置に使用され、もう 1 つは状況の表示に使用されます。各地雷をクリアすると盤面の が表示され、現在位置を中心とした 8 つの位置の地雷の数を判断する際には、現在位置の周囲 8 つの要素を訪問する必要があるため、チェス盤の境界線の位置が表示されます。配列添字にアクセスすると範囲外になるため、9 9 のチェス盤を11 11 として定義する必要があり、上下に追加のグリッド行があり、左右に追加のグリッド列が存在します。これらの位置に地雷が配置されないように初期化するだけで、各 9*9 チェス盤の各位置を訪問します。位置の周囲に 8 つの位置がある場合、配列の添え字は範囲外に表示されず、影響もありません。周囲の地雷の数に関する当社の判断
コード表示:

void ArrBoard(char Mine[Rows][Cols], int rows, int cols)
{
    
    
	int count = Easy_Count;
	while (count)
	{
    
    
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (Mine[x][y] != '1')
		{
    
    
			Mine[x][y] = '1';
			count--;
		}
	}
}

srand((unsigned int)time(NULL)) を指定して rand 関数を呼び出します。関数呼び出しは 1 から 9 までの乱数を生成します。雷を表すには '1' を使用します。


5. チェス盤を印刷する

チェス盤を印刷するときは、必要な 9*9 の行と列を印刷するだけでよいため、9 として印刷するマクロを渡すだけで済みます。コードは次のとおりです

void DisBoard(char Mine[Rows][Cols], int rows, int cols)
{
    
    
	printf("---------扫雷---------\n");
	int i = 0, j = 0;
	for (i = 0; i <= rows; i++)
	{
    
    
		printf("%d ", i);//把列的序号也打印出来
	}
	printf("\n");
	for (i = 1; i <=rows; i++)
	{
    
    
		printf("%d ", i);//每行打印前先把行号打印了
		for (j = 1; j <=cols; j++)
		{
    
    
			printf("%c ", Mine[i][j]);
		}
		printf("\n");
	}
	printf("---------扫雷---------\n");
}

印刷時に各位置の座標を決定しやすくするために、配列内のチェス盤の最初の行の配列添え字が 1 になるように、各行と列のラベルを印刷できます。最初の列は : 1 になり、プレイヤーが見つけやすくなります。


6. プレイヤーは地雷除去を開始します

コード表示:

int NumThunder(char Mine[Rows][Cols],int x,int y)
{
    
    //我们可以将判断一个位置周围八个位置的雷数总和的代码单独封装成一个函数
	return Mine[x - 1][y] + Mine[x][y - 1] + Mine[x][y + 1] + Mine[x - 1][y - 1] + Mine[x - 1][y + 1] + Mine[x + 1][y] + Mine[x + 1][y - 1] + Mine[x + 1][y + 1] - 8 * 48;
	//字符'0'的Acall值是48,所以这里-8*48是进行字符和整型的转化
}


void RemMine(char Mine[Rows][Cols], char Dis[Rows][Cols], int rows, int cols)
{
    
    
	int win = 0;
	while (win<rows*cols- Easy_Count)//循环确保排雷结束后游戏才结束
	{
    
    
		int x = 0, y = 0;
		printf("请输入你想要排雷的坐标>\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= rows && y >= 1 && y <= cols)
		{
    
    
			if (Mine[x][y] == '1')//踩到雷,游戏直接结束
			{
    
    
				printf("踩到地雷了,结束失败!\n");
				DisBoard(Mine, Row, Col);//失败后展示雷的分布
				break;
			}
			else 
			{
    
    
				//不是雷,则计算坐标x,y周围有几个雷
				int res = NumThunder(Mine, x, y) + 48;
				Dis[x][y] = res;
				DisBoard(Dis, Row, Col);//展示本次排雷后的棋盘以供继续排雷
				win++;//每排雷一次,排雷的次数加1
			}
		}
		else//输入坐标必须在1-9范围内,否则重新输入
		{
    
    
			printf("输入坐标有误,重新输入!\n");
		}
	}
	if (win == rows * cols - Easy_Count)//排雷次数与非雷数量相等且一直没有踩到雷时游戏胜利
	{
    
    
		printf("恭喜你,排雷成功!\n");
		DisBoard(Mine, Row, Col);//成功后展示雷的分布
	}
}


7. 各機能に合わせてゲームをプレイするゲーム機能

ゲーム関数を使用して、ゲーム実装プロセスの関数を特定の順序で組み合わせて、ゲームのプロセス全体を完了します

void game()
{
    
    
	char MineBoard[Rows][Cols] = {
    
     0 };//布置雷盘
	char ShowBoard[Rows][Cols] = {
    
     0 };//展示的棋盘
	InitBoard(MineBoard, Rows, Cols,'0');//初始化时将多的那两行两列也算上,因为后面统计周围雷数量时要用
	InitBoard(ShowBoard, Rows, Cols, '*');
	//DisBoard(MineBoard, Row, Col);//打印时就只穿想要打印的数量,顺便就从下标1开始打印了,因为0下标的元素刚好不用展示出来
    ArrBoard(MineBoard, Row, Col);//随机放置地雷
	//DisBoard(MineBoard, Row, Col);
	DisBoard(ShowBoard, Row, Col);
	//DisBoard(MineBoard, Row, Col);
	RemMine(MineBoard,ShowBoard, Row, Col);
}

8. game.h のヘッダー ファイルは次のようになります。

以下に、game.h ヘッダー ファイルで定義されている定数マクロのヘッダー ファイル コード表示と、使用されるライブラリ関数を示します

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

# define Row 9
# define Col 9
# define Rows Row+2
# define Cols Col+2
#define Easy_Count 10//设置的雷数


//初始化棋盘
void InitBoard(char Mine[Rows][Cols], int rows, int cols,char ch);

//打印棋盘
void DisBoard(char Mine[Rows][Cols], int rows, int cols);

//布雷
void ArrBoard(char Mine[Rows][Cols], int rows, int cols);

//排雷
void RemMine(char Mine[Rows][Cols], char Dis[Rows][Cols], int rows, int cols);

9. 完成したゲームの表示

選ぶ
1を選択してゲームを開始します
ここに画像の説明を挿入
採掘したい座標を選択し、地雷除去を開始します 各地雷除去が成功した後、最新のボードを表示し続けて地雷除去を続けます 地雷を踏むとゲームは失敗し
ここに画像の説明を挿入
、地雷がプレイヤーに表示されます。

要約する

このマインスイーパー ゲームについての私の理解が皆様のお役に立てば幸いです。最適化できる部分は遠慮なく修正してください。ご視聴ありがとうございます。今後も私のプログラミング学習プロセスを共有していきます。

おすすめ

転載: blog.csdn.net/m0_71214261/article/details/131959914