文章目录
1.题目描述
问题描述:
扫雷游戏
基本要求:
(1)完成棋盘的初始化并在标准显示器中显示
(2)通过输入行列值确定用户输入
(3)游戏进行给出提示信息
(4)给出游戏的测试程序。
2.设计思路分析
3.设计程序流程图
用户会首先看到一个菜单,选择1进入游戏同时系统打印出10*10的扫雷界面,选择2退出游戏,如果进入游戏,用户输入所要选择的行列值,如果扫中雷,直接结束游戏,选中非雷区,则显示周围雷的个数,用户重复上述过程接着玩游戏,直至用户输或者赢。
扫雷逻辑比较简单,思路也很清晰,按照思路把各个功能封装到函数里,一个扫雷的程序就完成了。
4.数据结构定义
1、定义1212的二维数组用来存放雷区
2、定义1010的二维数组显示用户所见的扫雷
5.源程序
5.1 自定义lei.h头文件
#ifndef _LEI_H_
#define _LEI_H_
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <time.h>
#pragma warning(disable:4996)
#define ROW 12 //雷区行数
#define COL 12 //雷区列数
#define MINES 20
void Menu(); //用户菜单
void Game(); //游戏显示界面初始化
void SetMine(char mine_board[][COL], int row, int col); //布雷
void PlayGame(char show_board[][COL], char mine_board[][COL], int row, int col); //用户玩游戏
int GetMineNum(char mine_board[][COL], int i, int j); //计算雷的个数
void ShowBoard(char show_board[][COL], int row, int col); //扫雷显示界面
#endif
5.2 lei.c核心代码书写。
对定义的每个函数进行具体功能的编写,写之前明确各个函数实现的功能。
#define _CRT_SECURE_NO_WARNINGS 1
#include "lei.h"
void Menu() //用户菜单
{
printf("###########################################\n");
printf("## 1. Play 2. Exit ##\n");
printf("###########################################\n");
printf("Please Select:> ");
}
static int GetIndex(int start, int end) //得到雷坐标 static修饰 该函数只在该文件内部使用
{
return rand() % (end - start + 1) + start; //rand()%(m) 随机生成0到m-1
}
void SetMine(char mine_board[][COL], int row, int col) //布雷
{
srand((unsigned long)time(NULL)); //设置随机种子 time保证每一次都不一样
int mine_num = MINES; //布雷个数MINES
while (mine_num)
{
int i_index = GetIndex(1, col - 2); //在10*10内布雷
int j_index = GetIndex(1, col - 2);
if (mine_board[i_index][j_index] == '0') //判断雷位置合法性 此位置是否布雷
{
mine_board[i_index][j_index] = '1';
mine_num--;
}
}
}
int GetMineNum(char mine_board[][COL], int i, int j)//计算周围雷的个数
{
return mine_board[i - 1][j - 1] + mine_board[i - 1][j] + \
mine_board[i - 1][j + 1] + mine_board[i][j - 1] + \
mine_board[i][j + 1] + mine_board[i + 1][j - 1] + \
mine_board[i + 1][j] + mine_board[i + 1][j + 1] - 8 * '0';
//-8 * '0'是为了转化成可以直接使用的雷的个数
}
void ShowBoard(char show_board[][COL], int row, int col) //扫雷显示界面
{
int i = 1;
int j = 1;
printf(" ");
//10*10 打印 1 2 3 4 5 6 7 8 9 10
for (; i <= col - 2; i++){
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= col - 1; i++){
printf("----");
}
printf("\n");
for (i = 1; i <= row - 2; i++){
printf("%2d|", i);
for (j = 1; j <= col - 2; j++){
printf(" %c |", show_board[i][j]);
}
printf("\n");
int k = 1;
for (; k <= col - 1; k++){
printf("----");
}
printf("\n");
}
}
void PlayGame(char show_board[][COL], char mine_board[][COL], int row, int col) //用户玩游戏
{
int i = 0;
int j = 0;
int total = (ROW - 2)*(COL - 2);
while (1){
ShowBoard(show_board, row, col);
printf("Please Enter Pos<x, y>: ");
scanf("%d%d", &i, &j);
if (i >= 1 && i <= row - 2 && j >= 1 && j <= col - 2) //输入是否合法
{
if (mine_board[i][j] == '0'){ //计算周围雷的个数
int num = GetMineNum(mine_board, i, j);
show_board[i][j] = num + '0'; //转化成字符
total--;
}
else{ //扫中雷了
ShowBoard(mine_board, row, col);
printf("Game Over! You Lose :(!\n");
break;
}
}
else{
printf("Enter Error, Try Again!\n");
continue;
}
if (total == MINES){ //用户均未扫中雷 用户赢了
printf("You Win:)\n");
break;
}
}
}
void Game()//游戏显示界面初始化
{
char show_board[ROW][COL]; //显示界面
char mine_board[ROW][COL]; //雷界面
memset(show_board, '*', sizeof(show_board)); //memset() 按字节为单位初始化
memset(mine_board, '0', sizeof(mine_board));
SetMine(mine_board, ROW, COL); //布雷
PlayGame(show_board, mine_board, ROW, COL); //用户玩游戏
}
5.3 main.c主函数的书写
#define _CRT_SECURE_NO_WARNINGS 1
#include "lei.h"
int main()
{
int select = 0;
int quit = 0;
while (!quit){
Menu(); //用户菜单
scanf("%d", &select);
switch (select){
case 1:
Game();
break;
case 2:
printf("I Am Quit!\n");
quit = 1;
break;
default:
printf("Select Error! Try Again!\n");
break;
}
}
return 0;
}
5.4 注意
1、扫雷主要使用二维数组来定义数据结构,存储数据,增强了数组的应用熟练度。static int GetIndex(int start, int end)
函数被static修饰,表示该函数只在该文件内部使用。
2、
srand((unsigned long)time(NULL));
return rand() % (end - start + 1) + start;
程序中使用了srand和rand,srand 初始化随机种子,rand 生成随机数。
6.运行结果
1、运行程序的初始界面
2、选择1开始游戏
3、开始游戏,输入您想要点击的位置(行和列),知道赢得游戏,或者输掉游戏,然后选择1继续游戏,或者选择2退出游戏
7.存在问题分析
1.一旦游戏开始必须等用户输掉才可以结束游戏,要想退出必须关掉程序,用户体验不佳。
改进:程序中加入break,在每一次用户输入后加入if判断,提示用户是否要继续玩游戏,方便随时退出游戏。
2.游戏耗时太长,如果在用户运气特别好的情况下,要选择80次才可以胜利。
改进:布雷布多一点或者用户选择10次直接胜利。