// 扫雷程序 C-Free编译通过
// by: Ricky 2012-9-20
// 文件名: mine.cpp
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#define OUTPUT_STR(str) printf(str)
#define INPUT_STR(str) gets(str)
#define CLRSCREEN system("cls") // 清屏
#define PAUSESCREEN system("pause") // 屏幕暂停
enum winorfail {RUNING, WIN, FAIL}; // 输赢结果
enum check_state {UNKNOW, NO, YES, DOUBT}; // 地雷被扫的状态
enum mine_in {Y, N}; // 此坑是否真的有地雷
typedef struct _mine // 地雷坑 的结构体定义
{
int x,y; // 地雷坐标
check_state CheckState; // 当前地雷被扫的状态
mine_in MineIn; // 此坑是否真的有地雷
int MineNumAround; // 周围地雷数目
winorfail (*ChangeState)(struct _mine *ThisMine, check_state CheckState);// 改变状态函数
void (*MoreAct)(void *p); // 预留功能接口 [接口预留]
} MineStruct, *pMineStruct;
enum game_grade {USER_DEFINED, EASY, MIDDLE, HARD}; // 难度等级:自定义/易/中/难
enum game_state {RUN, PAUSE, STOP}; // 程序状态:运行/暂停/停止
typedef void* histrylist; // 记录玩家英雄榜的链表[预留]
typedef struct _panel // 阵地的结构体定义
{
pMineStruct *Mine; // 地雷表: x*y个雷坑
game_grade Grade; // 难度等级
int x, y; // 阵地的宽和高
int MinesNum; // 阵地内的地雷数目
int CatchMineNum; // 玩家找到的雷数
game_state GameState; // 当前游戏状态
winorfail WinOrFail; // 输赢情况
int TimeOutSeconds; // 超时等待的秒数 [预留]
histrylist Histry; // 玩家英雄榜 [预留]
char* BackgroundArgv; // 背景元素Color、Music等 [预留]
void (*InitPanel)(void); // 初始化函数
void (*DestroyPanel)(void); // 销毁函数
void (*ChangeState)(game_state state); // 改变状态函数
void (*GetCtrl)(void); // 接收玩家的控制命令
void (*Output)(void); // 输出
void (*OpenBlankMine)(int x,int y); // 打开周围的一片无雷区
void (*ChangeBackground)(char* Argv); // 改变背景函数 [预留]
void (*MoreAct)(void *p); // 预留功能接口 [接口预留]
} Panel, *pPanel;
Panel panel; // 阵地(面板)的全局对象
char *info_str[]=
{
"扫雷吧!\n游戏说明:\n确定(x,y)位置无雷,输入:x y N\n确定(x,y)位置有雷,输入:x y Y\n怀疑(x,y)位置有雷,输入:x y ?\n",
"当前雷区大小: %d*%d, 地雷数%d\n"
};
winorfail ChangeMineStateFun(pMineStruct ThisMine, check_state CheckState)
{
if(CheckState == NO)
{
if(ThisMine->MineIn == N)
ThisMine->CheckState = NO;
else if(ThisMine->MineIn == Y)
return FAIL;
}
else
ThisMine->CheckState = CheckState;
return RUNING;
}
// 打开周围空白雷坑
void OpenBlankMineFun(int x,int y)
{
if (x < 0 || x >= panel.x || y < 0 || y >= panel.y)//越界
return;
if(panel.Mine[x][y].MineNumAround > 0)
{
panel.Mine[x][y].CheckState = NO;
return;
}
if(panel.Mine[x][y].CheckState == NO)//雷坑已打开
return;
if (panel.Mine[x][y].MineIn == N)
{
panel.Mine[x][y].CheckState = NO;//先标记,否则递归会死循环
OpenBlankMineFun(x - 1, y - 1);
OpenBlankMineFun(x - 1, y);
OpenBlankMineFun(x - 1, y + 1);
OpenBlankMineFun(x + 1, y - 1);
OpenBlankMineFun(x + 1, y);
OpenBlankMineFun(x + 1, y + 1);
OpenBlankMineFun(x, y + 1);
OpenBlankMineFun(x, y - 1);
}
return;
}
void OutPutFun(void)
{
CLRSCREEN;
OUTPUT_STR(info_str[0]); // 游戏说明字符串
char strTemp[30] = {0};
sprintf(strTemp, info_str[1], panel.x, panel.y, panel.MinesNum); // 输出雷区信息
OUTPUT_STR(strTemp);
// 检测并输出
int tempWinOrFail = 1; // 假设赢
OUTPUT_STR(" x\t");
for(int x=0; x<panel.x; x++)
{
char strTemp[5] = {0};
sprintf(strTemp, "%d ", x%10);
OUTPUT_STR(strTemp);
}
OUTPUT_STR("\ny\n\n");
for(int y=0; y<panel.y; y++)
{
char strTemp[5] = {0};
sprintf(strTemp, "%d:\t", y);
OUTPUT_STR(strTemp);
for(int x=0; x<panel.x; x++)
{
if(panel.Mine[x][y].MineIn == Y && panel.WinOrFail == FAIL) //踩雷了,输出所有雷
OUTPUT_STR("* ");
else if(panel.Mine[x][y].MineNumAround != 0 && panel.Mine[x][y].CheckState == NO) // 输出安全区周边雷数
{
char strTemp[5] = {0};
sprintf(strTemp, "%d ", panel.Mine[x][y].MineNumAround);
OUTPUT_STR(strTemp);
}
else
{
switch(panel.Mine[x][y].CheckState)
{
case UNKNOW:
OUTPUT_STR("O ");
if(panel.Mine[x][y].MineIn == Y) tempWinOrFail = 0;
break;
case YES:
OUTPUT_STR("Y ");
if(panel.Mine[x][y].MineIn == N) tempWinOrFail = 0;
break;
case NO:
OUTPUT_STR("- ");
//if(panel.Mine[x][y].MineIn == Y) tempWinOrFail = -1;// 已在changeminestate函数中检测
break;
case DOUBT:
OUTPUT_STR("? ");
if(panel.Mine[x][y].MineIn == Y) tempWinOrFail = 0;
break;
}
}
}
OUTPUT_STR("\n");
}
if(panel.WinOrFail == FAIL)
{
OUTPUT_STR("--->踩雷啦!!!结束\n");
PAUSESCREEN;
}
else if(1 == tempWinOrFail)
{
panel.WinOrFail = WIN;
OUTPUT_STR("\n*********恭喜!扫雷完成!*********\n");
}
}
void GetCtrlFun(void)
{
int x=-1,y=-1;
char cmd=' ';
do
{
OUTPUT_STR("请输入扫雷命令(x y cmd): ");
scanf("%d %d %c",&x, &y, &cmd);
if(cmd >= 'a') cmd = cmd + ('A'-'a');//转成大写字母
}while (x<0 || x>=panel.x || y<0 || y>=panel.y || !(cmd == 'Y' || cmd == 'N' || cmd == '?'));
if('N' == cmd)
{
panel.OpenBlankMine(x, y);
panel.WinOrFail = panel.Mine[x][y].ChangeState(&panel.Mine[x][y], NO);
}
else if('Y' == cmd)
panel.WinOrFail = panel.Mine[x][y].ChangeState(&panel.Mine[x][y], YES);
else if('?' == cmd)
panel.WinOrFail = panel.Mine[x][y].ChangeState(&panel.Mine[x][y], DOUBT);
fflush(stdin);
//getchar();
panel.Output();
return;
}
void DestroyPanelFun(void)
{
for(int x=0; x<panel.x; x++)
{
delete [] panel.Mine[x];
}
delete [] panel.Mine;
panel.Mine = NULL;
}
void InitPanelFun(void)
{
// TODO: 将此函数中的scanf和printf进行封装,使输入输出不依赖特定平台
int reDo = 0;
OUTPUT_STR("by: 瑞 2012-9-20\n");
do
{
OUTPUT_STR("请输入游戏难度等级:(可选等级:1,2,3,分别表示由易到难;输入0表示自定义)");
scanf("%d", &panel.Grade);
switch(panel.Grade)
{
case EASY:
panel.x = 10;
panel.y = 10;
panel.MinesNum = 10;
break;
case MIDDLE:
panel.x = 20;
panel.y = 20;
panel.MinesNum = 30;
break;
case HARD:
panel.x = 30;
panel.y = 30;
panel.MinesNum = 60;
break;
case USER_DEFINED:
do
{
// TODO: 此处需要更严格的数据合理性检查
OUTPUT_STR("请输入阵地(面板)大小(例如设置8*9的阵地,输入:8 9): ");
scanf("%d%d", &panel.x, &panel.y);
OUTPUT_STR("请输入地雷个数(例如设置10个地雷,输入:10): ");
scanf("%d", &panel.MinesNum);
}while(panel.x <=0 || panel.y <= 0 || panel.MinesNum <= 0);
break;
default:
reDo = 1;
break;
}
}while(1 == reDo);
panel.WinOrFail = RUNING;
panel.GameState = RUN;
panel.CatchMineNum = 0;
panel.DestroyPanel = DestroyPanelFun;
panel.GetCtrl = GetCtrlFun;
panel.Output = OutPutFun;
panel.OpenBlankMine = OpenBlankMineFun;
// 其它预留参数暂不设置
// 动态建立地雷阵地表
panel.Mine = new pMineStruct[panel.x];
if(NULL == panel.Mine) // 内存分配失败
exit(1);
for(int x=0; x<panel.x; x++)
{
panel.Mine[x] = new MineStruct[panel.y];
for(int y=0; y<panel.y; y++)
{
panel.Mine[x][y].x = x;
panel.Mine[x][y].y = y;
panel.Mine[x][y].MineIn = N;
panel.Mine[x][y].MineNumAround = 0;
panel.Mine[x][y].CheckState = UNKNOW;
panel.Mine[x][y].ChangeState = ChangeMineStateFun;
}
}
// 随机安放地雷
srand(time(NULL)); // 随机种子初始化
for(int i=0; i< panel.MinesNum; i++)
{
int x = rand() % panel.x;
int y = rand() % panel.y;
if(Y == panel.Mine[x][y].MineIn)
{
i--;
}
else
{
panel.Mine[x][y].MineIn = Y;
}
}
// 标记周围的地雷数目
for(int x=0; x<panel.x; x++)
{
for(int y=0; y<panel.y; y++)
{
if(x>0 && y>0 && Y==panel.Mine[x-1][y-1].MineIn)
panel.Mine[x][y].MineNumAround++;
if(x>0 && Y==panel.Mine[x-1][y].MineIn)
panel.Mine[x][y].MineNumAround++;
if(x>0 && y<panel.y-1 && Y==panel.Mine[x-1][y+1].MineIn)
panel.Mine[x][y].MineNumAround++;
if(y>0 && Y==panel.Mine[x][y-1].MineIn)
panel.Mine[x][y].MineNumAround++;
if(y<panel.y-1 && Y==panel.Mine[x][y+1].MineIn)
panel.Mine[x][y].MineNumAround++;
if(x<panel.x-1 && y>0 && Y==panel.Mine[x+1][y-1].MineIn)
panel.Mine[x][y].MineNumAround++;
if(x<panel.x-1 && Y==panel.Mine[x+1][y].MineIn)
panel.Mine[x][y].MineNumAround++;
if(x<panel.x-1 && y<panel.y-1 && Y==panel.Mine[x+1][y+1].MineIn)
panel.Mine[x][y].MineNumAround++;
}
}
// 输出
panel.Output();
}
void InitGame(void)
{
panel.InitPanel = InitPanelFun;
panel.InitPanel();
}
int main()
{
InitGame();
while(panel.WinOrFail == RUNING)
{
panel.GetCtrl();
}
PAUSESCREEN;
panel.DestroyPanel();
return 0;
}
控制台的扫雷程序(C语言)
最新推荐文章于 2024-07-28 12:16:56 发布