前言
文章展示了9×9的简单扫雷小游戏(也可以通过修改部分代码更改成n×n的),并简单介绍了编写程序过程中的思路,文件结尾附带完整代码!!!
一、游戏原理
游戏开始时,系统随机在9×9共81个格子中随机设置十颗地雷,玩家需要将没有地雷的格子(全部找出来)找出来。当玩家点击任意一个格子后,若这个格子没有地雷,则会显示当前位置周围八个格子地雷数之和(现在大家见到的扫雷游戏,当玩家点击了数字是0的格子时游戏会帮助玩家将周围的8个格子全部打开,此方面的优化该程序暂未给出),玩家需要通过当前已知的数字判断地雷的位置,并将认为没有地雷的格子全部点击,若过程中未点击到地雷,则游戏胜利;否则,游戏失败。
二、核心思路
创建两个数组mine和show,分别存放地雷位置和玩家看到的画面。数组mine初始化为字符0,然后将随机分配为地雷的地方赋值为字符1。数组show初始化为字符*,当玩家输入某个位置时,若对应位置的数组mine值为1则视为踩到的地雷;否则,数组mine对应位置的周围8个元素相加之和即为该位置周围的地雷数(关于如何计算字符型数字之和的问题我在上一篇文章中有过专门的总结)。
三、实现过程
1、创建游戏菜单
菜单打印函数menu()
void menu() {
printf("********************************\n");
printf("********** 1.play **********\n");
printf("********** 0.exit **********\n");
printf("********************************\n");
}
通过do...while循环实现游戏的多次开始
int input = 0;
do{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("选择错误,请重新选择!!!\n");
break;
}
} while (input);
2、游戏初始化
创建数组mine和数组show分别用来存放地雷位置和游戏画面,在game.c文件中创建初始化函数 InitBoard()。
char mine[11][11];
char show[11][11];
为了方便计算周围地雷数, 需要再9×9的格子周围加上一行(列)并初始化为0;
void InitBoard(char board[11][11], int n, char x) {
int i = 0;
int j = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
board[i][j] = x;
}
}
if (x=='*') {
board[0][0] = ' ';
board[10][10] = ' ';
board[0][10] = ' ';
board[10][0] = ' ';
for (j = 1; j < n - 1; j++) {
board[0][j] = j + '0';
board[10][j] = j + '0';
}
for (i = 1; i < n - 1; i++) {
board[i][0] = i + '0';
board[i][10] = i + '0';
}
}
}
为方便玩家观察位置,将show数组的四周初始化为对应坐标的数值。
在game.c文件中创建函数布置地雷函数SetMine(),在数组mine中随机布置十颗地雷。
void SetMine(char mine[11][11], int n) {
int i = 0;
int x = 0;
int y = 0;
for (i = 0; i < n - 1; i++) {
while (1) {
x = rand() % (n - 2);
y = rand() % (n - 2);
if (mine[x + 1][y + 1] == '0') {
mine[x + 1][y + 1] = '1';
break;
}
}
}
}
3、游戏阶段
利用do...while循环结构实现重复排雷、统计地雷数量的过程,并利用变量T记录排雷次数,从而判断是否胜利。
int T = 1;
do {
DisplayBoard(show, 11);
if (!FindMine(mine, show, 11)) {
printf("---- 游戏获胜! ----\n");
DisplayBoard(show, 11);
printf("---- 游戏获胜! ----\n");
break;
}
if (T == 71) {
break;
}
} while (T++);
在game.c文件中创建打印函数DisplayBoard()、排雷函数FindMine()以及统计雷数函数GetMineCount()。
void DisplayBoard(char board[11][11], int n) {
int i = 0;
int j = 0;
for (i = 0; i < n; i++) {
printf("-----------------------\n");
for (j = 0; j < n; j++) {
printf("|%c", board[i][j]);
}
printf("|\n");
}
printf("-----------------------\n");
}
int FindMine(char mine[11][11], char show[11][11], int n) {
printf("请输入排雷位置:>");
int x = 0;
int y = 0;
while (1) {
scanf("%d%d", &x, &y);
if (x >= 1 && x <= 9 && y >= 1 && y <= 9) {
if (show[x][y] == '*') {
if (mine[x][y] == '1') {
printf("很遗憾,你被炸死了......\n");
printf("地雷分布图:\n");
DisplayBoard(mine, 11);
return 0;
}
else {
int z = GetMineCount(mine, x, y);
show[x][y] = z + '0';
return 1;
}
}
else {
printf("该位置已完成排雷,");
}
}
else {
printf("非法位置,");
}
printf("请重新输入排雷位置:>");
}
}
int GetMineCount(char mine[11][11], int x, int y) {
int z = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
z += mine[x + i][y + j];
}
}
return (z - 9 * '0');
}
四、完整代码
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu() {
printf("********************************\n");
printf("********** 1.play **********\n");
printf("********** 0.exit **********\n");
printf("********************************\n");
}
void game() {
char mine[11][11];
char show[11][11];
InitBoard(mine, 11, '0');
InitBoard(show, 11, '*');
SetMine(mine, 11, '0');
int T = 1;
do {
DisplayBoard(show, 11);
if (!FindMine(mine, show, 11)) {
printf("---- 游戏获胜! ----\n");
DisplayBoard(show, 11);
printf("---- 游戏获胜! ----\n");
break;
}
if (T == 71) {
break;
}
} while (T++);
}
int main()
{
srand((int)time(NULL));
int input = 0;
do{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("选择错误,请重新选择!!!\n");
break;
}
} while (input);
return 0;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char board[11][11], int n, char x) {
int i = 0;
int j = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
board[i][j] = x;
}
}
if (x=='*') {
board[0][0] = ' ';
board[10][10] = ' ';
board[0][10] = ' ';
board[10][0] = ' ';
for (j = 1; j < n - 1; j++) {
board[0][j] = j + '0';
board[10][j] = j + '0';
}
for (i = 1; i < n - 1; i++) {
board[i][0] = i + '0';
board[i][10] = i + '0';
}
}
}
void DisplayBoard(char board[11][11], int n) {
int i = 0;
int j = 0;
for (i = 0; i < n; i++) {
printf("-----------------------\n");
for (j = 0; j < n; j++) {
printf("|%c", board[i][j]);
}
printf("|\n");
}
printf("-----------------------\n");
}
void SetMine(char mine[11][11], int n) {
int i = 0;
int x = 0;
int y = 0;
for (i = 0; i < n - 1; i++) {
while (1) {
x = rand() % (n - 2);
y = rand() % (n - 2);
if (mine[x + 1][y + 1] == '0') {
mine[x + 1][y + 1] = '1';
break;
}
}
}
}
int FindMine(char mine[11][11], char show[11][11], int n) {
printf("请输入排雷位置:>");
int x = 0;
int y = 0;
while (1) {
scanf("%d%d", &x, &y);
if (x >= 1 && x <= 9 && y >= 1 && y <= 9) {
if (show[x][y] == '*') {
if (mine[x][y] == '1') {
printf("很遗憾,你被炸死了......\n");
printf("地雷分布图:\n");
DisplayBoard(mine, 11);
return 0;
}
else {
int z = GetMineCount(mine, x, y);
show[x][y] = z + '0';
return 1;
}
}
else {
printf("该位置已完成排雷,");
}
}
else {
printf("非法位置,");
}
printf("请重新输入排雷位置:>");
}
}
int GetMineCount(char mine[11][11], int x, int y) {
int z = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
z += mine[x + i][y + j];
}
}
return (z - 9 * '0');
}
game.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
void InitBoard(char board[11][11], int n, char x); //数组初始化
void DisplayBoard(char board[11][11], int n); //打印棋盘
void SetMine(char mine[11][11], int n); //布置雷
int FindMine(char mine[11][11], char show[11][11], int n); //排雷
int GetMineCount(char mine[11][11], int x, int y); //统计雷数