一.扫雷游戏规则
1.使用控制台应用实现扫雷功能。
2.游戏可以选择游玩与退出,一次不过瘾继续游玩。
3.可以自定义棋盘的大小、雷的个数。
4.如果选择的位置是雷则炸死游戏结束,如果不是则显示周围雷的个数,直到剩余位置全是雷,游戏胜利。
二.扫雷游戏分析
2.1雷数组的创建
扫雷小游戏提供一个棋盘,里面随机放上几个雷,因此我们可以借助数组来存放个个方格的相关信息,现在我们规定雷用‘1’表示,非雷用‘0’表示(后面说明),然后我们选择排查的位置后,用‘n’(n为周围雷的个数)来替换原来的字符。
这样做有两个问题(9*9为例)
1.我们需要排查每个位置周围的8个元素,但是如果这个位置恰好在数组的边界,在排查的时候是不是就会越界???
2.当我们统计出所选位置周围的雷的个数后,如果恰好一个雷是不是返回的'1'和原来的‘1’(表示雷)就冲突了???
解决方法
1.我们将9*9的数组扩大到11*11,但是打印的时候只打印9*9的棋盘。
2.创建两个二维数组,一个用来存放雷的信息,一个用来存放排雷的的信息(这个数组是给玩家看的)。
2.2数组的初始化
有了两个数组之后,就要初始化里面的内容:
存放雷的数组我们全部给它初始化成‘0‘。
雷信息的数组给它全初始化成’*‘以此来呈现给玩家。
2.3棋盘的的打印
给玩家呈现棋盘就要涉及到对棋盘的打印,本质上就是对二维数组的打印。
2.4雷的埋藏
埋雷就是将存放雷的数组里面的’0‘改为’1‘,这就涉及到我们的随机数生成方法,和前面的猜数字游戏一样。
2.5雷的排除
通过循环的方法一步一步的选择排除的位置,然后根据周围雷的个数替换掉存雷信息数组的’*‘
三.扫雷代码的实现
3.1创建菜单
首先打印一个菜单,然后玩家选择是否开始游戏,接受玩家输入的信息,用switch case语句来处理输入的信息
3.2创建数组
我们希望后续可以随意更改数组的大小,如果仅仅给定义一个9或其他大小,在后续改的时候要每个相关位置都改一遍,那么有没有办法只改一次就可以完成对所有涉及到数组大小的位置都更改呢?
答案是有的:宏定义
我们把宏定义相关的内容放在游戏相关的头文件里面,由于主函数需要引game.h,所以为了避免重复我们把引库函数头文件的代码放到game.h里面
3.3对棋盘初始化
3.4打印数组
3.5埋雷
3.6排雷
四.游戏的代码
game.h
#pragma once
#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>
void init_board(char board[ROWS][COLS], int rows, int cols,char set);
void print_board(char board[ROWS][COLS], int row, int col);
void mine_set(char board[ROWS][COLS], int row, int col, int count);
void mine_sweep(char board1[ROWS][COLS], char board2[ROWS][COLS], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
int find_mind(char board[ROWS][COLS], int x, int y)
{
int i = 0;
int j = 0;
int ret = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (board[i][j] == '1')
{
ret++;
}
}
}
return ret;
}
void init_board(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;
}
}
}
void print_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; 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 mine_set(char board[ROWS][COLS], int row, int col, int count)
{
while (count)
{
int x = rand() % row + 1;//1-9
int y = rand() % col + 1;//1-9
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
void mine_sweep(char board1[ROWS][COLS], char board2[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = ROW*COL-COUNT;
while (win)
{
printf("请输入坐标\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
{
if (board2[x][y] == '*')
{
if (board1[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
print_board(board1, ROW, COL);
break;
}
else
{
int ret = find_mind(board1, x, y);
board2[x][y] = '0' + ret;
print_board(board2, ROW, COL);
win--;
}
}
else
{
printf("该位置被排查过,请重新输入\n");
}
}
else
{
printf("输入错误,请重新输入\n");
}
}
if (win == 0)
{
printf("恭喜你排雷成功\n");
print_board(board1, ROW, COL);
}
}
mine_sweeping.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
printf("*************************\n");
printf("**1.paly 0.exit**\n");
printf("*************************\n");
}
void game()
{
//创建存放雷的数组
char board1[ROWS][COLS] = { 0 };
//创建排雷信息的数组
char board2[ROWS][COLS] = { 0 };
//对棋盘初始化
init_board(board1, ROWS, COLS, '0');
init_board(board2, ROWS, COLS, '*');
//打印棋盘
//print_board(board1, ROW, COL);
print_board(board2, ROW, COL);
//埋雷
mine_set(board1, ROW, COL, COUNT);
print_board(board1, ROW, COL);
mine_sweep(board1, board2, ROW, COL);
}
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();
return 0;
}