同样根据鹏哥的讲解与思路,自己动手成功实现了扫雷的机制。
唯一难为住的地方:在用递归实现多个不是雷的位置连续显示,自己试着写了一下,结果难以算法自洽,bug很多,计算繁琐,无奈放弃。就在一筹莫展的时候玩了两把扫雷,在玩的过程中有了新的递归实现方法,最后终于实现!
失败的代码也以注释的形式放出来,毕竟是成功路上的一部分~
main.c
#include "game.h"
char mine[ROWS][COLS] = {0};
char show[ROWS][COLS] = {0};
int main()
{
play();
return 0;
}
game.h
#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED
#endif // GAME_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define minecount 10
char mine[ROWS][COLS];
char show[ROWS][COLS];
void game();
int Howmany(char board[ROWS][COLS],int x,int y);
void Showing(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col,int x,int y);
void Minesweeper(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);
void putmine(char board[ROWS][COLS],int row,int col);
void Displayboard(char board[ROWS][COLS],int row,int col);
void Initboard(char board[ROWS][COLS],int row,int col,char flag);
void play();
void menu();
test.c
#include "game.h"
void menu()
{
printf("***************************************\n");
printf("*********** 1.play 0.exit ************\n");
printf("***************************************\n\n");
}
void play()
{
do
{
int input = 0;
menu();
printf("请输入:>");
scanf("%d",&input);
if(input == 1)
{
game();
}
else
{
if(input == 0)
{
printf("退出游戏\n");
break;
}
else
{
printf("输入错误,请重新输入");
}
}
}while(1);
}
//初始化,mine数组未放雷的地方是0,show没有打开的地方是*
void Initboard(char board[ROWS][COLS],int row,int col,char flag)
{
int i = 0;
int j = 0;
for(i=0;i<row;i++)
{
for(j=0;j<col;j++)
{
board[i][j] = flag;
}
}
}
//打印棋盘界面,棋盘是9*9的尺寸
void Displayboard(char board[ROWS][COLS],int row,int col)
{
int i = 0;
int j = 0;
int k = 0;
printf(" ");
for(k=1;k<=col;k++) //列号
{
printf("%d ",k);
}
for(i=1;i<=row;i++)
{
printf("\n");
printf("%d ",i); //行号
for(j=1;j<=col;j++)
{
printf("%c ",board[i][j]);
}
}
printf("\n");
}
//布置雷,雷用1来表示
void putmine(char board[ROWS][COLS],int row,int col)
{
srand((unsigned int)time(NULL));
int count = 0;
int x,y;
while(count<minecount)
{
x = rand()%row + 1;
y = rand()%col + 1;
if(board[x][y] == '0')
{
board[x][y] = '1';
count++;
}
}
}
//扫雷,用户输入坐标进行扫雷,如果是雷,游戏结束,否则提示用户该处九宫格雷的数量
void Minesweeper(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col)
{
int in_x = 0;
int in_y = 0;
int remain = row * col;
while(remain > minecount)
{
printf("\n请输入坐标(例:1 1):>");
scanf("%d %d",&in_x,&in_y);
if(in_x<=row&&in_x>0&&in_y<=col&&in_y>0)
{
if(show[in_x][in_y] == '*')
{
if(mine[in_x][in_y] == '0')
{
//int ret = Howmany(mine,in_x,in_y);
//show[in_x][in_y] = ret + '0';
//remain--;
Showing(mine,show,row,col,in_x,in_y);
int i,j;
remain = 0;
for(i=1;i<=row;i++)
{
for(j=1;j<=col;j++)
{
if(show[i][j]=='*')
{
remain++;
}
}
}
Displayboard(show,ROW,COL);
}
else
{
printf("踩雷啦,完蛋!\n");
break;
}
}
else
{
printf("该坐标已经扫过啦,快换一个\n");
}
}
else
{
printf("你看看你的坐标合理嘛,重新输!\n");
}
}
if(remain == minecount)
{
printf("\n\n\n\n太厉害了,你做到了!!!\n\n");
Displayboard(mine,ROW,COL);
printf("\n");
Displayboard(show,ROW,COL);
}
}
//计算雷的数量,因为雷是用字符表示,所以变成数字需要字符之间做差
int Howmany(char board[ROWS][COLS],int x,int y)
{
int i = 0;
int j = 0;
int sum = 0;
for(i=x-1;i<=x+1;i++)
{
for(j=y-1;j<=y+1;j++)
{
sum += board[i][j]-'0';
}
}
return sum;
}
//当给入一个坐标(该坐标已知不为雷),要求显示所有与之连续且周围雷数量为0的方格
void Showing(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col,int x,int y)
{
int ret = Howmany(mine,x,y);
show[x][y] = ret + '0';
if(ret == 0)
{
int i = 0,j = 0;
for(i = x-1;i<=x+1;i++)
{
for(j = y-1;j<=y+1;j++)
{
if(show[i][j] != '*'||i<=0||i>=ROWS||j<=0||j>=COLS)
{
continue;
}
Showing(mine,show,row,col,i,j);
}
}
}
//失败啦
// int ret = Howmany(mine,x,y);
// show[x][y] = ret + '0';
// int X=x;
// int Y=y;
// if(show[x][y] == '0' && y<=col)
// {
// while(show[x][++Y]!='*' && Y<=col)
// {}
// Showing(mine,show,row,col,x,Y);
// }
// Y=y;
// if(show[x][y] == '0'&& x<=row)
// {
// while(show[++X][y]!='*'&& X<=row)
// {}
// Showing(mine,show,row,col,X,y);
// }
// X=x;
// if(show[x][y] == '0' && y>=1)
// {
// while(show[x][--Y]!='*' && Y>=1)
// {}
// Showing(mine,show,row,col,x,Y);
// }
// Y=y;
// if(show[x][y] == '0' && x>=1)
// {
// while(show[--X][y]!='*'&& X>=1)
// {}
// Showing(mine,show,row,col,X,y);
// }
// X=x;
}
void game()
{
//创建两个二维数组,一个用于存放雷的信息(mine),另一个用于存放扫雷的信息(show)
//初始化
Initboard(mine,ROWS,COLS,'0');
Initboard(show,ROWS,COLS,'*');
//打印棋盘界面
Displayboard(mine,ROW,COL);
Displayboard(show,ROW,COL);
//布置雷
putmine(mine,ROW,COL);
//扫雷
Minesweeper(mine,show,ROW,COL);
}