C语言小项目(2)——扫雷(基础版)
作者:互联网
C语言小项目(2)——扫雷(基础版)
前言
扫雷游戏是C语言初学者都需要练习的一个小项目,本文所实现的扫雷为最基础的版本(即一次只能扫一格),实际的扫雷游戏会有一种功能:在玩家点击格子的时候会向外展开,直到即将遇到雷为止。本文目前暂无实现这一功能。
代码详解
一、主函数
int main()
{
int i = 0;
srand((unsigned int)time(NULL));
do
{
menu();//打印菜单
scanf("%d", &i);
switch (i)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (i);
return 0;
}
1、srand((unsigned int)time(NULL))
为随机数生成器,后续布置雷的时候需要利用到rand()函数。
2、do-while循环
用于玩家多次游玩,直到玩家选择游戏结束,则终止循环。
menu()函数为菜单函数,用于打印简易菜单供玩家选择。
void menu()
{
printf("*************************\n");
printf("****** 1、开始游戏 ******\n");
printf("****** 0、结束游戏 ******\n");
printf("*************************\n");
}
运用switch-case函数,若玩家输入"1",则开始游戏;若玩家输入"0",则游戏结束,同时循环中止;若玩家输入其他数字,则会提示玩家并让玩家重新输入,直到输入的数字为"0"或者"1"为止。
二、游戏实现函数
本扫雷游戏的实现依靠两个二维数组:mine数组用于系统随机布置雷,show数组展现给玩家,供玩家进行排雷。当除了雷以外的格子都被玩家选中之后,玩家获得胜利。
void game()
{
//初始化
char mine[ROWS][COLS] = { 0 };//存放布置雷的信息
char show[ROWS][COLS] = { 0 };//存放玩家操作的信息
//初始化布置雷界面
Init_board(mine, ROWS, COLS, '0');
//初始化玩家操作界面
Init_board(show, ROWS, COLS, '*');
//随机生成雷
Mine_set(mine, ROW, COL);
//打印扫雷界面
Display_board(show, ROW, COL);
//排雷
Mine_sweep(mine, show, ROW, COL);
}
1、char mine[ROWS][COLS] = { 0 },char show[ROWS][COLS] = { 0 }
用于创建并初始化二维数组,作为扫雷的界面
本项目采用9*9的格子,为了便于日后的修改,此处采用了define ROW和COL的方式。
除了ROW和COL之外,额外定义了ROWS和COLS这两个变量名。玩家在扫雷的时候,若没有选到雷,被选中的格子会显示周围雷的个数,但边界处的格子在计算时会有一部分的格子在边界外,如果不加以处理的话不利于之后的计算。因此,本项目选择额外在最外围加了一圈,这样的即便是边界处也可以计算周围的雷的个数。
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
2、void Init_board(char board[ROWS][COLS], int row, int col, char set)
该函数声明为扫雷界面初始化函数声明,将mine初始化为字符’0’,show初始化为’*’(此处通过建立char类型的变量set,赋予set不同的值,可以将界面初始化为任何字符,避免了需要建立两个函数分别初始化mine和show)
void Init_board(char board[ROWS][COLS], int row, int col, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
3、Mine_set(mine, ROW, COL)
该函数用于随机生成雷。利用count计数,若该处未布置雷,则放置字符’1’代表雷(此处放置’1’便于之后的计算周围雷的个数),count相应减1。
void Mine_set(char board[ROWS][COLS], int row, int col)
{
int count = easy_mode;
while (count > 0)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
此处通过定义了easy_mode,便于日后对于雷的个数进行修改。
#define easy_mode 10
4、Display_board(show, ROW, COL)
该函数作用为打印界面供玩家进行扫雷,除了9*9格子外额外打印了行号和列号便于玩家输入坐标进行排雷。
void Display_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//打印列号
for (j = 0; j <= col; j++) {
printf("[%d]", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("[%d]", i);//打印行号
for (j = 1; j <= col; j++)
{
printf(" %c ", board[i][j]);
}
printf("\n");
5、Mine_sweep(mine, show, ROW, COL)
该函数为整个扫雷游戏的核心。当玩家选择了所有除了雷以外的格子时,玩家获得胜利。
void Mine_sweep(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_mode)
{
printf("请输入排查的坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("你被炸死了,游戏结束\n");
Display_board(mine, ROW, COL);
break;
}
else
{
int n = get_mine_amount(mine, x, y);//判断周围雷的个数
show[x][y] = n + '0';
win++;
Display_board(show, ROW, COL);
}
}
else
{
printf("超出范围,请重新输入\n");
}
}
if (win == row * col - easy_mode)
{
printf("恭喜你,获得胜利\n");
Display_board(mine, ROW, COL);
}
}
玩家输入坐标后,首先要排查玩家输入的坐标是否在界面范围内,若在范围内,继续判断玩家是否踩到了雷,若踩到雷则跳出循环游戏结束,反之则利用get_mine_amount(mine, x, y)函数计算周围雷的个数,并将个数打印在界面上,供玩家进行下一步的判断。
此处利用了一个小技巧:一个数字加上字符’0’可以转变成相对应的字符(数字加上字符’0’相当于该数字加上’0’的ASCII码值)。
因此在get_mine_amount函数中,我们只需加总玩家选中的坐标周围8个格子里的字符后减去8乘上’0’,即可得到对应的雷的个数的数字,这也是先前选择字符’1’作为雷的标记的原因。
int get_mine_amount(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1]
+ mine[x - 1][y] + mine[x + 1][y]
+ mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1]
- 8 * '0';
}
由于二维数组show是char类型的,因此在赋值的时候需要加上字符’0’将数字转变为对应字符。
代码展示
一、game.h
#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_mode 10
//初始化扫雷界面
void Init_board(char board[ROWS][COLS], int row, int col, char set);
//打印扫雷界面
void Display_board(char board[ROWS][COLS], int row, int col);
//随机生成雷
void Mine_set(char board[ROWS][COLS], int row, int col);
//排雷
void Mine_sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
二、test.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
//菜单函数
void menu()
{
printf("*************************\n");
printf("****** 1、开始游戏 ******\n");
printf("****** 0、结束游戏 ******\n");
printf("*************************\n");
}
//扫雷游戏
void game()
{
//初始化
char mine[ROWS][COLS] = { 0 };//存放布置雷的信息
char show[ROWS][COLS] = { 0 };//存放玩家操作的信息
//初始化布置雷界面
Init_board(mine, ROWS, COLS, '0');
//初始化玩家操作界面
Init_board(show, ROWS, COLS, '*');
//随机生成雷
Mine_set(mine, ROW, COL);
//打印扫雷界面
Display_board(show, ROW, COL);
//排雷
Mine_sweep(mine, show, ROW, COL);
}
//主函数
int main()
{
int i = 0;
srand((unsigned int)time(NULL));
do
{
menu();//打印菜单
scanf("%d", &i);
switch (i)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (i);
return 0;
}
三、game.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
//初始化扫雷界面
void Init_board(char board[ROWS][COLS], int row, int col, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
//打印扫雷界面
void Display_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//打印列号
for (j = 0; j <= col; j++) {
printf("[%d]", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("[%d]", i);//打印行号
for (j = 1; j <= col; j++)
{
printf(" %c ", board[i][j]);
}
printf("\n");
}
}
//随机生成雷
void Mine_set(char board[ROWS][COLS], int row, int col)
{
int count = easy_mode;
while (count > 0)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
//判断周围雷的个数
int get_mine_amount(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1]
+ mine[x - 1][y] + mine[x + 1][y]
+ mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1]
- 8 * '0';
}
//排雷
void Mine_sweep(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_mode)
{
printf("请输入排查的坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("你被炸死了,游戏结束\n");
Display_board(mine, ROW, COL);
break;
}
else
{
int n = get_mine_amount(mine, x, y);//判断周围雷的个数
show[x][y] = n + '0';
win++;
Display_board(show, ROW, COL);
}
}
else
{
printf("超出范围,请重新输入\n");
}
}
if (win == row * col - easy_mode)
{
printf("恭喜你,获得胜利\n");
Display_board(mine, ROW, COL);
}
}
总结
本项目基本实现了扫雷游戏,但仍旧存在较大的修改空间,例如利用递归实现选中格子之后的展开功能……
标签:COLS,ROWS,项目,int,mine,C语言,char,扫雷,board 来源: https://blog.csdn.net/m0_61166151/article/details/122030977