C语言学习入门第四节————数组(下)

系列文章目录

C语言学习入门第四节————数组(下)

数组

  1. 一维数组的创建和初始化
  2. 一维数组的使用
  3. 一维数组在内存中的存储
  4. 二维数组的创建和初始化
  5. 二维数组的使用
  6. 二维数组在内存中的存储
  7. 数组越界
  8. 数组作为函数参数
  9. 数组的应用实例1:三子棋
  10. 数组的应用实例2:扫雷游戏



数组的应用实例1:三子棋

在学习完c语言后的函数,指针与数组后。我想用这些知识来编写我的第一个c语言小游戏——三子棋。虽然涉及的只是基础语法,但这也可以为我之后的代码编写打下良好基础。下面是总体实现思路以及代码框架等。

1.总体思路

  1. 要想实现三子棋游戏,就要先有让玩家选择是否进入游戏的菜单.
  2. 初始化棋盘,并显示出棋盘与棋子。
  3. 玩家通过输入要落子的坐标实现落子。(玩家的棋子用‘ * ’表示。)
  4. 电脑进行下棋。(电脑的棋子用‘ # ’表示。)
  5. 在每次玩家和电脑下完棋后,判断有没有赢家。若棋盘被下满,则为平局。

2.代码实现步骤

(1).头文件

代码如下(示例):

#include<stdio.h>
#include<stdlib.h>//rand()函数生成随机数
#include<time.h>//time()函数获取当前时间用来生成随机数
#define ROW  3//行
#define COL  3//列
void clean_board(char board[ROW][COL],int row,int col);//初始化棋盘 

void printf_board(char board[ROW][COL],int row,int col);//打印棋盘

void game();
 
void PlayerMove(char board[ROW][COL],int row,int col); //玩家下棋 

void ComputerMove(char board[ROW][COL],int row,int col);//电脑下棋
 
int IsFull(char board[ROW][COL],int row,int col);//判断棋盘是否已被下满(平局)

char IsWin(char board[ROW][COL],int row,int col);//判断输赢

void menu();//生成游戏菜单

(2).创建游戏菜单

代码如下(示例):

void menu()
{
	printf("*****************************\n");
	printf("*********1. play ************\n");
	printf("*********0. exit ************\n");
	printf("*****************************\n");
}

(3).主函数框架

当玩家输入1时,开始游戏。当玩家输入0时,退出游戏。当玩家输入错误时提醒玩家输入错误,并重新输入。(用do
while循环来保证游戏的正常进行。)

代码如下(示例):

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu(); 
		printf("请选择:>");
		scanf("%d",&input); 
		switch(input)
		{
			case 1:
				game();
				break;
			case 0:
				printf("退出游戏!");
				break;
			default:
			  	 printf("输入错误!请重新选择。"); 
		}
	}while(input);
	return 0;
} 

:srand((unsigned int)time(NULL));
此函数用于生成随机数,让电脑能够随机落子。

(4).game()函数框架

先创立一个二维数组,并用该数组来初始化棋盘。将数组的首地址,数组的行、列传给各函数形参。棋盘初始化并打印后,玩家和电脑分别进行下棋同时判断是否有三个一样的棋子连成一条线。并判断是玩家胜利还是电脑胜利。当棋盘被下满时则为平局。

代码如下(示例):

void game()
{
	char board[ROW][COL] ={0};
	clean_board(board,ROW,COL);
	//初始化棋盘 
	printf_board(board,ROW,COL); 
		//打印棋盘 
	char ret = 0;
	while(1)
	{
			//玩家下棋 
		PlayerMove(board,ROW,COL); 
	    printf_board(board,ROW,COL);
	        //判断输赢 
		ret = IsWin(board,ROW,COL);
		if(ret != 'C')  break;	 
	    	//电脑下棋 
	    ComputerMove(board,ROW,COL); 
		printf_board(board,ROW,COL);
		    //判断输赢
		ret = IsWin(board,ROW,COL);
      	if(ret != 'C')	break; 
	    	
	}
	if(ret == '*')
     	printf("玩家赢\n");
	else if(ret == '#')
	    printf("电脑赢\n");
	else 
	    printf("平局\n"); 
	
}

(5).game()函数的具体实现

1)初始化棋盘函数

用两个for循环嵌套让二维数组中元素都为空格,来实现棋盘为空的情况。

void clean_board(char board[ROW][COL],int row,int col)
{
	int i = 0;
	for(i = 0;i < row ;i++)
	{
		int j = 0;
		for(j  = 0;j< col;j++)
		{
			board[i][j] = ' ';
		} 
	}
}
2)打印棋盘函数
void printf_board(char board[ROW][COL],int row,int col)
{
	int i = 0;
	for(i = 0;i < row;i++)
	{
		int j = 0;
		//打印数据 
		for(j = 0;j  < col;j++)
		{
			printf(" %c ",board[i][j]);
			if(j < col - 1)
			printf("|");
		}
		printf("\n"); 
			//打印分割线
		if(i < row -1)
		{
			
	      for(j = 0;j < col ;j++)
		  {
			printf("---");
			if(j < col-1 ) printf("|");
	      }
	      printf("\n");
     	}
	}

棋盘打印效果:
在这里插入图片描述

3)玩家下棋

在落子时判断输入数字是否合法,坐标内是否已有棋子。

void PlayerMove(char board[ROW][COL],int row,int col)
{
	int x = 0,y = 0;
	printf("现在是你下棋\n");
	while(1)
	{
		printf("输入落子的坐标,中间用空格隔开>");
		scanf("%d %d",&x,&y);
		if(x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if(board[x-1][y-1] == ' ')//当输入坐标为空格时,可以落子
			{
				board[x-1][y-1] = '*';
				break;
			} 
			else 
			{
				printf("此处已有棋子,不能落子,请重新输入坐标>");
				
			}
		}
		else//非法
		{
			printf("输入坐标错误,请重新输入\n"); 
		} 
	}
}
4)电脑下棋

通过生成随机数实现电脑随机落子。

void ComputerMove(char board[ROW][COL],int row,int col) 
{
	int x = 0,y = 0;//0-row-1
	printf("现在是电脑下棋:>\n");

	while(1)
	{
		x = rand() % row;
	    y = rand() % col;
     	if(board[x][y] == ' ')
     	{
		board[x][y] = '#';
		break;
	    }
    }
	
}
5)判断输赢

循环遍历board数组,当行、列,对角线上有三个相同的棋子时将该棋子返回game()函数并根据这个棋子判断是玩家胜利还是电脑胜利。(当返回值为’* ’ 时为玩家赢,当返回值为‘#’时为电脑赢。)当棋盘被下满时,返回‘Q’。(平局)当没有三个棋子连成线且棋盘没被下完时,返回‘C’。

//玩家赢  返回'*'
//电脑赢  返回'#'
//平局    返回'Q'
//继续    返回'C' 
char IsWin(char board[ROW][COL],int row,int col)
{
	//赢
	 
	 //行
	 int i = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];
		}
	}
	 //列
	   for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
		}
	}
	 //对角线
	 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
		return board[1][1];
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
		return board[1][1];

	//平局 
	 if(IsFull(board,row,col) == 1)
	{
	    return 'Q';  
	} 
	//继续 
	  	return 'C';
	
}
补充:判断棋盘是否下满

循环遍历board数组,当里面有空格时,返回0(继续),当循环结束后(棋盘中空格时)返回1;

int IsFull(char board[ROW][COL],int row,int col)
{
	int i = 0;
	for(i = 0;i < row;i++)
	{
		int j = 0;
		for(j = 0;j < col;j++)
		{
			if(board[i][j] == ' ')
			return 0;
		}
	}
	return 1;
}

3.完整代码

#pragma once
//游戏相关的自定义函数 声明 写到game.h中
 
#include <stdio.h> 
#include <stdlib.h> //rand函数需要的头文件
#include <time.h> //time函数需要的头文件
//直接把头文件包含在自定义头文件中,当别的文件包含本头文件时,
//这个头文件里的头文件也会被包含
 
//定义宏常量:行数ROW  列数COL 
//,之后想修改,直接修改头文件里的这两个宏常量就可以
#define ROW 3 
#define COL 3
 
// 1.  InitBoard(); 用于初始化数组,将空格全部初始化为空格
void InitBoard(char board[ROW][COL], int row, int col);
 
// 2.  DisplayBoard():打印数组(棋盘)
void DisplayBoard(char board[ROW][COL], int row, int col);
 
// 3. 玩家下棋:
void PlayerMove(char board[ROW][COL], int row, int col);
 
// 4. 电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
 
// 5. 判断输赢(返回对应的符号):
//玩家赢 -- ‘*’
//电脑赢 -- ‘#’
//平局 -- ‘Q’
//继续 -- ‘C’
char IsWin(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1
//游戏相关的自定义函数 代码 写到game.c中
#include "game1.h"
 
 
// 1.  InitBoard(); 用于初始化数组,将空格全部初始化为空格
void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++) // 遍历行
	{
		int j = 0;
		for (j = 0; j < col; j++) // 遍历列
		{
			board[i][j] = ' '; // 将空格全部初始化为空格
		}
	}
}
 
// 2.  DisplayBoard():打印数组(棋盘)
 
//版本1:都是空格,什么都看不见
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
//	int i = 0;
//	for ( i = 0; i < row; i++) // 遍历行
//	{
//		int j = 0;
//		for (j = 0; j < col; j++) // 遍历列
//		{
//			printf("%c", board[i][j]);
//		}
//		// 打印完一行后换行
//		printf("\n");
//	}
//}
 
//版本2:只能打印对应的行,不能打印对应的列(列被”写死“了)
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
//	int i = 0;
//	for (i = 0; i < row; i++) // 遍历行
//	{
//		//1. 打印数据
//		printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//
//		//2. 打印分割线
//		if (i < row - 1) //只有中间才需要打印分割线,最后一行不打印分割线
//		{
//			printf("---|---|---\n");
//		}
//			
//	}
//}
 
 
//版本3: 实现多行多列,边写边想边实现
void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++) // 遍历行
	{
		//1. 打印数据
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]); // 先打印数据
			      
			if (j < col-1) // 最后一行不打印竖杠
			{
				printf("|"); // 再打印竖杠
			}
	
		}
		// 打印完一行后换行
		printf("\n");
 
		//2. 打印分割线
		if (i < row - 1)//只有中间才需要打印分割线,最后一行不打印分割线
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1) // 最后一行不打印竖杠
				{
					printf("|"); // 再打印竖杠
				}
			}
			printf("\n");
		}
	}
}
 
// 3. 玩家下棋:
void PlayerMove(char board[ROW][COL], int row, int col)
{
	// 让玩家通过坐标选择下棋位置
	int x = 0;
	int y = 0;
	printf("玩家下棋>: \n");
	
	while (1) //输入成功了再break跳出循环
	{
		printf("请输入下棋的坐标,中间使用空格>:");
		scanf("%d %d", &x, &y);
 
		//判断输入是否正确(二维数组行和列都是从0开始的,但玩家不一定知道)
		if (x >= 1 && x <= row && y >= 1 && y <= col) //坐标合法
		{
			//判断是否可以落子
			if (board[x-1][y-1] == ' ') //可以落子
				//board[x-1][y-1]:输入是1行1列,其实是0行0列
			{
				//落子了就把空格换成 * 号
				board[x - 1][y - 1] = '*';
				break;
			}
			else //不能落子
			{
				printf("坐标被占用,不能落子,重新输入坐标\n");
			}
		}
		else //坐标非法
		{
			printf("坐标非法,重新输入\n"); 
		}
	}
}
 
// 4. 电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0; // 让x随机生成 0 -- (row-1) 的值
	int y = 0; // 让y随机生成 0 -- (col-1) 的值
 
	printf("电脑下棋:>\n");
 
	//数组的下标已经约定了,不会越界,但还有可能被占用
	while (1)
	{
		x = rand() % row; //结果为 0 -- (row-1) 的值
		y = rand() % col; //结果为 0 -- (col-1) 的值
 
		if (board[x][y] == ' ') //如果随机坐标为空格,则落子
		{
			board[x][y] = '#';
			break; //落子成功则跳出循环
		}
		//若不是空格,则继续循环出一个随机坐标,直至落子成功
	}
}
 
// 5. 判断输赢(返回对应的符号):
//玩家赢 -- ‘*’
//电脑赢 -- ‘#’
//平局 -- ‘Q’
//继续 -- ‘C’
 
// 5(补充):判断棋盘是否已满
int IsFull(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++) //遍历行
	{
		int j = 0;
		for (j = 0; j < col; j++) //遍历列
		{
			if (board[i][j] == ' ')
			{
				return 0; 
				//整个数组中有找到空格,则返回0
			}
		}
	}
	//整个数组中没有找到空格(棋盘已满),则返回1
	return 1;
}
 
char IsWin(char board[ROW][COL], int row, int col)
{
	//赢 (判断三行三列和对角线)
		// 判断 三行 是否有连成一线的
	int i = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
			//同行第一个元素等于第二个元素,第二个元素等于第三个元素,判断其中一个元素是否为空格
		{ 
			return board[i][0]; 
			//因为玩家赢时,同行上都是 ‘*’,所以直接返回行上的其中一个元素就行
		}
 
	}
 
		// 判断 三列 是否有连成一线的
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
			//因为电脑赢时,同行上都是 ‘#’,所以直接返回行上的其中一个元素就行
		}
 
	}
 
		// 判断 对角线 是否有连成一线的
			//其中一条对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
			//另一条对角线
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}
 
	//平局 (上面四个return都没执行的话,则执行下面的代码)
		//自定义函数IsFull()函数用于判断棋盘是否已满
	if (IsFull(board, row, col) == 1) //如果返回值为1,说明棋盘已满,平局
	{
		return 'Q';
	}
 
	//继续 (没有赢,也没平局,继续下棋)
	return 'C';
 
}
#define _CRT_SECURE_NO_WARNINGS 1
 
//1. 游戏不退出,继续玩下一把(循环)
//2. 应用多文件的形式写代码
 
#include "game1.h" //包含自己定义的头文件
 
 
void menu()
{
	printf("***********************************\n");
	printf("**********    1.play    ***********\n");
	printf("**********    0.exit    ***********\n");
	printf("***********************************\n");
}
 
void game()
{
/*
1. 游戏在走的过程中要进行数据的存储,三子棋可以使用3*3的二维数组
	即  char board[3][3];
2. 没下棋之前数组中存放空格,下棋后将空格替换成字符
*/
	char board[ROW][COL] = { 0 };
 
	InitBoard(board, ROW, COL); //传递 数组名,行数,列数
	// 用于初始化数组,将空格全部初始化为空格
	// 将游戏相关的自定义函数代码写到game.c中
	
	// 打印棋盘
	DisplayBoard(board, ROW, COL);
 
//下棋:
	char ret = 0; //接受判断输赢的符号
//让玩家一直下:
	while (1)
	{
		//玩家下棋:
		PlayerMove(board, ROW, COL);
		//落子后再打印棋盘看棋盘情况
		DisplayBoard(board, ROW, COL);
		//判断输赢(三子相连)
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
 
		//电脑下棋:
		ComputerMove(board, ROW, COL);
		//落子后再打印棋盘看棋盘情况
		DisplayBoard(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
 
	}
 
	//写在while循环外面的话,只用写一次
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局");
	}
 
}
 
int main()
{
	int input = 0;
 
	//rand函数调用之前得调用srand,
	//整个程序只用调一次,所以放在主函数中
	srand((unsigned int)time(NULL));
 
//1. 游戏不退出,继续玩下一把(循环)	
	do //不管三七二十一,先打印菜单
	{
		menu(); //打印游戏菜单
		printf("请选择:>");
		scanf("%d", &input); //1 0 其它
 
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择:\n");
			break;
		}
	} while (input); 
	//当input为0时停止循环退出游戏
	//当input非0时继续循环
	
	return 0;
}

4. 总结

三子棋游戏到这里就结束了,总体上是个适合新手练习的简单小项目。如果本文对你起到了帮助,你可以点个赞,谢谢支持。欢迎大家到评论区讨论这个代码还有哪些可以优化,或者如何让这个小游戏更加丰富。

数组的应用实例2:扫雷游戏

`
扫雷是一款经典的电脑小游戏,它的游戏规则是在一个9×9(初级)、16×16(中级)、16×30(高级)或自定义大小的方块矩阵中随机布置一定量的地雷(初级为10个,中级为40个,高级为99个),再由玩家在一定时间内依照翻开方块的提示逐个翻开不是雷方块,以找出所有地雷为最终游戏目标,如果踩到雷游戏就结束。
在这里插入图片描述


1.总体思路

1.扫雷游戏要2两个二位数组,一个存放雷的信息,一个存放布置好的雷的信息。
2.将’ 1’ ,'0’放进存放雷的信息的数组中.(用’1’表示雷)。
3.在排雷时输入要排查的坐标,如果不是雷则显示周围8个坐标里雷的个数直到10个雷全被找出。游戏结束。如要排查的坐标是雷,游戏结束。

2.代码实现步骤

1.头文件

代码如下(示例):

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

#define EASY_COUNT 10

#define ROW 9
#define COL 9

#define ROWS  ROW+2
#define COLS  COL+2

void  memu();//打印菜单 

void game();//游戏主体

void InitBoard(char board[ROWS][COLS],int rows,int cols,char set);//初始化游戏棋盘

void PrintfBoard(char board[ROWS][COLS],int row,int col);//打印游戏棋盘

void PutMine(char board[ROWS][COLS],int row,int col); //随机布置雷

void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//玩家排雷

int GetMineCount(char mine[ROWS][COLS],int x,int y);//统计输入要排查的坐标周围8个坐标内雷的个数并返回

2.创建游戏菜单

代码如下(示例):

void menu()
{
	printf("*****************************\n");
	printf("*********1. play ************\n");
	printf("*********0. exit ************\n");
	printf("*****************************\n");
}

3.主函数框架

int main()
{
   
	int input = 0;
    srand((unsigned int)time(NULL));	
	do
	{
	    menu();
	    printf("请选择:>");
    	scanf("%d",&input);
        switch(input)
       {
    	 case 1:
    	    game();
        	break;
         case 0:
            printf("退出游戏!"); 
    	    break;
    	 default:
    	 printf("选择错误,重新选择!");
    	
	   }
    }while(input);
    return 0;  
}

运用switch语句,输入1进入游戏,输入0退出游戏。通过do while语句先执行,后判断来实现可游玩多次。同时用input控制循环,当选择0时正好不符合while的条件退出循环。

4.初始化游戏棋盘和创建数组

1)创建数组
  1. 创建mine数组来存放地雷的信息,当玩家输入要排查的坐标时调用mine数组来判断。创建show数组,将棋盘和排查雷的信息显示给玩家。
  2. 当玩家输入的要查找的棋子坐标在边缘时,排查该坐标周围雷个数会越界访问,因此要将mine和show两个数组同时增加两行两列,由99变成1111**(用宏定义ROW
    COL为 9,ROWS和COLS为ROW+2,便于棋盘大小的更改和游戏难度的提升(暂未实现))
2)初始化

有mine和show两个数组,因此同事初始化。将show数组初始化为’*‘,mine数组初始化为’0’.

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}
//初始化棋盘
	//1.mine数组初始化为'0'
	//2.show数组初始化为'*' 
	InitBoard(mine,ROWS,COLS,'0');
	InitBoard(show,ROWS,COLS,'*'); 
3)打印棋盘信息
void PrintfBoard(char board[ROWS][COLS],int row,int col)
{
	int  i = 0;
	printf("--------扫雷游戏-------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%C ", board[i][j]);
		}
		printf("\n");
	}
}
4)设置地雷

通过生成随机数来设置地雷,存放地雷信息的mine数组之前被全被初始化为’0’,现在让电脑随机更改10个mine数组的值为’1’来表示放置地雷。(count表示的是地雷的个数,每次成功生成一个雷时,count就减1,直到count减到0时,跳出循环。雷布置完毕。

void PutMine(char board[ROWS][COLS],int row,int col)
{
	//布置10个雷
	//生成随机的坐标,布置雷 
	int count = EASY_COUNT;  
	while(count)
	{
	   int x = 0,y = 0;
	       x = rand() % row + 1;
           y = rand() % col + 1;
		   if(board[x][y] == '0')
		   {
		   	board[x][y] = '1';
		   	count--;
		   }
    }	
}
5)排查雷

1.首先定义全局变量win,每查找一个坐标win加1,直到win =行数*列数-雷的数量时,玩家排雷成功,并打印出雷的信息。
2.宏定义雷的数量为10,方便后续地雷数量的更改。
3.玩家输入要查找的坐标时,判断在mine函数中,该坐标值是否为’1’。若为1则玩家排雷失败,游戏结束、当该坐标值为’0’时,统计该坐标周围中雷的个数并赋值给show函数对应坐标中。

void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col)
{
int x = 0;
	int y = 0;
	int win = 0;
	while (win <row*col- EASY_COUNT)
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				PrintfBoard(mine, ROW, COL);
				break;
			}
			else
			{
				//该位置不是雷,就统计这个坐标周围有几个雷
				int count=GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				PrintfBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
	PrintfBoard(mine, ROW, COL);
	}
}


6)统计要查找的坐标周围8个坐标中雷的个数
int GetMineCount(char mine[ROWS][COLS],int x,int y)
{
	return (mine[x-1][y]+mine[x-1][y-1]+mine[x][y - 1]+mine[x+1][y-1]+mine[x+1][y]+mine[x+1][y+1]+mine[x][y+1]+mine[x-1][y+1] - 8 * '0');
}

3.完整代码

#pragma once
 
//该文件存放 游戏函数声明 的代码
 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
 
//游玩时显示的数组大小
#define ROW 9
#define COL 9
 
//实际数组大小
#define ROWS ROW+2
#define COLS COL+2
 
//简单版本的雷个数
#define EASY_COUNT 10
 
//1. InitBoard() -- 初始化棋盘 函数声明
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
 
//2. DisplayBoard() -- 打印棋盘
//传过来的数组是 11*11 的数组,但(访问)显示的只是其中的 9*9 
void DisplayBoard(char board[ROWS][COLS], int row, int col);
 
//3. SetMine() -- 布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
 
//4. FindMine() -- 排查雷(在mine数组中找信息,信息放到show数组中,操作的也是9*9)
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1
 
//该文件存放 游戏实现 的代码
 
#include "game2.h"
 
//1. InitBoard() -- 初始化棋盘 函数实现
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	//遍历行:
	for (i = 0; i < rows; i++)
	{
		//遍历列:
		int j = 0;
		for ( j = 0; j < cols; j++)
		{
			board[i][j] = set;
			//直接把棋盘初始化成传过来的 set
		}
	}
}
 
//2. DisplayBoard() -- 打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
//行和列都是从0开始的,要打印 9*9 ,只需要从第1行和列开始打印就好
	int i = 0;
	printf("---------扫雷游戏--------\n");
	for (i = 0; i <= col; i++) //打印列序号
	{
		printf("%d ", i);
	}
 
	printf("\n"); //换行,防止上面和下面的循环在同一行
 
	for (i = 1; i <= row; i++) //从第一行开始
	{
		printf("%d ", i); //打印行序号
		int j = 0;
		for ( j = 1; j <= col; j++) //从第一列开始
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}
 
//3. SetMine() -- 布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
	//布置10个雷
	//生成随机的坐标,布置雷
	int count = EASY_COUNT; //布置的雷的数量
	while (count) //只要还有雷(非0),就继续布置
	{
		 //雷在行列中都是布置在 1-9 
		//用rand()函数生成随机的x和y坐标
		int x = rand() % row + 1; //取余后(row=9)是 0-8 ,再+1后是 1-9
		int y = rand() % col + 1;
 
		if (board[x][y] == '0') //当前位置无雷才能布置
		{
			board[x][y] = '1'; //布雷
			count--; //布雷成功后,布雷数减1
		}
 
		//直到count = 0;跳出循环
	}
 
}
 
//3.5 --- GetMineCount()函数:统计mine数组坐标为x y的位置上雷的个数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] +
		mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0');
	//把xy坐标周围8个坐标的字符 0(无雷) 或 1(有雷) 加起来,
	//再 - 8 * '0' ,把字符 0 或 1 转化为 数字(整型)0 或 1
}
 
//4. FindMine() -- 排查雷(在mine数组中找信息,信息放到show数组中,操作的也是9*9)
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) 
{
	int x = 0;
	int y = 0;
 
	int win = 0; //统计找出的不是雷的位置
 
	while (win < row * col - EASY_COUNT)
		//找到非雷位置 小于 总位置数 减 雷数,说明还有雷,继续排雷
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
			//输入的坐标正确:1-9
		{
			if (mine[x][y] == '1') //踩到雷了
			{
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(mine, ROW, COL); //结束后查看游戏情况
				break; //这轮游戏结束
			}
			else //没踩到雷的话,统计周围雷的个数 
			{
				int count = GetMineCount(mine, x, y); //把周围雷个数传给count
				//GetMineCount():用于统计周围雷的个数
				//统计mine数组中该坐标周围有几个雷,所以要把mine传过去
 
				//雷的个数传到show数组相同x y坐标上
				show[x][y] = count + '0'; 
				//show是字符数组,count是数字,+‘0’后转化为字符
				//假设count = 3,加上0的ACSII值 48 后,即 51
				//ASCII码值51 对应的就是 字符3(ASCII码值为51)
 
				DisplayBoard(show, ROW, COL); //打印查看排雷情况
			
				win++; //找到不是雷的位置就++
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
	//被炸死 或者 排完雷后 到这位置
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(mine, ROW, COL); //查看棋盘
	}
}
#define _CRT_SECURE_NO_WARNINGS 1
 
//实现扫雷游戏代码
//该文件为 测试游戏 的代码
 
// 设计要点:
//1. 扫雷游戏要存储布置好的雷的信息,需要一个二维数组
 
//2. 给两个二维数组: 一个存放雷的信息 ; 另一个存放布置好的雷的信息
 
//3. 为了防止在统计坐标周围的雷的额个数的时候越界,我们让给数组设计为 11 * 11;
 
//4. 数组是 11 * 11,并且是字符数组
 
#include "game.h"
 
void menu()
{
	printf("***********************************\n");
	printf("**********    1.play    ***********\n"); 
	printf("**********    0.exit    ***********\n");
	printf("***********************************\n");
}
 
void game()
//在自定义game()函数中实现扫雷游戏的执行
{
	char mine[ROWS][COLS]; //存放布置好的雷
	char show[ROWS][COLS]; //存放排查出的雷的信息
 
	//1. 初始化棋盘
	//(1). mine数组最开始全是‘0’;
	//(2). show数组最开始全是‘#’;
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	// 第四个参数为想要初始化成的 符号
 
	//2. 打印棋盘(玩的时候只显示 9*9 ,所以打印 9*9 就可以了)
	//DisplayBoard(mine, ROW, COL); 
	DisplayBoard(show, ROW, COL); //实际显示的棋盘
 
	//3. 布置雷(布置在 9*9 中)
	SetMine(mine, ROW, COL); //雷是布置在mine数组上的
	//DisplayBoard(mine, ROW, COL);
 
	//4. 排查雷(在mine数组中找信息,信息放到show数组中,操作的也是9*9)
	FindMine(mine, show, ROW, COL);
	 
	  
}
 
int main()
{
	int input = 0;
	
	//使用rand前要设置srand。设置随机数起点
	//用time()函数返回时间戳
	//返回类型为 无符号整型
	srand((unsigned int)time(NULL));
	
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
 
		switch (input)
		{
		case 1:
			game(); 
			//在自定义game()函数中实现扫雷游戏的执行
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
 
	} while (input); 
	//如果选择了0退出游戏,则刚好判断为0退出循环
	//非0则继续循环
	return 0;
}

4.总结

以上就是C语言实现简单的扫雷游戏,本文仅仅简单实现了扫雷的基本功能,而改变难度难度,排雷展开等还为未实现。但是比较适合新手练习。如果本文对你起到了帮助,你可以点个赞,谢谢支持。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值