设计要求
1.第一次不会踩到雷
2.点开不是雷显示周围雷数
3.周围没有雷,则展开一片
实现思路
1.需要两个棋盘,一个设计者棋盘,一个玩家棋盘,设计者棋盘用来布雷,玩家棋盘用来排雷。
2.布雷。我们要设计的是一个9x9的棋盘,布有10个雷,那我们是不是就 想到需要创建一个九行九列的二维数组,1表示雷,0表示没有雷,这样能完成吗?答案是否定的。用1表示雷的话,如果某处周围有一个雷,则显示1,那这个1是雷数还是雷呢?所以不能用1来表示雷,同理,0也不可以。那用什么表示?可以用字符1(’1’)和字符0(’0’)来表示,所以将棋盘初始化为’0’,这样都可以用%c来打印。解决了这个还有没有问题呢?你想,要计算一个坐标周围的雷数,就要遍历周围的8个坐标,如果设计成9x9的棋盘,最外围一圈的坐标周围就没有8个位置,这时是不是就搞不定了,所以我们要设计成一个11x11的棋盘,但时我们布雷时就只用中间的9x9的位置。这样就搞定了!
3.排雷。同理布雷,也要设计成11x11的棋盘。这是玩家棋盘,所以初始化时初始化为’*’(当然也可以是其他字符)。
4.判断输赢。当玩家棋盘还剩10个*时,则玩家扫雷成功。
具体实现
1.创建一个工程,新建test.c
,game.c
,game.h
2.test.c
test函数
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
}
菜单函数
void menu()
{
printf("############################\n");
printf("####### 1. play #########\n");
printf("####### 0. exit #########\n");
printf("############################\n");
}
3game.c
初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
memset(board, set, rows*cols*sizeof(board[0][0]));
}
布雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
打印棋盘
测试阶段可以把两个棋盘都打印出来,游戏完成后只打印玩家棋盘。
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf(" ");
for (i = 1; i <= col; i++)
{
printf("%d ", i);
}
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 FindMineSafe(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
int ret = 1;
printf("请输入坐标:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (Mine[x][y] == '1')
{
Mine[x][y] = '0';
count = GetMineCount(Mine, x, y);
Show[x][y] = count + '0';
OpenMine(Mine, Show, ROW, COL, x, y);
while (ret)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (Mine[x][y] == '0')
{
Mine[x][y] = '1';
}
ret--;
}
}
else
{
OpenMine(Mine, Show, ROW, COL, x, y);
}
PrintBoard(Show, ROW, COL);
}
}
如果选中的不是雷,则要计算周围的雷数,设计函数如下:
int GetMineCount(char Mine[ROWS][COLS], int x, int y)
{
return Mine[x - 1][y] +
Mine[x - 1][y - 1] +
Mine[x][y - 1] +
Mine[x + 1][y - 1] +
Mine[x + 1][y] +
Mine[x + 1][y + 1] +
Mine[x][y + 1] +
Mine[x - 1][y + 1] - 8 * '0';
}
如果坐标周围没有雷,则进行展开。这里要用到递归(函数自己调用自己)
void OpenMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col, int x, int y)//递归
{
int ret = 0;
ret = GetMineCount(Mine, x, y);//计算周围雷数
if (ret == 0)
{
Show[x][y] = ' ';
if (x - 1>0 && y>0 && Show[x - 1][y] == '*')
OpenMine(Mine, Show, row, col, x - 1, y);
if (x - 1>0 && y + 1 <= col && Show[x - 1][y + 1] == '*')
OpenMine(Mine, Show, row, col, x - 1, y + 1);
if (x>0 && y + 1 <= col && Show[x][y + 1] == '*')
OpenMine(Mine, Show, row, col, x, y + 1);
if (x + 1 <= row && y + 1 <= col && Show[x + 1][y + 1] == '*')
OpenMine(Mine, Show, row, col, x + 1, y + 1);
if (x + 1 <= row && y>0 && Show[x + 1][y] == '*')
OpenMine(Mine, Show, row, col, x + 1, y);
if (x + 1 <= row && y - 1>0 && Show[x + 1][y - 1] == '*')
OpenMine(Mine, Show, row, col, x + 1, y - 1);
if (x>0 && y - 1>0 && Show[x][y - 1] == '*')
OpenMine(Mine, Show, row, col, x, y - 1);
if (x - 1>0 && y - 1>0 && Show[x - 1][y - 1] == '*')
OpenMine(Mine, Show, row, col, x - 1, y - 1);
}
else
{
Show[x][y] = GetMineCount(Mine, x, y) + '0';
}
}
排雷过程
void FindMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (Mine[x][y] == '1')
{
printf("很遗憾您踩到雷了,游戏结束!\n");
PrintBoard(Mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(Mine, x, y);
Show[x][y] = count + '0';
OpenMine(Mine, Show, ROW, COL, x, y);
PrintBoard(Show, ROW, COL);
if (IsWin(Show, row, col) == COUNT)
{
printf("恭喜您,扫雷成功!\n");
PrintBoard(Mine, ROW, COL);
break;
}
}
}
else
{
printf("坐标非法!\n");
break;
}
}
}
判断输赢
int IsWin(char Show[ROWS][COLS], int row, int col)
{
int count = 0;
int i = 0;
int j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (Show[i][j] == '*')
count++;
}
}
return count;
}
附上源码
game.h
#ifndef __GAME_H__
#define __GAME_H__
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define COUNT 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
void SetMine(char board[ROWS][COLS], int row, int col);
void PrintBoard(char board[ROWS][COLS], int row, int col);
void FindMineSafe(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col);
void FindMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col);
void FindMineSafe(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col);
#endif //__GAME_H__
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void game()
{
char Mine[ROWS][COLS] = { 0 };//
char Show[ROWS][COLS] = { 0 };
InitBoard(Mine, ROWS, COLS,'0');//初始化设计者棋盘
InitBoard(Show, ROWS, COLS,'*');//初始化玩家棋盘
SetMine(Mine, ROW, COL);//布置雷
//PrintBoard(Mine, ROW, COL);//打印设计者棋盘
PrintBoard(Show, ROW, COL);//打印玩家棋盘
FindMineSafe(Mine, Show, ROW, COL);//第一次不炸死
FindMine(Mine, Show, ROW, COL);//排雷
}
void menu()
{
printf("############################\n");
printf("####### 1. play #########\n");
printf("####### 0. exit #########\n");
printf("############################\n");
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
}
int main()
{
test();
system("pause");
return 0;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
memset(board, set, rows*cols*sizeof(board[0][0]));
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf(" ");
for (i = 1; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ",board[i][j]);
}
printf("\n");
}
}
int GetMineCount(char Mine[ROWS][COLS], int x, int y)
{
return Mine[x - 1][y] +
Mine[x - 1][y - 1] +
Mine[x][y - 1] +
Mine[x + 1][y - 1] +
Mine[x + 1][y] +
Mine[x + 1][y + 1] +
Mine[x][y + 1] +
Mine[x - 1][y + 1] - 8 * '0';
}
void OpenMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col, int x, int y)//递归
{
int ret = 0;
ret = GetMineCount(Mine, x, y);
if (ret == 0)
{
Show[x][y] = ' ';
if (x - 1>0 && y>0 && Show[x - 1][y] == '*')
OpenMine(Mine, Show, row, col, x - 1, y);
if (x - 1>0 && y + 1 <= col && Show[x - 1][y + 1] == '*')
OpenMine(Mine, Show, row, col, x - 1, y + 1);
if (x>0 && y + 1 <= col && Show[x][y + 1] == '*')
OpenMine(Mine, Show, row, col, x, y + 1);
if (x + 1 <= row && y + 1 <= col && Show[x + 1][y + 1] == '*')
OpenMine(Mine, Show, row, col, x + 1, y + 1);
if (x + 1 <= row && y>0 && Show[x + 1][y] == '*')
OpenMine(Mine, Show, row, col, x + 1, y);
if (x + 1 <= row && y - 1>0 && Show[x + 1][y - 1] == '*')
OpenMine(Mine, Show, row, col, x + 1, y - 1);
if (x>0 && y - 1>0 && Show[x][y - 1] == '*')
OpenMine(Mine, Show, row, col, x, y - 1);
if (x - 1>0 && y - 1>0 && Show[x - 1][y - 1] == '*')
OpenMine(Mine, Show, row, col, x - 1, y - 1);
}
else
{
Show[x][y] = GetMineCount(Mine, x, y) + '0';
}
}
void FindMineSafe(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
int ret = 1;
printf("请输入坐标:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (Mine[x][y] == '1')
{
Mine[x][y] = '0';
count = GetMineCount(Mine, x, y);
Show[x][y] = count + '0';
OpenMine(Mine, Show, ROW, COL, x, y);
while (ret)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (Mine[x][y] == '0')
{
Mine[x][y] = '1';
}
ret--;
}
}
else
{
OpenMine(Mine, Show, ROW, COL, x, y);
}
//PrintBoard(Mine, ROW, COL);
PrintBoard(Show, ROW, COL);
}
}
int IsWin(char Show[ROWS][COLS], int row, int col)
{
int count = 0;
int i = 0;
int j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (Show[i][j] == '*')
count++;
}
}
return count;
}
void FindMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (Mine[x][y] == '1')
{
printf("很遗憾您踩到雷了,游戏结束!\n");
PrintBoard(Mine, ROW, COL);
break;
}
else
{
int count = GetMineCount(Mine, x, y);
Show[x][y] = count + '0';
OpenMine(Mine, Show, ROW, COL, x, y);
PrintBoard(Show, ROW, COL);
if (IsWin(Show, row, col) == COUNT)
{
printf("恭喜您,扫雷成功!\n");
PrintBoard(Mine, ROW, COL);
break;
}
}
}
else
{
printf("坐标非法!\n");
break;
}
}
}
代码演示
可以看到(1,5)是雷。第一次输入(1,5)没有踩到雷,并且展开了一片。
有什么不足之处请多多指教!欢迎留言指教。