扫雷(C语言版)
这个扫雷是在9*9的格子里,一共有10个地雷.
游戏功能:输入扫雷坐标后可以将周围没有地雷的坐标展开,可以标记可能有地雷的坐标,标记错了可以取消标记,利用清屏函数实现每次输完正确的坐标后可以清空屏幕再打印存放地雷的棋盘,
game.h(头文件)
# ifndef _ _GAME _ H __
# define _ _GAME _ H _ _
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define H 11//设置雷数组是行
#define L 11//设置雷数组是列
#define Hh (H-2)//排雷时打印出来的数组的行
#define Ll (L-2)//排雷时打印出来的数组的行
#define MINE_NUM 10 //雷的个数
#define DISPLAY_BOARD 0//检查时查看雷
#define HAVE_MINE 0//检查have_mine函数
void lay_mines (char arr1[H][L],int h,int l);//布雷
void display_board(char arr[H][L], int h, int l); //打印数组
void find_mines(char arr1[H][L], char arr2[H][L], int h, int l); //输入坐标扫雷
void sign_mines(char arr1[H][L], char arr2[H][L], int h, int l);//标记雷
void not_sign_mines(char arr1[H][L], char arr2[H][L], int h, int l);//取消标记
void unfold_mines (char arr1[H][L], char arr2[H][L], int h, int l,int a, int b);//展开周围没有雷的坐标
#endif
test.c(测试游戏功能)
# include "game2.h"
void menu()//打印菜单函数
{
printf ("**********************************\n");
printf ("********* 扫雷游戏 **********\n");
printf ("******** (1)play **********\n");
printf ("******** (0)exit **********\n");
printf ("**********************************\n");
printf ("注:游戏坐标为0~9\n");
}
void empty(char arr[H][L],int h,int l,char p)//初始化数组,将数组内容全部初始化为传给函数的参数 字符p
{
int i = 0, j = 0;
for (i=0; i<h; i++)
{
for(j=0; j<l; j++)
{
arr[i][j] = p;
}
}
}
void display_board(char arr[H][L], int h, int l)//打印棋盘
{
int i = 0, j = 0;
for (i=0; i<l; ++i)
{
printf ("%-4d",i);//打印列号
}
printf ("\n");
for (i=1; i<h; ++i)
{
printf (" %-2d|",i);//打印行号
for (j=1; j<l; ++j)//打印竖线
{
printf (" %c ",arr[i][j]);
if(j<l-1)
{
printf ("|");
}
}
printf ("\n");
for (j=0; j<l; ++j) //打印横线
{
printf ("--- ");
}
printf ("\n");
}
}
void game ()
{
char arr1[H][L] = {'0'};
char arr2[H][L] = {'0'};
empty (arr1, H, L, '0');//把数组初始化为0,arr1是布雷用的数组
empty (arr2, H, L, '*');//吧数组初始化为*,arr2是打印到屏幕的数字
system("cls"); //清屏函数
//布雷
lay_mines (arr1, Hh, Ll);
#if DISPLAY_BOARD
//查看雷
display_board(arr1, Hh+1, Ll+1);
#endif
//排雷
display_board (arr2, Hh+1, Ll+1);
find_mines(arr1, arr2, Hh, Ll);
}
int main()
{
int input = 0;
srand ((unsigned) time (NULL));
do
{
menu();
printf ("请选择0(exit)/1(play):\n");
scanf ("%d",&input);
switch(input)
{
case 0: printf ("退出游戏!!!\n");
break;
case 1: game ();
break;
default: printf ("你输入的有误,请重新输入!!\n");
break;
}
}while (input);
system ("pause");
return 0;
}
game.c(游戏主要函数)
#include "game2.h"
void lay_mines (char arr[H][L],int h,int l) //布雷
{
int a = 0, i = 0, j = 0 ;
while(a<MINE_NUM)
{
i = rand()% Hh +1;
j = rand()% Ll +1;
if (arr[i][j] == '0')
{
arr[i][j] = '1';
a++;
}
}
}
void unfold_mines (char arr1[H][L] , char arr2[H][L] ,int a, int b)//利用递归,展开周围没有雷的空格
{
arr2[a][b] = ((arr1[a-1][b-1] + arr1[a-1][b] + arr1[a-1][b+1]
+ arr1[a][b-1] + arr1[a][b+1]
+ arr1[a+1][b-1] + arr1[a+1][b] + arr1[a+1][b+1])
- 8*'0')+'0' ;
if(arr2[a][b] == '0')
{
if (a-1>0 && b-1>0 && arr2[a-1][b-1] == '*')
{
unfold_mines (arr1, arr2, a-1, b-1);
}
if (a-1>0 && b>0 && arr2[a-1][b] == '*')
{
unfold_mines (arr1, arr2, a-1, b);
}
if (a-1>0 && b+1>0 && arr2[a-1][b+1] == '*')
{
unfold_mines (arr1, arr2, a-1, b+1);
}
if (a>0 && b-1>0 && arr2[a][b-1] == '*')
{
unfold_mines (arr1, arr2, a, b-1);
}
if (a>0 && b+1>0 && arr2[a][b+1] == '*')
{
unfold_mines (arr1, arr2, a, b+1);
}
if (a+1>0 && b-1>0 && arr2[a+1][b-1] == '*')
{
unfold_mines (arr1, arr2, a+1, b-1);
}
if (a+1>0 && b>0 && arr2[a+1][b] == '*')
{
unfold_mines (arr1, arr2, a+1, b);
}
if (a+1>0 && b+1>0 && arr2[a+1][b+1] == '*')
{
unfold_mines (arr1, arr2, a+1, b+1);
}
}
}
void first_mine(char arr1[H][L], char arr2[H][L], int a, int b)//第一次排雷不能被炸死
{
int i = 0, j = 0;
if (arr1[a][b] == '1')
{
arr1[a][b] = '0';
while (1)
{
i = rand()% Hh +1;
j = rand()% Ll +1;
if (arr1[i][j] == '0')
{
arr1[i][j] = '1';
break;
}
}
}
}
int have_mine(char arr[H][L],int h, int l)//判断是否把地雷排完,排完返回0,否则返回1
{
int i = 0, j = 0, sign_count = 0, left_count = 0;//sign_count 表示标记个数,find_count 表示剩余未标记雷的个数
for (i=1; i<h; ++i)
{
for (j=1; j<l; ++j)
{
if (arr[i][j] == '*')
{
left_count ++;
}
if (arr[i][j] == '#')
{
sign_count ++;
}
}
}
#if HAVE_MINE
printf ("sign_count = %d\n",sign_count);
printf ("left_count = %d\n",left_count);
#endif
if ((left_count+sign_count) == MINE_NUM)
{
return 0;
}
else
{
return 1;
}
}
void sign_mines(char arr1[H][L], char arr2[H][L], int h, int l)//标记函数
{
int a = 0, b = 0;
printf("请输入你要标记的坐标:\n");
scanf ("%d%d",&a, &b);
if(arr2[a][b] == '*')
{
system("cls"); //清屏函数
arr2[a][b] = '#';
display_board (arr2, Hh+1, Ll+1);
}
else
{
printf ("你输入的坐标有误\n");
}
}
void not_sign_mines(char arr1[H][L], char arr2[H][L], int h, int l)//取消标记函数
{
int a = 0, b = 0;
printf("请输入你要取消标记的坐标:\n");
scanf ("%d%d",&a, &b);
if(arr2[a][b] == '#')
{
system("cls"); //清屏函数
arr2[a][b] = '*';
display_board (arr2, Hh+1, Ll+1);
}
else
{
printf ("你输入的坐标有误\n");
}
}
void find_mines(char arr1[H][L], char arr2[H][L], int h, int l)//排雷(第一次不炸死)
{
int a = 0, b = 0, times = 0, t = 0;//a , b—数组下标, time — 次数(保证第一次不被炸死)
int is_pai = 0;
do
{
times ++;
printf("标记(1)/取消标记(2)/排雷(3)\n");
scanf ("%d", &is_pai);
if (is_pai == 1)//1表示标记
{
sign_mines(arr1, arr2, h, l);
}
else if (is_pai == 2)// 2表示取消标记
{
not_sign_mines( arr1, arr2, h, l);
}
else if (is_pai == 3)//3表示排雷
{
printf ("请输入你要排的雷的坐标:\n");
scanf ("%d%d", &a, &b);
if (arr2[a][b] != '*')
{
printf ("你输入的坐标有误!\n");
}
else if (arr2[a][b] == '*' && a>=1 && a<=h && b>=1 &&b<=h)
{
if(times == 1)
{
first_mine(arr1, arr2, a, b);
}
if (times !=1 && arr1[a][b] == '1')
{
printf ("恭喜你,被炸死了!!!\n");
display_board(arr1, h+1, l+1);
break;
}
else
{
system("cls"); //清屏函数
unfold_mines (arr1 , arr2 , a, b);
display_board(arr2, h+1, l+1);
}
}//排雷else
else
{
printf ("你的输入有误!!!\n");
}
}//1, 2, 3 else
else
{
printf ("你的输入有误!!!\n");
}
t = have_mine(arr2, Hh+1, Ll+1);//t 表示判断是不是把雷排完了的变量
}while (t);
if (t == 0)
{
printf ("恭喜你,把雷排完了!!!\n");
display_board(arr1, h+1, l+1);
}
}