C语言—实现扫雷游戏(注释详解)

前言

一、游戏规则介绍

扫雷是一个十分经典的游戏,一张棋盘中有很多个不确定是雷还是安全区域的格子,当点击之后若没有雷则会在该区域显示周围八个格子雷的数目,若有雷则游戏结束。今天我就跟大家分享一下如何用c语言实现初阶版扫雷。

二、基本思路流程介绍

1.创建一个用户交互菜单
2.创建一个Show_Mines棋盘用来埋雷并初始化
3.创建一个Show_Table 棋盘用来和用户交互并初始化
4.玩家选择想要扫描的坐标
5.判定游戏是否结束
6.若没有踩雷则在刚扫描的区域上显示周围八个区域的地雷数目并继续游戏
7.继续扫雷
8.判定游戏是否结束

9.若全部扫描完非雷区域则游戏结束

效果展示
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

三、代码实现

1.用户交互菜单(Menu函数)

Menu(){
    
    
	printf("########################\n");
	printf("# 1. Play       0.Exit #\n");
	printf("########################\n");
}



2. Game函数

void Game()
{
    
    
	srand((unsigned long)time(NULL)); //生成随机数种子

	char show_board[ROW][COL];   
	char mines_board[ROW][COL];

	memset(show_board, WHAT, sizeof(show_board));//生成并且初始化用户显示棋盘
	memset(mines_board, '0', sizeof(mines_board));//生成并且初始化扫雷棋盘

	SetMines(mines_board, ROW, COL);//放雷

	int count = (ROW - 2)*(COL - 2) - NUM;    //若扫完这些次 不触雷则胜利

	while (count){
    
    
		system("cls");
		ShowBoard(show_board, ROW, COL);
		printf("请选择你要扫描的区域坐标 ");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		if (x < 1 || x > ROW-2 || y < 1 || y > COL-2){
    
     //非法性输入判断
			printf("输入错误!\n");
			continue;
		}
		if (show_board[x][y] != WHAT){
    
               
			printf("此处已经被扫过了,请从新输出\n");
			continue;
		}
		if (mines_board[x][y] == '1'){
    
    
			system("cls");
			ShowBoard(mines_board, ROW, COL);
			printf("踩雷了!游戏结束!\n");
			break;
		}
		
		show_board[x][y] = CountMines(mines_board, x, y);
		count--;
	}

}
1.memset函数直接定义show_board函数并且初始化二维数组为全WHAT宏定义的*。
2.先向用户展示用户展示棋盘,用户输入一个坐标进行非法性判断。
3.把用户输入的坐标拿给放置雷的棋盘中,若该区域有雷则游戏结束,反之则继续
4.游戏胜利条件为扫描完所有非雷区域



3.放雷函数(SetMines函数)

void SetMines(char board[][COL], int row, int col){
    
     //放雷函数
	int count = NUM;
	while (count){
    
    
		int x = rand() % (row - 2) + 1;
		int y = rand() % (col - 2) + 1;
		if (board[x][y] == '0'){
    
    
			board[x][y] = '1';
			count--;
		}
	}
}

使用随机数种子生成1到 棋盘大小长宽-2的随机数,这些随机数组成的坐标放雷,循环次数就是雷的数目。因为随机数可能生成一样的,所以要进行一次非法性判断,当棋盘这个位置没有雷的情况下才能往里面放雷。


4.扫雷展示面板(ShowBoard函数和ShowLine函数)

void ShowBoard(char board[][COL], int row, int col){
    
    //扫雷展示面板
	printf("     ");
	for (int i = 1; i <= (col - 2); i++){
    
      //打印表头数字
		printf("%d   ", i);
	}
	printf("\n");
	ShowLine(col);//显示行线
	for (int i = 1; i <= (row - 2); i++){
    
    
		printf("%-3d|", i);
		for (int j = 1; j <= (col - 2); j++){
    
    
			printf(" %c |", board[i][j]);	
		}
		printf("\n");
		ShowLine(col);
	}
}


void ShowLine(int col){
    
      //显示横着的虚线,作为行间隔

	for (int i = 0; i <= (col - 2); i++){
    
    
		printf("----");
	}
	printf("\n");
}



5.统计周围雷的个数(CountMines函数)

CountMines(char board[][COL], int x, int y){
    
     //统计周围雷的个数
	return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + \
		board[x][y + 1] + board[x + 1][y + 1] + board[x + 1][y] + \
		board[x + 1][y - 1] + board[x][y - 1] - 7 * '0';//本来减八个零,但是整形转字符加一个‘0’
}

由于数组中存放的是字符’0’,周围是8个数字,所以-8*'0’才能返回雷数的int值,为了把数字也能打印出来,所以+‘0’,否则打印的是数字作为的ASCLL码的值,最终的结果为-7*‘0’.


6.mine函数

int main()
{
    
    
	int quit = 0;
	int select = 0;
	while (!quit){
    
    
		Menu();
		printf("请输入 ");
		scanf("%d", &select);
		switch (select){
    
    
		case 1:
			Game();
			break;
		case 0:
			quit = 1;
			break;
		default:
			printf("输入错误,请重试!\n");
			break;
		}
	}

	printf("byebye!\n");

	system("pause");
	return 0;
}



四、总代码

#ifndef __Test_H__
#define __Test_H__

#include<stdio.h>
#include<Windows.h>
#include <stdlib.h>
#include <time.h>
#define	WHAT '*'
#define NUM  20
#define COL  10
#define ROW  10
void Game();
#pragma warning(disable:4996)
#endif       //以上都是头文件

int main()
{
    
    
	int quit = 0;
	int select = 0;
	while (!quit){
    
    
		Menu();
		printf("请输入 ");
		scanf("%d", &select);
		switch (select){
    
    
		case 1:
			Game();
			break;
		case 0:
			quit = 1;
			break;
		default:
			printf("输入错误,请重试!\n");
			break;
		}
	}

	printf("byebye!\n");

	system("pause");
	return 0;
}


void Game()
{
    
    
	srand((unsigned long)time(NULL)); //生成随机数种子

	char show_board[ROW][COL];   
	char mines_board[ROW][COL];

	memset(show_board, WHAT, sizeof(show_board));
	memset(mines_board, '0', sizeof(mines_board));

	SetMines(mines_board, ROW, COL);

	int count = (ROW - 2)*(COL - 2) - NUM;    //若扫完这些次 不触雷则胜利

	while (count){
    
    
		system("cls");
		ShowBoard(show_board, ROW, COL);
		printf("请选择你要扫描的区域坐标 ");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		if (x < 1 || x > ROW-2 || y < 1 || y > COL-2){
    
     //非法性输入判断
			printf("输入错误!\n");
			continue;
		}
		if (show_board[x][y] != WHAT){
    
               
			printf("此处已经被扫过了,请从新输出\n");
			continue;
		}
		if (mines_board[x][y] == '1'){
    
    
			system("cls");
			ShowBoard(mines_board, ROW, COL);
			printf("踩雷了!游戏结束!\n");
			break;
		}
		
		show_board[x][y] = CountMines(mines_board, x, y);
		count--;
	}
}


CountMines(char board[][COL], int x, int y){
    
     //统计周围雷的个数
	return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + \
		board[x][y + 1] + board[x + 1][y + 1] + board[x + 1][y] + \
		board[x + 1][y - 1] + board[x][y - 1] - 7 * '0';//本来减八个零,但是整形转字符加一个‘0’
}

void ShowBoard(char board[][COL], int row, int col){
    
    //扫雷展示面板
	printf("     ");
	for (int i = 1; i <= (col - 2); i++){
    
    
		printf("%d   ", i);
	}
	printf("\n");
	ShowLine(col);//显示行线
	for (int i = 1; i <= (row - 2); i++){
    
    
		printf("%-3d|", i);
		for (int j = 1; j <= (col - 2); j++){
    
    
			printf(" %c |", board[i][j]);	
		}
		printf("\n");
		ShowLine(col);
	}
}

oid SetMines(char board[][COL], int row, int col){
    
     //放雷函数
	int count = NUM;
	while (count){
    
    
		int x = rand() % (row - 2) + 1;
		int y = rand() % (col - 2) + 1;
		if (board[x][y] == '0'){
    
    
			board[x][y] = '1';
			count--;
		}
	}
}
void ShowLine(int col){
    
    

	for (int i = 0; i <= (col - 2); i++){
    
    
		printf("----");
	}
	printf("\n");
}

Menu(){
    
       //用户交互函数
	printf("########################\n");
	printf("# 1. Play       0.Exit #\n");
	printf("########################\n");
}

Guess you like

Origin blog.csdn.net/weixin_50302770/article/details/117574675