控制台的扫雷程序(C语言)
// 扫雷程序 C-Free编译通过// by: 瑞 2012-9-20 #include <stdio.h>#include <stdlib.h>#include <iostream>#include <windows.h>#include <time.h>using namespace std;#define CLRSCREENsystem("cls") // 清屏 #define PAUSESCREEN system("pause") // 屏幕暂停enum winorfial {RUNING, WIN, FAIL};// 输赢结果enum check_state {UNKNOW, NO, YES, DOUBT}; // 地雷被扫的状态enum mine_in {Y, N}; // 此坑是否真的有地雷typedef struct _mine // 地雷坑 的结构体定义{ intx,y; // 地雷坐标 check_stateCheckState; // 当前地雷被扫的状态 mine_inMineIn; // 此坑是否真的有地雷 intMineNumAround; // 周围地雷数目 winorfial(*ChangeState)(struct _mine *ThisMine, check_stateCheckState);// 改变状态函数 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_gradeGrade; // 难度等级 intx, y; // 阵地的宽和高 intMinesNum; // 阵地内的地雷数目 intCatchMineNum; // 玩家找到的雷数 game_stateGameState; // 当前游戏状态 winorfial WinOrFail; // 输赢情况 intTimeOutSeconds; // 超时等待的秒数 [预留] histrylistHistry; // 玩家英雄榜 [预留] 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;Panelpanel;// 阵地(面板)的全局对象 char*str[]={ "扫雷吧!\n游戏说明:\n确定(x,y)位置无雷,输入:x y N\n确定(x,y)位置有雷,输入:x y Y\n怀疑(x,y)位置有雷,输入:x y ?\n", "当前雷区大小: %d*%d, 地雷数%d\n"};winorfial ChangeMineStateFun(pMineStruct ThisMine, check_stateCheckState){ 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; printf(str[0]); // 游戏说明字符串 printf(str[1], panel.x, panel.y, panel.MinesNum); // 输出雷区信息 // 检测并输出 int tempWinOrFail = 1; // 假设赢 printf(" x\t"); for(int x=0; x<panel.x; x++) { printf("%d ", x%10); } printf("\ny\n\n"); for(int y=0; y<panel.y; y++) { printf("%d:\t", y); for(int x=0; x<panel.x; x++) { if(panel.Mine[x][y].MineIn == Y && panel.WinOrFail == FAIL) //踩雷了,输出所有雷 printf("* "); else if(panel.Mine[x][y].MineNumAround != 0 && panel.Mine[x][y].CheckState == NO) // 输出安全区周边雷数 printf("%d ", panel.Mine[x][y].MineNumAround); else { switch(panel.Mine[x][y].CheckState) { case UNKNOW: printf("%c ", 'O'); if(panel.Mine[x][y].MineIn == Y) tempWinOrFail = 0; break; case YES: printf("%c ", 'Y'); if(panel.Mine[x][y].MineIn == N) tempWinOrFail = 0; break; case NO: printf("%c ", '-'); //if(panel.Mine[x][y].MineIn == Y) tempWinOrFail = -1;// 已在changeminestate函数中检测 break; case DOUBT: printf("%c ", '?'); if(panel.Mine[x][y].MineIn == Y) tempWinOrFail = 0; break; } } } printf("\n"); } if(panel.WinOrFail == FAIL) { printf("--->踩雷啦!!!结束\n"); PAUSESCREEN; } else if(1 == tempWinOrFail) { panel.WinOrFail = WIN; printf("\n*********恭喜!扫雷完成!*********\n"); }}void GetCtrlFun(void){ int x=-1,y=-1; char cmd=' '; do { printf("请输入扫雷命令(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 DestrPanelFun(void){ for(int x=0; x<panel.x; x++) { delete [] panel.Mine[x]; } delete [] panel.Mine;}void InitPanelFun(void){ // TODO: 将此函数中的scanf和printf进行封装,使输入输出不依赖特定平台 int reDo = 0; printf("by: 瑞 2012-9-20\n"); do { printf("请输入游戏难度等级:(可选等级: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: 此处需要更严格的数据合理性检查 printf("请输入阵地(面板)大小(例如设置8*9的阵地,输入:8 9): "); scanf("%d%d", &panel.x, &panel.y); printf("请输入地雷个数(例如设置10个地雷,输入:10): "); scanf("%d", &panel.MinesNum); //printf(str[1], panel.x, panel.y, 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 = DestrPanelFun; panel.GetCtrl = GetCtrlFun; panel.Output = OutPutFun; panel.OpenBlankMine = OpenBlankMineFun; // 其它预留参数暂不设置 // 动态建立地雷阵地表 panel.Mine = new pMineStruct[panel.x]; 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;}