文章目录
前言
提示:这里可以添加本文要记录的大概内容:
今天来和大家说说扫雷如何写。
提示:以下是本篇文章正文内容,下面案例可供参考
一、整体思路
和上文五子棋呢一样,我们依然用三个文件,game.c game.h 源.c这样分模块实现更直观,更清晰。
二、解决思路
1.主函数的设计
代码如下(示例):
主函数我们用do while 和switch来实现,当然也可以用while (, , ,)加逗号表达式来实现。
#include "game.h"
void menu()
{
printf("*******************\n");
printf("***0.exit 1.play***\n");
printf("*******************\n");
}
void game()
{
char mine[Rows][Cols] = { 0 };//布置雷
char show[Rows][Cols] = { 0 };//显示雷
InitBoard(mine, Rows, Cols, '0');//初始化mine棋盘
InitBoard(show, Rows, Cols, '*');//初始化show棋盘
setmine(mine, Row, Col);//布置雷区
print_Board(show, Row, Col);
print_Board(mine, Row, Col);
find_mine(mine, show, Row, Col);
}
int main()
{
int input = 0;
srand((unsigned)time(NULL));
do
{
menu();
printf("请输入 :");
scanf("%d", &input);
switch (input)
{
case 0:
printf("游戏结束\n");
break;
case 1:
game();
break;
default:
printf("请重新输入\n");
break;
}
} while (input);
return 0;
}
2.头文件的设计
头文件我们全部放在game.h这个文件夹里
代码如下(示例):
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <stdlib.h>
#define Row 9
#define Col 9
#define Rows Row+2
#define Cols Col+2
#define Easy_count 5
void InitBoard(char Board[Rows][Cols], int rows, int cols, char set);
void print_Board(char Board[Rows][Cols], int row, int col);
void setmine(char Board[Rows][Cols], int row, int col);
void find_mine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col);
int mine_count(char mine[Rows][Cols], int x, int y);
void open(char mine[Rows][Cols], char show[Rows][Cols], int x, int y);
void mark(char show[Rows][Cols], int row, int col);
3.棋盘的初始化
遍历整个棋盘并且放入一个字符来接收我们想要初始化的字符,增加了函数的可复用性。
void InitBoard(char Board[Rows][Cols], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < Rows; i++)
{
int j = 0;
for (j = 0; j < Cols; j++)
{
Board[i][j] = set;
}
}
}
4.棋盘的打印
打印行和打印列,这样可以看起来更直观。
void print_Board(char Board[Rows][Cols], int row, int col)
{
int i = 0;
printf("-------------------\n");
for (i = 0; i <= row; i++)
{
printf("%d ", i);//打印行
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);//打印列
for (j = 1; j <= col; j++)
{
printf("%c ", Board[i][j]);
}
printf("\n");
}
printf("-------------------\n");
}
4.布置雷区
用rand函数随机布置雷区,调用rand需要用srand生成随机数起点,并且srand只能生成一次,因为srand里的参数是时间戳,如果连续生成新的起点,随机数会很接近。
void setmine(char Board[Rows][Cols], int row, int col)
{
int count = Easy_count;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (Board[x][y] == '0')
{
Board[x][y] = '1';
count--;
}
}
}
5.获取选取坐标周围的雷的数量
这里我们通过循环来实现选取坐标周围8个数的和。
int mine_count(char mine[Rows][Cols], int x, int y)
{
int i = 0;
int count = 0;
for (i = -1; i <= 1; i++)
{
int j = 0;
for (j = -1; j <= 1; j++)
{
if (mine[x + i][y + j] == '1')
count++;
}
}
return count;
}
6.判断输赢
判断输赢还是独立出来好,这样增加其他拓展时更独立,不需要更改。
int Is_win(char show[Rows][Cols], int row, int col)
{
int i = 0;
int count = 0;
for (i = 1; i <= row; i++)
{
int j = 0;
for (j = 1; j <= col; j++)
{
if (show[i][j] == '*')
count++;
}
}
return count;
}
7.扫雷
到了最关键的扫雷时刻,首先判断坐标的合法性,最好这里再判断一下是不是输入了重复坐标,这里没有写。每次打印棋盘前清屏,这样更美观。
void find_mine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col)
{
int x = 0;
int y = 0;
mark(show, row, col);
while (Is_win(show, row, col)>Easy_count)
{
printf("请输入坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '0')
{
int count = mine_count(mine, x, y);
if (count == 0)
{
system("cls");
open(mine, show, x, y);
print_Board(show, row, col);
}
else
{
system("cls");
show[x][y] = count + '0';
print_Board(show, row, col);
}
}
else
{
system("cls");
print_Board(show, row, col);
printf("很遗憾,你被炸死了\n");
break;
}
}
else
{
printf("坐标已被占用,请重新输入\n");
}
}
else
{
printf("坐标不合法,请重新输入\n");
}
}
if (Is_win(show, row, col)==Easy_count)
{
printf("恭喜你,获胜了\n");
}
}
8.拓展扫雷
拓展扫雷有三个关键点
1.拓展时选取坐标没有雷
2.选取坐标周围如果有雷则不继续拓展,显示周围8个坐标的 雷的数量
3.防止死递归。
void open(char mine[Rows][Cols], char show[Rows][Cols], int x, int y)
{
int i = 0;
int count = mine_count(mine, x, y);
if (count == 0)
{
show[x][y] = ' ';
for (i = -1; i <= 1; i++)
{
int j = 0;
for (j = -1; j <= 1; j++)
{
if (show[x + i][y + j] == '*')
open(mine, show, x + i, y + j);
}
}
}
else
show[x][y] = count + '0';
}
9.标记扫雷
标记功能还是很容易实现的,这里随便用一个字符来实现标记,取消标记用初始化字符改回来就好。
void mark(char show[Rows][Cols], int row, int col)
{
int x = 0; int y = 0; int input = 0;
do
{
printf("0.开始扫雷\n");
printf("1.开始标记\n");
printf("2.取消标记\n");
scanf("%d", &input);
if (input > 0)
{
printf("请输入标记坐标:");
scanf("%d %d", &x, &y);
}
switch (input)
{
case 0:
break;
case 1:
show[x][y] = '#';
system("cls");
print_Board(show, row, col);
break;
case 2:
show[x][y] = '*';
system("cls");
print_Board(show, row, col);
break;
default:
printf("请重新输入:");
break;
}
} while (input);
}