1、游戏介绍
一款基于扫雷的新型排位游戏(ps:目前只有单机版,仅支持键盘输入数据),只要通过排位晋段赛,即可获得对应的称号。(ps:目前仅提供白银、黄金、钻石、大师等四个段位晋级赛,分别对应10颗、20颗、30颗、50颗雷)
2、玩法说明
版权说明
首先根据主菜单提示输入1开始游戏,
接下来根据个人实力选择要冲击的段位,
以冲击白银段位为例,下图所示的10x10棋盘中设置了10颗雷,
根据提示选择是否标记当前位置的雷,或者排查当前位置下面是否有雷,
选择排查地雷,并在10x10棋盘上任选一个坐标输入(4,7),
这里实现了展开一片非雷区域的功能,由于坐标(3,10)上不再是*,这里再次输入坐标(3,10),会提示重新输入,
由于(3,10)位置上数字为0,表示以(3,10)为中心,周围8个方向上没有雷,所以尝试输入坐标(2,10),
发现(2,10)位置是1,表示周围有1个雷,多次尝试输入其他坐标排雷,直到可以确定某一位置必然是雷,
由于(1,9)、(2,9)、(2,10)三个位置均为1,那么(1,10)必为雷,对其进行标记(ps:标记为?),
当然,也支持取消标记,
如果输入坐标不合法(ps:输入除数字外的字符),游戏因异常被终止,
如果已经标记了某个位置(确定该位置就是雷),
后来误操作,选择了排查雷,然后输入了上图中被标记位置的坐标(1,1),这仍然会被炸死,谁让你乱改呢?哈哈哈哈哈……
省略若干步骤,直到标记完所有的雷,游戏结束,并且打印雷的分布图,
若输入坐标恰好是雷的坐标,则游戏结束,输出雷的分布图,并且蜂鸣器响,这里用蜂鸣器的响声模拟爆炸。
3、功能介绍
a.为提升游戏体验,保证玩家第一次随机输入排雷坐标不被炸死;
b.展开非雷区域;
c.标记雷;
d.取消标记雷;
e.不小心踩雷,蜂鸣器响。
4、方案设计
关于游戏主菜单、冲段等级菜单以及扫雷游戏菜单等这里就不一一叙述了,接下来讲讲怎么开发这款游戏。首先需要说明的是,游戏界面显示的是'*',真正存放雷的界面显示'0'和'1',标记用'?'表示,接下来为了方便讲解,先给出MineSweep.h,该头文件包含了一些宏定义以及函数的声明。
# ifndef __MINESWEEP_H__ # define __MINESWEEP_H__ //真正存放雷的行数 # define MINE_REAL_ROW 10 //真正存放雷的列数 # define MINE_REAL_COL 10 //真正存放雷的棋盘的行数 # define BOARD_REAL_ROW 10 //真正存放雷的棋盘的列数 # define BOARD_REAL_COL 10 //显示雷数组的行 # define MINE_DISPLAY_ROW MINE_REAL_ROW+2 //显示雷数组的列 # define MINE_DISPLAY_COL MINE_REAL_COL+2 //显示存放雷棋盘数组的行 # define BOARD_DISPLAY_ROW BOARD_REAL_ROW+2 //显示存放雷棋盘数组的列 # define BOARD_DISPLAY_COL BOARD_REAL_COL+2 //增加一行雷 # define MINE_ONE_ROW 1 //增加一列雷 # define MINE_ONE_COL 1 //白银段位设置10个雷 # define MINE_SILVER_COUNT 10 //黄金段位设置20个雷 # define MINE_GOLDEN_COUNT 20 //钻石段位设置30个雷 # define MINE_DIAMOND_COUNT 30 //大师段位设置50个雷 # define MINE_MASTER_COUNT 50 //随机设置雷的存放位置 void SetMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int rank_num); //第一次遇到雷后移动该雷的位置到其他位置 void MoveMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int x, int y); //显示雷的分布界面 void DisplayMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL]); //显示游戏棋盘的界面 void DisplayBoard(char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL]); //统计雷的个数 int GetMineCount(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int x, int y); //统计棋盘中标记地雷的个数 int GetSignCount(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL]); //展开没有雷的区域 void SpreadNoMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y); //标记雷 void SignMine(char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y); //取消标记雷 void NoSignMine(char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y); //玩扫雷游戏 void PlayGame(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int rank); #endif //__MINESWEEP_H__
关于棋盘选择10x10 以及 12x12
10x10的数组存放雷的棋盘数组以及雷的数组,12x12的数组是在10x10的数组基础上增加了两圈,最外面一圈存放一堆数字,为了更好的显示各个位置的坐标,由于真正存放雷的数组的最外层显示其周围雷的数量不方便,这里选择增加一圈,便于对循环的控制。
关于初始化数组
定义好数组后,用库函数memset(别忘了引头文件<string.h> or <memory.h>)对其初始化。
//定义雷数组 char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL] = {0}; //定义游戏棋盘数组 char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL] = {0}; //初始化雷数组 memset(mine, '0', sizeof(mine)); //初始化游戏棋盘数组 memset(board, '*', sizeof(board));
关于设置雷的存放位置
利用随机数种子产生随机数存放到雷数组中,当然还得传入冲段等级对应的雷的数量。
/* * 函数名称:SetMine * * 函数功能:随机设置雷的位置 * * 入口参数:mine, rank_num * * 出口参数:void * * 返回类型:void */ void SetMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int rank_num) { int x = 0; int y = 0; while (rank_num) { x = (rand() % MINE_REAL_ROW) + MINE_ONE_ROW; y = (rand() % MINE_REAL_COL) + MINE_ONE_COL; if ('0' == mine[x][y]) { mine[x][y] = '1'; rank_num--; } else { ; } } return; }
关于显示棋盘和雷的界面
这里就不赘述了,详情见源代码。
关于第一次踩雷不被炸死
注意:这里的第一次踩雷是指第一次输入排雷坐标(ps:在玩游戏过程中,应该设置一个标志位来检测是否为第一次输入排雷坐标),而不是说输入几次排雷坐标没被炸死,再次输入一个排雷坐标被炸死的情况。理解这点很重要,要不然每次游戏过程中的第一次踩雷都将被移动到非雷的位置,这是错误的。
设计思路:如果当前位置是雷,那么将这个雷的位置移动到其他非雷的位置(ps:只移动一个雷的位置)。
/* * 函数名称:MoveMine * * 函数功能:若第一次遇到雷,则移动该雷的位置到其他非雷的位置 * * 入口参数:mine, x, y * * 出口参数:void * * 返回类型:void */ void MoveMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int x, int y) { if ('1' == mine[x][y]) { mine[x][y] = '0'; while (1) { int new_x = (rand() % MINE_REAL_ROW) + MINE_ONE_ROW; int new_y = (rand() % MINE_REAL_COL) + MINE_ONE_COL; if ((new_x != x) && (new_y != y) && ('1' != mine[new_x][new_y])) { mine[new_x][new_y] = '1'; break; } else { ; } } } else { ; } return; }
关于统计雷的个数
以当前位置为中心,查看其周围8个方向是否有雷存在,如果有,则计数器加1,反之则为0。而雷的显示界面只有'0'和'1',显然这是字符,要想得到数字,只需减去'0'即可。(ps: 想得到数字1,只需要'1' - '0'即可,要想得到数字2,只需要'2' - '0'即可,这是因为数字对应的ASCII码是连续的)
/* * 函数名称:GetMineCount * * 函数功能:统计雷的个数 * * 入口参数:mine, x, y * * 出口参数:void * * 返回类型:int */ int GetMineCount(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int x, int y) { return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1] + mine[x + 1][y] + mine[x + 1][y - 1] + mine[x][y - 1] - 8 * '0'); }
关于统计棋盘中标记地雷的个数
遍历真正存放雷的棋盘数组,若当前位置是雷,并且该雷被标记,则计数器加1。
/* * 函数名称:GetSignCount * * 函数功能:统计棋盘中标记地雷的个数 * * 入口参数:mine, board * * 出口参数:mark_count * * 返回类型:int */ int GetSignCount(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL]) { int row = 0; int col = 0; int mark_count = 0; for (row=1; row<=BOARD_REAL_ROW; row++) { for (col=1; col<=BOARD_REAL_COL; col++) { if (('1' == mine[row][col]) && ('?' == board[row][col])) { mark_count++; } else { ; } } } return mark_count; }
关于展开没有雷的区域
若该位置没有雷,则展开该位置一圈的非雷区域,横坐标从x-1遍历到x+1,纵坐标从y-1遍历到y+1。
/* * 函数名称:SpreadNoMine * * 函数功能:展开没有雷的区域 * * 入口参数:mine, board, x, y * * 出口参数:void * * 返回类型:void */ void SpreadNoMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y) { int row = 0; int col = 0; char ret = GetMineCount(mine, x, y) + '0'; if ('0' == ret) { for (row=x-1; row<=x+1; row++) { for (col=y-1; col<=y+1; col++) { board[row][col] = GetMineCount(mine, row, col) + '0'; } } } else { ; } return; }
上述展开只能实现一圈的展开,因此使用递归的方式去实现展开。
void SpreadNoMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y) { if ((x >= 1) && (x <= MINE_REAL_ROW) && (y >= 1) && (y <= MINE_REAL_COL)) { if (0 == GetMineCount(mine, x, y)) { board[x][y] = '0'; if ('*' == board[x - 1][y - 1]) { SpreadNoMine(mine, board, x-1, y-1); } if ('*' == board[x - 1][y]) { SpreadNoMine(mine, board, x-1, y); } if ('*' == board[x + 1][y + 1]) { SpreadNoMine(mine, board, x+1, y+1); } if ('*' == board[x][y - 1]) { SpreadNoMine(mine, board, x, y-1); } if ('*' == board[x][y + 1]) { SpreadNoMine(mine, board, x, y+1); } if ('*' == board[x + 1][y - 1]) { SpreadNoMine(mine, board, x+1, y-1); } if ('*' == board[x + 1][y]) { SpreadNoMine(mine, board, x+1, y); } if ('*' == board[x + 1][y + 1]) { SpreadNoMine(mine, board, x+1, y+1); } } else { ; } } else { ; } return; }
关于标记雷和取消标记雷
这个实现起来比较简单,只要替换掉游戏显示棋盘上的'*'即可。
/* * 函数名称:SignMine * * 函数功能:标记雷 * * 入口参数:board, x, y * * 出口参数:void * * 返回类型:void */ void SignMine(char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y) { if ('*' == board[x][y]) { board[x][y] = '?'; } else { ; } return; } /* * 函数名称:NoSignMine * * 函数功能:取消标记雷 * * 入口参数:board, x, y * * 出口参数:void * * 返回类型:void */ void NoSignMine(char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y) { if ('?' == board[x][y]) { board[x][y] = '*'; } else { ; } return; }
关于玩扫雷游戏细节
每次开始玩游戏前,先选择是否要标记雷或者排查雷,这里通过扫雷游戏菜单来进行选择,除此之外,对于重复输入的坐标,以及输入非数字的字符等进行了相应的处理,详情见源代码。
5、源代码
附上源代码,欢迎各位大佬交流,写的不好或者不对的地方麻烦给出改进意见,争取作出一款可玩性强的游戏。
MineSweep.c
#define _CRT_SECURE_NO_WARNINGS 1 /* * Copyright (c) 2018, code farmer from sust * All rights reserved. * * 文件名称:MineSweep.c * 功能:扫雷游戏内部实现细节 * 1.第一次踩雷不炸死 * 2.周围没有雷实现展开 * 3.实现标记雷(用?标记) * 当前版本:V3.0 * 作者:sustzc * 完成日期:2018年4月13日12:44:33 */ # include <stdio.h> # include <stdlib.h> # include <assert.h> # include "MineSweep.h" /* * 函数名称:SetMine * * 函数功能:随机设置雷的位置 * * 入口参数:mine, rank_num * * 出口参数:void * * 返回类型:void */ void SetMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int rank_num) { int x = 0; int y = 0; while (rank_num) { x = (rand() % MINE_REAL_ROW) + MINE_ONE_ROW; y = (rand() % MINE_REAL_COL) + MINE_ONE_COL; if ('0' == mine[x][y]) { mine[x][y] = '1'; rank_num--; } else { ; } } return; } /* * 函数名称:MoveMine * * 函数功能:若第一次遇到雷,则移动该雷的位置到其他非雷的位置 * * 入口参数:mine, x, y * * 出口参数:void * * 返回类型:void */ void MoveMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int x, int y) { if ('1' == mine[x][y]) { mine[x][y] = '0'; while (1) { int new_x = (rand() % MINE_REAL_ROW) + MINE_ONE_ROW; int new_y = (rand() % MINE_REAL_COL) + MINE_ONE_COL; if ((new_x != x) && (new_y != y) && ('1' != mine[new_x][new_y])) { mine[new_x][new_y] = '1'; break; } else { ; } } } else { ; } return; } /* * 函数名称:DisplayMine * * 函数功能:显示雷的分布界面 * * 入口参数:mine * * 出口参数:void * * 返回类型:void */ void DisplayMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL]) { int i = 0; int j = 0; printf(" "); for(i=1; i<=MINE_REAL_ROW; i++) { printf(" %d ", i); } printf("\n"); for(i=1; i<=MINE_REAL_ROW; i++) { printf("%2d", i); for(j=1; j<=MINE_REAL_COL; j++) { printf(" %c ", mine[i][j]); } printf("\n"); } return; } /* * 函数名称:DisplayBoard * * 函数功能:显示游戏棋盘界面 * * 入口参数:board * * 出口参数:void * * 返回类型:void */ void DisplayBoard(char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL]) { int i = 0; int j = 0; printf(" "); for(i=1; i<=BOARD_REAL_ROW; i++) { printf(" %d ", i); } printf("\n"); for(i=1; i<=BOARD_REAL_ROW; i++) { printf("%2d", i); for(j=1; j<=BOARD_REAL_COL; j++) { printf(" %c ", board[i][j]); } printf("\n"); } return; } /* * 函数名称:GetMineCount * * 函数功能:统计雷的个数 * * 入口参数:mine, x, y * * 出口参数:void * * 返回类型:int */ int GetMineCount(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], int x, int y) { return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1] + mine[x + 1][y] + mine[x + 1][y - 1] + mine[x][y - 1] - 8 * '0'); } /* * 函数名称:GetSignCount * * 函数功能:统计棋盘中标记地雷的个数 * * 入口参数:mine, board * * 出口参数:mark_count * * 返回类型:int */ int GetSignCount(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL]) { int row = 0; int col = 0; int mark_count = 0; for (row=1; row<=BOARD_REAL_ROW; row++) { for (col=1; col<=BOARD_REAL_COL; col++) { if (('1' == mine[row][col]) && ('?' == board[row][col])) { mark_count++; } else { ; } } } return mark_count; } /* * 函数名称:SpreadNoMine * * 函数功能:展开没有雷的区域 * * 入口参数:mine, board, x, y * * 出口参数:void * * 返回类型:void */ void SpreadNoMine(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y) { if ((x >= 1) && (x <= MINE_REAL_ROW) && (y >= 1) && (y <= MINE_REAL_COL)) { if (0 == GetMineCount(mine, x, y)) { board[x][y] = '0'; if ('*' == board[x - 1][y - 1]) { SpreadNoMine(mine, board, x-1, y-1); } if ('*' == board[x - 1][y]) { SpreadNoMine(mine, board, x-1, y); } if ('*' == board[x + 1][y + 1]) { SpreadNoMine(mine, board, x+1, y+1); } if ('*' == board[x][y - 1]) { SpreadNoMine(mine, board, x, y-1); } if ('*' == board[x][y + 1]) { SpreadNoMine(mine, board, x, y+1); } if ('*' == board[x + 1][y - 1]) { SpreadNoMine(mine, board, x+1, y-1); } if ('*' == board[x + 1][y]) { SpreadNoMine(mine, board, x+1, y); } if ('*' == board[x + 1][y + 1]) { SpreadNoMine(mine, board, x+1, y+1); } } else { ; } } else { ; } return; } /* * 函数名称:SignMine * * 函数功能:标记雷 * * 入口参数:board, x, y * * 出口参数:void * * 返回类型:void */ void SignMine(char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y) { if ('*' == board[x][y]) { board[x][y] = '?'; } else { ; } return; } /* * 函数名称:NoSignMine * * 函数功能:取消标记雷 * * 入口参数:board, x, y * * 出口参数:void * * 返回类型:void */ void NoSignMine(char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int x, int y) { if ('?' == board[x][y]) { board[x][y] = '*'; } else { ; } return; } /* * 函数名称:GameMenu * * 函数功能:扫雷游戏菜单 * * 入口参数:void * * 出口参数:select * * 返回类型:int */ int GameMenu(void) { int select = 0; printf("***********************************\n"); printf("********** 1 标记地雷 ***********\n"); printf("********** 2 取消标记 ***********\n"); printf("********** 3 排查地雷 ***********\n"); printf("***********************************\n"); printf("select>"); assert(1 == scanf("%d", &select)); return select; } /* * 函数名称:PlayGame * * 函数功能:玩扫雷游戏 * * 入口参数:mine, board, rank_num * * 出口参数:void * * 返回类型:void */ void PlayGame(char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL], char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL], int rank_num) { int count = 0; int ret = 0; int select = 0; //第一次遇到雷 int first_mine = 0; while(1) { select = GameMenu(); switch(select) { case 1: { int x = 0; int y = 0; printf("请输入标记坐标x y(x,y之间用空格隔开):"); //若没有输入数字,则异常退出 assert(2 == (scanf("%d %d", &x, &y))); if (((1 <= x) && (x <= MINE_REAL_ROW)) && ((1 <= y) && (y <= MINE_REAL_COL))) { if ('?' == board[x][y]) { printf("坐标重复,该位置已标记,请重新输入!\n"); } else { SignMine(board, x, y); DisplayBoard(board); } } else { printf("输入坐标有误!\n"); } } break; case 2: { int x = 0; int y = 0; printf("请输入取消标记坐标x y(x,y之间用空格隔开):"); //若没有输入数字,则异常退出 assert(2 == (scanf("%d %d", &x, &y))); if (((1 <= x) && (x <= MINE_REAL_ROW)) && ((1 <= y) && (y <= MINE_REAL_COL))) { if ('*' == board[x][y]) { printf("坐标重复,已取消标记,请重新输入!\n"); } else { NoSignMine(board, x, y); DisplayBoard(board); } } else { printf("输入坐标有误!\n"); } } break; case 3: { int x = 0; int y = 0; //输入坐标 printf("请输入坐标x y(x,y之间用空格隔开):"); //若没有输入数字,则异常退出 assert(2 == (scanf("%d %d", &x, &y))); //坐标合法性判断 if (((1 <= x) && (x <= MINE_REAL_ROW)) && ((1 <= y) && (y <= MINE_REAL_COL))) { if ('1' == mine[x][y]) { //保证第一次移动位置后就不会再移动雷的位置 if ((0 == count) && (0 == first_mine)) { MoveMine(mine, x, y); //DisplayMine(mine); DisplayBoard(board); //first_mine任意置为一个数字,只要不是0即可 //确保不会再次移动雷的位置 first_mine = 1; } else { //游戏结束,蜂鸣器响 printf("你被雷炸死了!\a\a\a\a\a\n"); printf("雷的分布界面如下!\n"); DisplayMine(mine); exit(0); } } else if (('*' != board[x][y]) && ('?' != board[x][y])) { printf("坐标重复,请重新输入!\n"); } else { //防止非第一次输入排雷坐标时移动某个雷的位置 first_mine = 1; ret = GetMineCount(mine, x, y); board[x][y] = ret + '0'; //展开非雷区域 SpreadNoMine(mine, board, x, y); DisplayBoard(board); //被标记的个数 count = GetSignCount(mine, board); //标记数等于设置的雷的数量 if (rank_num == count) { printf("恭喜你,晋段成功!\n"); printf("雷的分布界面如下!\n"); DisplayMine(mine); exit(0); } else { ; } } } else { printf("输入坐标有误!\n"); } } break; default: printf("输入有误,请重新输入!\n"); break; } } return; }
test.c
#define _CRT_SECURE_NO_WARNINGS 1 /* * Copyright (c) 2018, code farmer from sust * All rights reserved. * * 文件名称:test.c * 功能:扫雷游戏主程序(支持段位选择) * * 当前版本:V3.0 * 作者:sustzc * 完成日期:2018年4月13日12:44:20 */ # include <stdio.h> # include <stdlib.h> # include <string.h> # include <assert.h> # include <time.h> # include "MineSweep.h" /* * 函数名称:MainMenu * * 函数功能:游戏主菜单显示 * * 入口参数:void * * 出口参数:choose * * 返回类型:int */ int MainMenu(void) { int choose = 0; printf("********************************\n"); printf("******欢迎来到扫雷冲段大赛******\n"); printf("********** 1 开始游戏 **********\n"); printf("********** 2 版权说明 **********\n"); printf("********** 0 退出游戏 **********\n"); printf("********************************\n"); printf("choose>"); assert(1 == scanf("%d", &choose)); return choose; } /* * 函数名称:CopyRight * * 函数功能:游戏版权说明 * * 入口参数:void * * 出口参数:void * * 返回类型:void */ void CopyRight(void) { printf("**************************************************\n"); printf("*** Copyright (c) 2018, code farmer from sust. ***\n"); printf("************** All rights reserved. **************\n"); printf("**************************************************\n"); printf("\n"); return; } /* * 函数名称:RankMenu * * 函数功能:冲段等级菜单显示 * * 入口参数:void * * 出口参数:select * * 返回类型:int */ int RankMenu(void) { int select = 0; printf("***********************************\n"); printf("******* 请选择你要冲击的段位 ******\n"); printf("********** 1 白银段位 ***********\n"); printf("********** 2 黄金段位 ***********\n"); printf("********** 3 钻石段位 ***********\n"); printf("********** 4 大师段位 ***********\n"); printf("********** 0 返回上层 ***********\n"); printf("***********************************\n"); printf("select>"); assert(1 == scanf("%d", &select)); return select; } /* * 函数名称:SilverGame * * 函数功能:白银晋段赛 * * 入口参数:void * * 出口参数:void * * 返回类型:void */ void SilverGame(void) { //定义雷数组 char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL] = {0}; //定义游戏棋盘数组 char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL] = {0}; //初始化雷数组 memset(mine, '0', sizeof(mine)); //初始化游戏棋盘数组 memset(board, '*', sizeof(board)); //设置雷 SetMine(mine, MINE_SILVER_COUNT); //显示雷的分布界面 //DisplayMine(mine); //显示扫雷游戏棋盘界面 DisplayBoard(board); //白银晋段赛 PlayGame(mine, board, MINE_SILVER_COUNT); return; } /* * 函数名称:GoldenGame * * 函数功能:黄金晋段赛 * * 入口参数:void * * 出口参数:void * * 返回类型:void */ void GoldenGame(void) { //定义雷数组 char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL] = {0}; //定义游戏棋盘数组 char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL] = {0}; //初始化雷数组 memset(mine, '0', sizeof(mine)); //初始化游戏棋盘数组 memset(board, '*', sizeof(board)); //设置雷 SetMine(mine, MINE_GOLDEN_COUNT); //显示雷的分布界面 //DisplayMine(mine); //显示扫雷游戏棋盘界面 DisplayBoard(board); //黄金晋段赛 PlayGame(mine, board, MINE_GOLDEN_COUNT); return; } /* * 函数名称:DiamondGame * * 函数功能:钻石晋段赛 * * 入口参数:void * * 出口参数:void * * 返回类型:void */ void DiamondGame(void) { //定义雷数组 char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL] = {0}; //定义游戏棋盘数组 char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL] = {0}; //初始化雷数组 memset(mine, '0', sizeof(mine)); //初始化游戏棋盘数组 memset(board, '*', sizeof(board)); //设置雷 SetMine(mine, MINE_DIAMOND_COUNT); //显示雷的分布界面 //DisplayMine(mine); //显示扫雷游戏棋盘界面 DisplayBoard(board); //钻石晋段赛 PlayGame(mine, board, MINE_DIAMOND_COUNT); return; } /* * 函数名称:MasterGame * * 函数功能:大师晋段赛 * * 入口参数:void * * 出口参数:void * * 返回类型:void */ void MasterGame(void) { //定义雷数组 char mine[MINE_DISPLAY_ROW][MINE_DISPLAY_COL] = {0}; //定义游戏棋盘数组 char board[BOARD_DISPLAY_ROW][BOARD_DISPLAY_COL] = {0}; //初始化雷数组 memset(mine, '0', sizeof(mine)); //初始化游戏棋盘数组 memset(board, '*', sizeof(board)); //设置雷 SetMine(mine, MINE_MASTER_COUNT); //显示雷的分布界面 //DisplayMine(mine); //显示扫雷游戏棋盘界面 DisplayBoard(board); //大师晋段赛 PlayGame(mine, board, MINE_MASTER_COUNT); return; } /* * 函数名称:main * * 函数功能:游戏主程序 * * 入口参数:void * * 出口参数:0 * * 返回类型:int */ int main(void) { int choose = 0; int select = 0; srand((unsigned int)time(NULL)); do { choose = MainMenu(); last: switch(choose) { case 0: printf("退出游戏!\n"); break; case 1: select = RankMenu(); switch (select) { case 1: SilverGame(); break; case 2: GoldenGame(); break; case 3: DiamondGame(); break; case 4: MasterGame(); break; case 0: break; default: printf("输入有误,请重新输入!\n"); goto last; break; } break; case 2: CopyRight(); exit(1); default: printf("输入有误,请重新输入!\n"); break; } }while(choose); return 0; }
5、个人感触
目前该游戏更新到了第三版,也仅仅实现了一丢丢的功能,并且仍有很多bug。以后有机会的话,想利用MFC或者QT开发个图形界面玩一玩,起码鼠标可以用,黑框框的程序实在是不忍直视啊!!!关于后续版本,想尝试下统计每一局比赛的积分,当然这需要一套算法(ps:连胜次数越多,加分越多),并且加入惩罚机制(ps:比如需要在规定时间内排查雷,如果超时,会缩短每次排雷的时间,时间到了也算游戏结束),除此之外加入网络对战也可以哦!(ps:补充点socket编程的知识,一方布置雷,另一方排雷)。