C语言 | 扫雷游戏-优化
C语言实现扫雷游戏
本文接上篇:C语言实现扫雷游戏-简单版
为了添加扫出一片的效果,本文对扫雷部分函数做出修改如下:
static int get_mine(char mine[ROWS][COLS], int x, int y)
{
return mine[x-1][y-1] +
mine[x][y-1] +
mine[x+1][y-1] +
mine[x-1][y] +
mine[x+1][y] +
mine[x-1][y+1] +
mine[x][y+1] +
mine[x+1][y+1] - 8*'0';
}
static void clean_around(char show[ROWS][COLS], char mine[ROWS][COLS], char tag[ROWS][COLS], int x, int y)
{
//屏蔽掉边缘部分
if (x == 0 || x == ROWS - 1 || y == 0 || y == COLS - 1)
{
//
}
else
{
int i;
for (i = x - 1; i <= x + 1; i++)
{
int j;
for (j = y - 1; j <= y + 1; j++)
{
if (tag[i][j] == '0') //0表示未被访问过
{
tag[i][j] = '1';//标记为1,表示排查过,下次不再排查
int ret = get_mine(mine, i, j);
if (ret == 0)
{
show[i][j] = ' ';
clean_around(show, mine, tag, i, j);
}else
{
show[i][j] = ret + '0';
}
}
}
}
}
}
static int CountMine(char show[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <=col; j++)
{
if (show[i][j] == '*' || show[i][j] == '#')
{
count++;
}
}
}
return count;
}
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], char tag[ROWS][COLS], int row, int col)
{
int count = 0;//记录找出的雷的个数
while(count != EASY_COUNT)
{
//玩家输入
printf("Please enter x and y:>");
int x, y;
scanf("%d %d", &x, &y);
//检查输入合法性,不合法重新输入
if (x < 1 || y < 1 || x > ROW || y > COL)
{
printf("Invalid input, please re-enter.\n");
continue;
}
//点击or标记
printf("1 CLICK\n2 TAG\n\n");
int z;
scanf("%d", &z);
if (z == 1) //点击
{
if (mine[x][y] == '1') //炸死了
{
printf("Oops, here is a bomb, you out!\n");
PrintBoard(mine, row, col);
printf("\n\n\n");
break;
}else //安全
{
//查询周围一圈雷的个数
int ret = get_mine(mine, x, y);
tag[x][y] = '1';
if (ret == 0)
{
show[x][y] = ' ';
clean_around(show, mine, tag, x, y);
}else
{
show[x][y] = ret + '0';
}
PrintBoard(show, row, col);
printf("\n\n");
}
}else if (z == 2) //标记
{
show[x][y] = '#';
PrintBoard(show, row, col);
printf("\n\n");
}
//检查雷是否排完
count = CountMine(show, ROW, COL);
if (count == EASY_COUNT)
{
printf("Congratulations, you successfully cleared all the mines!\n");
PrintBoard(mine, row, col);
printf("\n\n\n");
}
}
}
效果测试
//设置一个雷
//show数组展示如下
0 1 2 3 4 5 6 7 8 9
1 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0
4 1 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0 0
8 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0
//可见只有(4,1)处是雷
//玩游戏测试
*********************
**** 1. Play ******
**** 0. Exit ******
*********************
Please enter your choice(1/0):> 1
Welcome to Minesweeper!
0 1 2 3 4 5 6 7 8 9
1 * * * * * * * * *
2 * * * * * * * * *
3 * * * * * * * * *
4 * * * * * * * * *
5 * * * * * * * * *
6 * * * * * * * * *
7 * * * * * * * * *
8 * * * * * * * * *
9 * * * * * * * * *
Please enter x and y:>4 3
1 CLICK
2 TAG
1
0 1 2 3 4 5 6 7 8 9
1
2
3 1 1
4 * 1
5 1 1
6
7
8
9
Congratulations, you successfully cleared all the mines!
0 1 2 3 4 5 6 7 8 9
1 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0
4 1 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0 0
8 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0
*********************
**** 1. Play ******
**** 0. Exit ******
*********************
Please enter your choice(1/0):> 0
Bye bye ~
完整版代码,欢迎各位网友复制测试
1-game.h
//库函数
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义字符
#define ROW 9 //排雷区域
#define COL 9 //排雷区域
#define EASY_COUNT 1 //雷的个数
#define ROWS ROW+2 //显示区域
#define COLS COL+2 //显示区域
//定义函数
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], char tag[ROWS][COLS], int row, int col);
2-game.c
#include "game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i;
for(i = 0; i < ROWS; i++)
{
int j;
for(j = 0; j < COLS; j++)
{
board[i][j] = set;
}
}
}
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i;
for(i = 0; i <= col; i++)
{
printf("%c ", i + '0');
}
printf("\n");
for(i = 1; i <= row; i++)
{
printf("%c ", i + '0');
int j;
for(j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
//某座标的值设为'1'代表设置雷
int count = 0;
while(count < EASY_COUNT)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x][y] == '0')
{
board[x][y] = '1'; //布置雷
count++;
}
}
}
}
static int get_mine(char mine[ROWS][COLS], int x, int y)
{
return mine[x-1][y-1] +
mine[x][y-1] +
mine[x+1][y-1] +
mine[x-1][y] +
mine[x+1][y] +
mine[x-1][y+1] +
mine[x][y+1] +
mine[x+1][y+1] - 8*'0';
}
static void clean_around(char show[ROWS][COLS], char mine[ROWS][COLS], char tag[ROWS][COLS], int x, int y)
{
//屏蔽掉边缘部分
if (x == 0 || x == ROWS - 1 || y == 0 || y == COLS - 1)
{
//
}
else
{
int i;
for (i = x - 1; i <= x + 1; i++)
{
int j;
for (j = y - 1; j <= y + 1; j++)
{
if (tag[i][j] == '0') //0表示未被访问过
{
tag[i][j] = '1';//标记为1,表示排查过,下次不再排查
int ret = get_mine(mine, i, j);
if (ret == 0)
{
show[i][j] = ' ';
clean_around(show, mine, tag, i, j);
}else
{
show[i][j] = ret + '0';
}
}
}
}
}
}
static int CountMine(char show[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <=col; j++)
{
if (show[i][j] == '*' || show[i][j] == '#')
{
count++;
}
}
}
return count;
}
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], char tag[ROWS][COLS], int row, int col)
{
int count = 0;//记录找出的雷的个数
while(count != EASY_COUNT)
{
//玩家输入
printf("Please enter x and y:>");
int x, y;
scanf("%d %d", &x, &y);
//检查输入合法性,不合法重新输入
if (x < 1 || y < 1 || x > ROW || y > COL)
{
printf("Invalid input, please re-enter.\n");
continue;
}
//点击or标记
printf("1 CLICK\n2 TAG\n\n");
int z;
scanf("%d", &z);
if (z == 1) //点击
{
if (mine[x][y] == '1') //炸死了
{
printf("Oops, here is a bomb, you out!\n");
PrintBoard(mine, row, col);
printf("\n\n\n");
break;
}else //安全
{
//查询周围一圈雷的个数
int ret = get_mine(mine, x, y);
tag[x][y] = '1';
if (ret == 0)
{
show[x][y] = ' ';
clean_around(show, mine, tag, x, y);
}else
{
show[x][y] = ret + '0';
}
PrintBoard(show, row, col);
printf("\n\n");
}
}else if (z == 2) //标记
{
show[x][y] = '#';
PrintBoard(show, row, col);
printf("\n\n");
}
//检查雷是否排完
count = CountMine(show, ROW, COL);
if (count == EASY_COUNT)
{
printf("Congratulations, you successfully cleared all the mines!\n");
PrintBoard(mine, row, col);
printf("\n\n\n");
}
}
}
3-test.c
#include "game.h"
void menu()
{
printf("*********************\n");
printf("**** 1. Play ******\n");
printf("**** 0. Exit ******\n");
printf("*********************\n");
}
void game()
{
//二维数组存储棋盘
char mine[ROWS][COLS] = {0}; //存放布置好的雷的信息
char show[ROWS][COLS] = {0}; //存放排查出的雷的信息
char tag[ROWS][COLS] = {0}; //用于标记被排查过的坐标
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
InitBoard(tag, ROWS, COLS, '0');
//打印棋盘
// PrintBoard(mine, ROW, COL);
PrintBoard(show, ROW, COL);
//布置雷
SetMine(mine, ROW, COL);
// PrintBoard(mine, ROW, COL);
//扫雷
FindMine(show, mine, tag, ROW, COL);
}
int main(int argc, char **argv)
{
srand((unsigned int)time(NULL));
int input;
do
{
menu();
printf("Please enter your choice(1/0):> ");
scanf("%d", &input);
switch (input)
{
case 1:
printf("Welcome to Minesweeper!\n");
game();
break;
case 0:
printf("Bye bye ~\n\n\n");
break;
default:
printf("Invalid input, please re-enter.\n");
break;
}
} while (input);
return 0;
}