前言
扫雷,俄罗斯方块,贪吃蛇,应该算的上是互联网最早的一批小游戏了,
我现在还忘不了初中时微机课上总是玩电脑自带的扫雷。这些游戏时隔多年仍然经久不衰。今天我来尝试一下用C语言编写扫雷程序
实现逻辑
玩法
首先在编写代码之前,我们要先在脑中想好怎么才能实现代码,然后再去想怎么用编程语言去实现。
上面就是扫雷的游戏截图。在编写之前我们首先要弄清扫雷的规则。
- 最开始是一个n*n的格子,每个格子下面都有可能有雷或者没雷。
- 如果点的格子没有雷,那么这块格子就会被揭开,然后如果周围一圈的格子都没有雷,那么周围格子就会被自动揭开,直到周围的格子至少有一个雷。
- 排出所有的雷即为获胜,如果点到雷就为失败。
思路
首先我们肯定要生成一个棋盘,对其进行操作,这自然容易让我们联想到二维数组的只是,我的最终代码也确实是用二维数组来实现的。
我们最终想呈现的效果(能力有限,完整的游戏暂时还没能力实现,只能别写一下基本思路)
- 在终端窗口用打印的二维数组代表棋盘
- 在键盘上输入坐标,表示翻开的格子
- 被先开的格子暴露出来,并提示周围还有几个雷
- 排除所有雷获胜,反之失败
效果如图
代码编写
- 首先我们可以生成一个菜单,让我们的游戏更精致一些
#include <stdio.h>
int main()
{
printf("开始游戏请按1\n");
printf("退出游戏请按2\n");
return 0;
}
- 然后我们根据设计的菜单进行引导操作
int main()
{
printf("如果想开始游戏请输入1\n");
printf("如果想退出游戏请输入2\n");
int n = 0;//输入一个选项
do
{
scanf("%d", &n);
switch (n)//这里用switch方便引导
{
case 1:
//开始游戏
break;
case 2:
printf("已退出游戏\n");
return 0;
break;
default://输入1和2以外的数字
printf("输入错误,请重新输入:\n");
}
} while (n != 1 && n != 2);
return 0;
}
- 具体实现游戏细节
首先可以打印一遍没揭开的棋盘
void cover_mint()//打印9*9的棋盘
{
int i = 0;
for (i = 0;i < 9;i++)
{
int j = 0;
for (j = 0;j < 9;j++)
{
printf("$ ");
}
printf("\n");
}
}
这里用$来遮挡,打印9*9的棋盘
- 然后如何实现输入坐标揭开棋盘呢
首先要埋雷,才能够扫雷,我们可以用0代替没有雷,1代替有雷,创建棋盘。但是这里我们最好提前想远一点,到后面我们需要排除所选位置周围8个格子的雷数。我们可以遍历9个格子从而实现
如图所示
那么当我们遍历到角落得位置怎么办,我们可以采用扩大棋盘的方式
(画的很草率,轻喷)
只要我们在周围一圈全都变成0就可以正常遍历了。所以我们在设计棋盘时要设计成11*11的二维数组
确定好数组的大小后,我们就可以埋雷了。我们在上一篇猜数字游戏中曾经使用过生成随机数的函数。简单说一下用法就是利用srand函数生成种子,rand函数生成随机数
#include <stdlib.h>
#include <time.h>
srand((unsigned int)time(NULL));
rand();
其中srand,rand函数头文件stdlib.h,time函数头文件time.h
srand((unsigned int)time(NULL));
int arr[11][11] = {0}//设置棋盘
int mine = 10;//埋十颗雷
while(mine)
{
int x = rand()%9+1;//确保下标x从1到8,最后埋的雷都都在中间9*9
int y = rand()%9+1
if(arr[x][]y]==0)//确保不会重复埋雷
{
arr[x][y] = 1;
mine--;
}
}
埋好雷之后就可以挖雷了
最开始棋盘肯定是全覆盖的,每揭开一次棋盘我们就把覆盖棋盘上的那部分换成内层棋盘,并遍历那个位置周围的内容,查看还有几个雷
char arr2[11][11]
int i = 0;
for(i = 0;i<11;i++)
{
int j = 0;
for(j = 0;j<11;j++)
{
arr2[i][j] = '$';
}
}//arr2数组用作表面遮盖棋盘
int row = 0;
int col = 0;
scanf("%d %d",&row,&col)//输入坐标
if(arr[row][col]==0)//这里举例一种情况,不是雷的情况
{
arr2[row][col] = '0'//把arr2的那个位置更改,这样扫过的雷就会保留下来
int p = 0;
for(p = 1;p<=9;p++)
{
int j = 0;
for(j = 1;j<9;j++)
{
if(i == row&&j == col)//扫过的地方变成0
{
printf("%d ",arr[i][j]);
}
else
{
printf("%c ",arr2[i][j]);//没扫过的地方还是遮盖的
}
}
}
}
上面是举例了扫到不是雷的情况,如果扫到的雷那么游戏结束。如果排除了所有的雷也是为游戏结束。一共81个格子,10颗雷,可以设置一个计次器,每扫完一个雷,计次+1;直到加到71即为获胜。由于可以用到很多函数和头文件,代码较长,可以分装在自己的库函数里。
最终代码
game.h`
`#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define MINE 10;
void print_mint(char arr2[11][11], int row, int col, int n);//打印排雷后的棋盘
void arrange_mine();//布雷函数
void cover_mint();
game.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void print_mint(char arr2[11][11], int row, int col, int n)//打印排雷后的棋盘
{
int arr0[11][11] = { 0 };
int arr1[11][11] = { 1 };
int i = 0;
for (i = 1;i <= 9;i++)
{
int j = 0;
for (j = 1;j <= 9;j++)
{
if (i == row && j == col && n == 0)//row和col是输入的坐标,输入位置解开遮挡
{
printf("%d ", arr0[i][j]);
arr2[i][j] = '0';
}
else if (i == row && j == col && n == 1)
{
arr2[i][j] = '1';//修改原先的遮挡棋盘让这个位置不再遮挡
}
else//其余位置继续遮挡
printf("%c ", arr2[i][j]);
}
printf("\n");
}
}
void arrange_mine()//布雷函数
{
int arr[11][11] = { 0 };//初始化棋盘
int i = 0;
int x = 0;
int y = 0;//x,y是雷的横纵坐标
int mine = MINE;
while (mine)//一共埋十个雷
{
x = rand() % 9 + 1;
y = rand() % 9 + 1;//埋雷的横纵坐标小于10
if (arr[x][y] == 0)//避免重复埋雷
{
arr[x][y] = 1;
mine--;
}
}
/*for (i = 1;i <= 9;i++)
{
int j = 0;
for (j = 1;j <= 9;j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}*/
int row = 0;
int col = 0;
int c = 0;//一共81个位置,10个雷,排查71次没有问题后游戏胜利
char arr2[11][11];
for (i = 0;i < 11;i++)//arr2用于遮挡
{
int j = 0;
for (j = 0;j < 11;j++)
{
arr2[i][j] = '$';
}
}
while (1)
{
printf("请输入想要排除的坐标:");
scanf("%d %d", &row, &col);//输入想要排除的坐标
if (arr[row ][col] == 0)//如果不是雷
{
print_mint(arr2, row, col, 0);
int a = 0;
int b = 0;
int count = 0;
for (a = row - 1;a < row + 2;a++)//遍历所选坐标的周围八个坐标,看看还有几个雷
{
for (b = col - 1;b < col + 2;b++)
{
if (arr[a][b] == 1)
{
count++;//count 用于计次雷数
}
}
}
printf("周围有%d个雷\n", count);
c++;
if (c == 71)
{
printf("恭喜你,所有的雷都被排除了\n");
}
}
else if (arr[row][col] == 1)
{
int i = 0;
for (i = 1;i < 10;i++)
{
int j = 0;
for (j = 1;j < 10;j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
printf("you lose");
break;
}
else
{
printf("非法坐标,请重新输入");
}
}
}
void cover_mint()//打印9*9的棋盘
{
int i = 0;
for (i = 0;i < 9;i++)
{
int j = 0;
for (j = 0;j < 9;j++)
{
printf("$ ");
}
printf("\n");
}
}
源.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
int main()
{
srand((unsigned int)time(NULL));//生成种子;
printf("如果想开始游戏请输入1\n");
printf("如果想退出游戏请输入2\n");
int n = 0;
do
{
scanf("%d", &n);
switch (n)
{
case 1:
printf("游戏开始\n");
cover_mint();
arrange_mine();
break;
case 2:
printf("已退出游戏");
return 0;
break;
default:
printf("输入错误,请重新输入:\n");
}
} while (n != 1 && n != 2);
return 0;
}
最后
耗费了一个下午写出的代码,可能还有很多可以简化或有问题的地方。瑾以此文分享一下我的心得,如果对你有帮助,还请帮忙点赞,评论。如果上面的代码或思路有任何问题,也欢迎在评论区指正