目录
一、打印菜单
void menu()
{
printf("******************************\n");
printf("*********** 1.play *********\n");
printf("*********** 0.exlt *********\n");
printf("******************************\n");
}
int main()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
prinft("请重新选择\n");
}
} while (input);
return 0;
}
二、创建棋盘
可以创建两个数组一个用来展示(展示数组),一个用来放雷和排查(雷数组)。两个数组的大小要相同,在排查雷数组坐标后可以在展示数组对应坐标处显示出来。需要创建4个常宏量,两个用来初始化,两个用来打印和排查,初始化的数组要比打印的棋盘大一圈,这个在后面会说用法。
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
1.初始化数组
雷数组用‘0’表示没雷,‘1’表示雷(使用字符方便一起初始化和打印),初始化时先全部初始化为‘0’,毕竟扫雷游戏没有刚开始就被炸死。
展示数组则可以用‘*’表示没被排查过,先初始化为‘*’。
void game()
{
char Show[ROWS][COLS] = { 0 };//展示数组
char Fixup[ROWS][COLS] = { 0 };//雷数组
Init(Show, '*');//初始化
Init(Fixup, '0');
}
void Init(char board[ROWS][COLS], char a)//初始化数组
{
int i = 0;
int j = 0;
for(i=0;i<ROWS;i++)
{
for (j = 0; j < COLS; j++)
board[i][j] = a;
}
}
2.打印棋盘
先按三子棋的棋盘打印
void Print(char board[ROWS][COLS])//打印棋盘
{
int i = 0;
int j = 0;
for (i = 1; i <= ROW; i++)
{
for (j = 1; j <= COL; j++)
{
printf(" %c ", board[i][j]);
if (j < COL)
printf("|");
}
printf("\n");
if (i < ROW)
{
for (j = 1; j <= COL; j++)
{
printf("---");
if (j < COL)
printf("|");
}
}
printf("\n");
}
}
不过我们的扫雷是在终端运行的,只能输入坐标去排查,看这个输出的结果显然是不方便排查。可以将它的行列打印出来方便找到排查的坐标。
void Print(char board[ROWS][COLS])//打印棋盘
{
int i = 0;
int j = 0;
for (i = 0; i <= ROW; i++)//打印列坐标
{
printf("%-2d ", i);//每列坐标都相隔3个字符
}
printf("\n\n");
for (i = 1; i <= ROW; i++)
{
printf("%-2d ", i);//打印行坐标
for (j = 1; j <= COL; j++)
{
printf(" %c ", board[i][j]);
if (j < COL)
printf("|");
}
printf("\n ");
if (i < ROW)
{
for (j = 1; j <= COL; j++)
{
printf("---");
if (j < COL)
printf("|");
}
}
printf("\n");
}
}
打印行列时,打印的数字多一位就需要少打印一个空格,不过一般棋盘的行列不会过百,就不需要考虑这种情况。
三、开始排雷
1.设置雷
打印棋盘使用的数组范围是1-ROW和1-COL,我们在排查时输入的坐标就刚好对应了数组的位置。在输入一次坐标后在设置雷,并且那个坐标不能放雷,防止刚开始就被炸死。雷可以定义一个常宏量来决定数量。
void Settd(char Fixup[ROWS][COLS],int count,int x,int y)//设置雷
{
while(count)
{
int i = rand() % ROW+1;
int j = rand() % COL+1;
if (Fixup[i][j] == '0' && (x!=i || y!=j))//生成坐标位置不是雷并且第一次输入不可以放雷
{
Fixup[i][j] = '1';
count--;
}
}
}
void Troub(char Show[ROWS][COLS], char Fixup[ROWS][COLS])//排雷
{
int win = 0;//排查了几个位置
int a = 0;
while(win<ROW*COL-COUNT)
{
printf("请选择坐标:");
int x=-1,y=-1;//输入一个数y的值会是上一个输入的值
scanf("%d.%d", &x, &y);//中间间隔.方便输入
if(a==0)
{
Settd(Fixup,COUNT,x,y);
a++;
}
}
printf("恭喜你扫雷成功\n");
Print(Fixup);
}
2.判断坐标
坐标得在数组范围内。
while(win<ROW*COL-COUNT)
{
printf("请选择坐标:");
scanf("%d.%d", &x, &y);//中间间隔.方便输入
if(a==0)
{
Settd(Fixup, COUNT, x, y);
a++;
}
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
}
else if (x == 0 && y == 0)//标记
{
}
else
printf("坐标非法,请重新输入\n");
}
}
在数组范围内就判断是否是雷,如果是提醒“游戏失败”并打印雷棋盘;不是雷则排查它周围雷的个数,如果周围没有雷则会展开去排查周围雷的周围雷的个数,排查的位置周围有雷就不会在展开。
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (Show[x][y]=='*')
{
if (Fixup[x][y] == '0')
{
Inia(Show, Fixup,&win,x,y);//展开排查
Print(Show);
}
else
{
printf("雷炸了,游戏失败\n");
Print(Fixup);
return;
}
}
else
{
printf("坐标已被排查\n");
continue;
}
}
2.1展开排查
展开排查的坐标可以确定不是雷,先排查它周围雷个数,将这个个数赋值到对应的展示数组内。如果是0则赋值空格,这样打印出来的效果会好些。
void Inia(char Show[ROWS][COLS], char Fixup[ROWS][COLS], int* w,int x,int y)
{
int a=Around(Fixup,x,y);//排查周围雷的个数
if (a == 0)
{
Show[x][y] = ' ';
}
else
Show[x][y] = a+'0';
}
int Around(char Fixup[ROWS][COLS],int x,int y)
{
return (Fixup[x][y - 1] +
Fixup[x + 1][y - 1] +
Fixup[x + 1][y] +
Fixup[x + 1][y + 1] +
Fixup[x][y + 1] +
Fixup[x - 1][y + 1] +
Fixup[x - 1][y] +
Fixup[x - 1][y - 1]) - 8 * '0';
}
这里排查的是它周围8个坐标,如果排查的坐标是在边缘的位置(例:1.1 1.2),创建数组没有扩大就会越界,这也是创建数组范围大的原因。
排查的坐标周围没有雷,就展开排查周围的坐标。
void Inia(char Show[ROWS][COLS], char Fixup[ROWS][COLS], int* w,int x,int y)
{
int a=Around(Fixup,x,y);//排查周围雷的个数
(*w)++;
if (a == 0)
{
Show[x][y] = ' ';
int i = 0;
int j = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
if (Show[x + i][y + j] == '*' && (x + i) >= 1 && (x + i) <= ROW && (y + j) >= 1 && (y + j) <= COL)
//只展开没有排查的和在棋盘范围内的
Inia(Show, Fixup, w, (x+i), (y+j));
}
}
}
else
Show[x][y] = a+'0';
}
3.设置标记
输入0.0开始和退出标记
else if (x == 0 && y == 0)//开始标记
{
while(1)
{
printf("标记坐标:");
x=-1,y=-1;
scanf("%d.%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (Show[x][y] == '*')//标记
{
Show[x][y] = '#';
Print(Show);
}
else if (Show[x][y] == '#')//取消标记
{
Show[x][y] = '*';
Print(Show);
}
else
printf("坐标已被排查,请重新标记\n");
}
else if (x == 0 && y == 0)
{
printf("退出标记\n");
break;
}
else
printf("坐标非法,请重新标记\n");
}
}
游戏代码
game.h
#pragma once
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define COUNT 8
void Init(char board[ROW][COL], char a);
void Print(char board[ROW][COL]);
void Troub(char Show[ROW][COL], char Fixup[ROW][COL]);
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void game()
{
char Show[ROWS][COLS] = { 0 };//展示数组
char Fixup[ROWS][COLS] = { 0 };//雷数组
Init(Show, '*');//初始化
Init(Fixup, '0');
Print(Show);//打印棋盘
Troub(Show, Fixup);
}
void menu()
{
printf("******************************\n");
printf("*********** 1.play *********\n");
printf("*********** 0.exlt *********\n");
printf("******************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("请重新选择\n");
}
} while (input);
return 0;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void Init(char board[ROWS][COLS], char a)//初始化数组
{
int i = 0;
int j = 0;
for(i=0;i<ROWS;i++)
{
for (j = 0; j < COLS; j++)
board[i][j] = a;
}
}
void Print(char board[ROWS][COLS])//打印棋盘
{
int i = 0;
int j = 0;
for (i = 0; i <= ROW; i++)//打印列坐标
{
printf("%-2d ", i);//每列坐标都相隔3个字符
}
printf("\n\n");
for (i = 1; i <= ROW; i++)
{
printf("%-2d ", i);//打印行坐标
for (j = 1; j <= COL; j++)
{
printf(" %c ", board[i][j]);
if (j < COL)
printf("|");
}
printf("\n ");
if (i < ROW)
{
for (j = 1; j <= COL; j++)
{
printf("---");
if (j < COL)
printf("|");
}
}
printf("\n");
}
}
void Settd(char Fixup[ROWS][COLS],int count,int x,int y)//设置雷
{
while(count)
{
int i = rand() % ROW+1;
int j = rand() % COL+1;
if (Fixup[i][j] == '0' && (x!=i || y!=j))//生成坐标位置不是雷并且第一次输入不可以放雷
{
Fixup[i][j] = '1';
count--;
}
}
}
int Around(char Fixup[ROWS][COLS],int x,int y)
{
return (Fixup[x][y - 1] +
Fixup[x + 1][y - 1] +
Fixup[x + 1][y] +
Fixup[x + 1][y + 1] +
Fixup[x][y + 1] +
Fixup[x - 1][y + 1] +
Fixup[x - 1][y] +
Fixup[x - 1][y - 1]) - 8 * '0';
}
void Inia(char Show[ROWS][COLS], char Fixup[ROWS][COLS], int* w,int x,int y)
{
int a=Around(Fixup,x,y);//排查周围雷的个数
(*w)++;
if (a == 0)
{
Show[x][y] = ' ';
int i = 0;
int j = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
if (Show[x + i][y + j] == '*' && (x + i) >= 1 && (x + i) <= ROW && (y + j) >= 1 && (y + j) <= COL)
//只展开没有排查的和在棋盘范围内的
Inia(Show, Fixup, w, (x+i), (y+j));
}
}
}
else
Show[x][y] = a+'0';
}
void Troub(char Show[ROWS][COLS], char Fixup[ROWS][COLS])//排雷
{
int win = 0;//排查了几个位置
int a = 0;
while(win<ROW*COL-COUNT)
{
printf("请选择坐标:");
int x = -1, y = -1;//输入一个数y的值会是上一个输入的值
scanf("%d.%d", &x, &y);//中间间隔.方便输入
if(a==0)
{
Settd(Fixup, COUNT, x, y);
a++;
}
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (Show[x][y]=='*')
{
if (Fixup[x][y] == '0')
{
Inia(Show, Fixup,&win,x,y);//展开排查
Print(Show);
}
else
{
printf("雷炸了,游戏失败\n");
Print(Fixup);
return;
}
}
else
{
printf("坐标已被排查\n");
continue;
}
}
else if (x == 0 && y == 0)//开始标记
{
while(1)
{
printf("标记坐标:");
x = -1, y = -1;
scanf("%d.%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (Show[x][y] == '*')//标记
{
Show[x][y] = '#';
Print(Show);
}
else if (Show[x][y] == '#')//取消标记
{
Show[x][y] = '*';
Print(Show);
}
else
printf("坐标已被排查,请重新标记\n");
}
else if (x == 0 && y == 0)
{
printf("退出标记\n");
break;
}
else
printf("坐标非法,请重新标记\n");
}
}
else
printf("坐标非法,请重新输入\n");
}
printf("恭喜你扫雷成功\n");
Print(Fixup);
}