思路
- 玩家输入地图规格和埋雷数
- 随机生成玩家要求的个数的雷
- 游戏循环
- 退出游戏循环,游戏结束
游戏循环
-
清屏
-
打印地图
- 未被翻开
- 被标记
- 被翻开就显示周围的地雷数,没有就不显示
-
如果地雷 都被标记就退出游戏循环
-
读取玩家输入
-
如果是打开
- 打开是雷游戏结束
- 不是雷就递归展开
-
如果是标记
- 没标记过就标记
- 标记过就取消标记
-
如果是退出就退出游戏循环
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MaxRow 100
#define MaxCol 100
#define NOTHING 0 //没有雷
#define MINE 1 //有雷
#define InMap(x , y , r ,c) (x >= 0 && x < r && y >= 0 && y < c) //判断一个坐标是否在范围内
#define SELECT "\033[7m" //选中的取反色
#define HIDE_CURSOR "\033[?25l" //隐藏光标
#define SHOW_CURSOR "\033[?25h" //显示光标
#define CANCEL "\033[0m" //取消反色
#define INITX 3
#define INITY 3
typedef enum Status
{
OPENED,
CLOSED,
MARKED
} STAT;
typedef struct Element
{
STAT stat;
int mine;
int number;
} ELEM; //地图元素
ELEM map [MaxRow][MaxCol];
void InitMap(int number , int row , int col)
{
int i , j , randx , randy;
for(i = 0; i < row; i++)
for(j = 0; j < col; j++)
{
map [i][j].stat = CLOSED;
map [i][j].mine = NOTHING;
map [i][j].number = 0;
}
for(i = 0; i < number; i++)
{
srand(time(NULL));
do
{
randx = rand() % row;
randy = rand() % col;
}while(map [randx][randy].mine == MINE); //如果有雷,就继续循环,直到无雷
map [randx][randy].mine = MINE;
}
}
void DrawMap(int x , int y , int row , int col , int over)
{
int i , j;
STAT s;
printf(HIDE_CURSOR); //隐藏光标
for(i = 0; i < row; i++)
{
for(j = 0; j < col; j++)
{
if(i == x && j == y)
printf(SELECT); //如果被选中
s = map [i][j].stat;
if(s == CLOSED)
{ if(over == 0)
putchar('#');
else
{
if(map [i][j].mine == MINE)
putchar('!');
else
putchar(' ');
} //如果游戏结束就将未翻开都显示
}
if(s == MARKED)
putchar('*');
if(s == OPENED) //如果不是0就显示数字
{
if(map [i][j].number == 0)
putchar(' ');
else
printf("%d" , map [i][j].number);
}
printf(CANCEL);
}
putchar('\n');
}
printf("key wsad to move,key o to open,key m to mark,key q to quit.\n");
}
int AroundMines(int x , int y , int row , int col) //求一个位置周围的雷数
{
int offsetx , offsety , around = 0;
for(offsetx = -1; offsetx <= 1; offsetx++)
for(offsety = -1 ; offsety <= 1; offsety++)
{
if(offsetx == 0 && offsety == 0)
continue;
if(InMap(x + offsetx , y + offsety , row , col))
{
if(map [x + offsetx][y + offsety].mine == MINE)
around++;
}
}
return around;
}
void Expand(int x , int y , int row , int col) //递归展开
{
STAT s;
int around;
s = map [x][y].stat;
if(s == MARKED || s == OPENED || map [x][y].mine == MINE) //如果打开过了或者标记过了或者是雷,就退出本次递归
return;
around = AroundMines(x , y , row , col);
map [x][y].stat = OPENED;
map [x][y].number = around;
if(around != 0)
return;
if(InMap(x - 1 , y , row , col))
Expand(x - 1 , y , row , col); //向上递归
if(InMap(x + 1 , y , row , col))
Expand(x + 1 , y , row , col); //向下递归
if(InMap(x , y - 1 , row , col))
Expand(x , y - 1 , row , col); //向左递归
if(InMap(x , y + 1 , row , col))
Expand(x , y + 1 , row , col); //向右递归
}
int Open(int x , int y , int row , int col)
{
int over = 0;
if(map [x][y].stat == CLOSED)
{
if(map [x][y].mine == NOTHING)
Expand(x , y , row , col);
else
over = 1;
}
return over;
}
void Mark(int x , int y)
{
if(map [x][y].stat == CLOSED)
map [x][y].stat = MARKED;
else
{
if(map [x][y].stat == MARKED) //如果标记两次就取消标记
map [x][y].stat = CLOSED;
}
}
int Win(int row, int col)
{
int win = 1 , i , j;
for(i = 0; i < row; i++)
for(j = 0; j < col; j++)
{
if(map [i][j].mine == MINE && map [i][j].stat != MARKED) //如果有没标记的雷就不结束
win = 0;
}
return win;
}
int main()
{
int x , y , over = 0 , quit = 0 , row , col , mines;
char input;
x = INITX;
y = INITY;
printf("please enter some data:\n");
printf("row column mines\n");
scanf("%d%d%d" , &row , &col , &mines);
InitMap(mines , row , col);
while(!quit)
{
system("clear");
DrawMap(x , y , row , col ,over);
if(Win(row , col))
{
printf("----GAME WIN----\n");
break;
}
if(over)
{
printf("----GAMEOVER----\n");
break;
}
input = getchar();
switch(input)
{
case 'w':
case 'W':
if(x > 0)
x--;
break;
case 's':
case 'S':
if(x < row - 1)
x++;
break;
case 'a':
case 'A':
if(y > 0)
y--;
break;
case 'd':
case 'D':
if(y < col -1)
y++;
break;
case 'o':
case 'O':
over = Open(x , y , row , col);
break;
case 'm':
case 'M':
Mark(x , y);
break;
case 'q':
case 'Q':
quit = 1;
break;
}
}
printf(SHOW_CURSOR);
}