# 控制台小游戏MineSweeper

2018-02-27 08:59:51来源:cnblogs.com作者:tniap人点击

`  1 #include<set>  2 #include<array>  3 #include<string>  4 #include<time.h>  5 #include<graphics.h>  6   7 using namespace std;  8 #define    Num    20                                       //小方块数量Num*Num //rand()使得Num数值太小进入死循环  9 #define   Size    25                                       //每个小方块大小 10 using    UInt16 = unsigned short int; 11 using    TheMap = array<array<UInt16, Num + 2>, Num + 2>;  //引索地图 12 #define    Trap   (UInt16)0X0000                           //地雷 13 #define InitMap   (UInt16)0X0001                           //表示无地雷，每次X2表示周围地雷数+1 14 #define   Asked   (UInt16)0XFFFF                           //标志已询问 15  16 void Init(TheMap &Map);                                    //生成Map、地雷，绘制窗口 17 bool MainLoop(TheMap &Map);                                //游戏循环 18 void DisplayEmpty(TheMap &Map, int i, int j);              //对提示区0的绘制 19 void DisplayNum(TheMap &Map, int i, int j);                //对提示区1-8的绘制 20 int DisplayFlag(TheMap &Map, int i, int j);                //对标志的绘制 21  22 int main() { 23     auto hwnd = initgraph(Num * Size, Num * Size); 24     //游戏的实现 25     TheMap Map; 26     Init(Map); 27     if (MainLoop(Map)) 28         MessageBox(hwnd, L"Win", L"Mine Clerance", MB_OK); 29     else 30         MessageBox(hwnd, L"Defeated", L"Mine Clerance", MB_OK); 31     //离开游戏 32     closegraph(); 33     return 0; 34 } 35 void Init(TheMap &Map) { 36     //初始化Map 37     for (auto &It : Map) 38         It.assign(InitMap); 39     //随机生成地雷 40     srand((unsigned)time(NULL)); 41     for (UInt16 k = 0; k < 2 * Num;) { 42         auto i = rand() % Num + 1; 43         auto j = rand() % Num + 1; 44         if (Map[i][j] == InitMap) { 45             Map[i][j] = Trap; 46             for (int m = -1; m <= 1; ++m) 47                 for (int n = -1; n <= 1; ++n) 48                     Map[i + m][j + n] <<= 1; 49             ++k; 50         } 51     } 52     //赋值Asked，防止越界 53     for (size_t i = 0; i < Num + 2; ++i) { 54         Map[i][0] = Asked; 55         Map[i][Num + 1] = Asked; 56         Map[0][i] = Asked; 57         Map[Num + 1][i] = Asked; 58     } 59     //绘制可视地图 60     setlinecolor(LIGHTGREEN); 61     for (size_t i = Size; i < Size * Num; i += Size) { 62         line(i, 0, i, Size * Num); 63         line(0, i, Size * Num, i); 64     } 65 } 66 bool MainLoop(TheMap &Map) { 67     int Ret = 0; 68     MOUSEMSG Point; 69     while (Ret != 1) { 70         Point = GetMouseMsg(); 71         if (Point.mkLButton) { //鼠标左键--点开小方块 72             Point = GetMouseMsg(); 73             size_t i = Point.x / Size + 1; 74             size_t j = Point.y / Size + 1; 75             switch (Map[i][j]) { 76             case Trap: //按到地雷 77                 for (size_t i = 1; i < Num + 1; ++i) 78                     for (size_t j = 1; j < Num + 1; ++j) 79                         if (Map[i][j] == Trap) 80                             outtextxy(i*Size - Size / 2, j*Size - 3 * Size / 4, L"X"); 81                 return false; 82             case InitMap: //按到0 83                 DisplayEmpty(Map, i, j); 84                 break; 85             case InitMap << 1: 86             case InitMap << 2: 87             case InitMap << 3: 88             case InitMap << 4: 89             case InitMap << 5: 90             case InitMap << 6: 91             case InitMap << 7: 92             case InitMap << 8: 93                 DisplayNum(Map, i, j); //按到1-8 94                 break; 95             } 96         } 97         else if (Point.mkRButton) { //鼠标右键--标记 98             Point = GetMouseMsg(); 99             auto i = Point.x / Size + 1;100             auto j = Point.y / Size + 1;101             Ret = DisplayFlag(Map, i, j);102             if (Ret == -1) {103                 DisplayFlag(Map, i, j);104                 MessageBox(GetHWnd(), L"NO More Mark", L"MineSweeper", MB_OK);105             }106         }107     }108     return true;109 }110 void DisplayEmpty(TheMap &Map, int i, int j) {111     //九宫格历遍，递归112     for (int m = i - 1; m <= i + 1; ++m)113         for (int n = j - 1; n <= j + 1; ++n) {114             if (Map[m][n] == InitMap) {115                 Map[m][n] = Asked;116                 outtextxy(m*Size - Size / 2, n*Size - 3 * Size / 4, wstring(to_wstring(0)).c_str());117                 DisplayEmpty(Map, m, n);118             }119             else if (Map[m][n] != Asked)120                 DisplayNum(Map, m, n);121         }122 }123 void DisplayNum(TheMap &Map, int i, int j) {124     UInt16 num = 8;125     switch (Map[i][j]) {126     case 2:--num;127     case 4:--num;128     case 8:--num;129     case 16:--num;130     case 32:--num;131     case 64:--num;132     case 128:--num;133     case 256:num;134         Map[i][j] = Asked;135         outtextxy(i*Size - Size / 2, j*Size - 3 * Size / 4, wstring(to_wstring(num)).c_str());136         break;137     }138 }139 int DisplayFlag(TheMap &Map, int i, int j) {140     static UInt16 TrueFlags = 0;     //定义被正确标志的地雷的数量141     static UInt16 FlagTimes = 0;     //定义被用户标志的地雷的数量142     static set<UInt16> Record;       //定义容器,用于记录标记点143     if (Map[i][j] == Asked)          //对已经访问点不做操作144         return 0;145     UInt16 ret = i << 8 | j;         //适用:Map下标最大0XFFFF146     auto Iter = Record.insert(ret);147     if (Iter.second) {//标记148         outtextxy(i*Size - Size / 2, j*Size - 3 * Size / 4, L"/?");149         if (Map[i][j] == Trap)150             ++TrueFlags;151         ++FlagTimes;152     }153     else {//清除标记154         Record.erase(ret);155         setfillcolor(BLACK);156         fillrectangle(i*Size - Size, j*Size - Size, i*Size, j*Size);157         if (Map[i][j] == Trap)158             --TrueFlags;159         --FlagTimes;160     }161     if (TrueFlags == 2 * Num)162         return 1;163     if (FlagTimes > 2 * Num) //控制标记数164         return -1;165     return 0;166 }`

2018-02-26