C++实现控制台版扫雷程序

Riva ·
更新时间:2024-11-13
· 1482 次阅读

本文实例为大家分享了C++实现控制台版扫雷程序的具体代码,供大家参考,具体内容如下

测试平台: WIN7

工具: VC6.0 , VS2008都能编译得过。

花了两天时间写的,里面涉及的算法大都是自己想的,所以可能有些BUG。

#include <iostream> #include <time.h> #include <windows.h> using namespace std; #pragma comment (linker,"/subsystem:console") #define BLACK 0        //空白 #define MINE 100    //地雷 #define NOSWEEP 0    //未扫过 #define SWEEP 1        //扫雷 #define FLAG 2        //标记 class WinMine { public:     WinMine(int iRow, int iColumn);     ~WinMine(); public:     void InitMine(int iMineMax);     void SetColor();     void StatisticsMine();     void Map();     bool OpenWhites(int x, int y, int status);     void GameStart(int iMineMax);     void GameOver();     bool GoodOver(); private:     int **m_ppMine;     int **m_ppSweep;     bool m_bMineflag;     bool m_bSweepflag;     int m_row;     int m_column;     int m_minenum; }; int main(void) {     system("color 0d");     while (true)     {         int level;         WinMine *Mine;         cout << "请输入游戏等级:" <<endl;         cout << "1.初级" <<endl;         cout << "2.中级" <<endl;         cout << "3.高级" <<endl;         cout << "4.退出" <<endl;         cin >> level;         if (level == 1)         {             Mine = new WinMine(9,9);             Mine->GameStart(10);         }         else if (level == 2)         {             Mine = new WinMine(16,16);             Mine->GameStart(40);         }         else if (level == 3)         {             Mine = new WinMine(16,30);             Mine->GameStart(70);         }         else if (level == 4)         {             return 0;         }         else          {             cout << "输入错误!" <<endl;             continue;         }         delete Mine;     }     return 0; } WinMine::WinMine(int iRow, int iColumn) {     int i;     //储雷状态     m_ppMine = (int **) new int[iRow]; if (!m_ppMine) return;     m_ppMine[0] = new int[iRow * iColumn]; if (!*m_ppMine) { delete[] m_ppMine; m_ppMine = NULL; return;}     m_bMineflag = true;     //扫雷状态     m_ppSweep = (int **) new int[iRow]; if (!m_ppSweep) return;     m_ppSweep[0] = new int[iRow * iColumn]; if (!*m_ppSweep) { delete[] m_ppSweep; m_ppSweep = NULL; return;}     m_bSweepflag = true;     m_row = iRow; m_column = iColumn;     for (i = 1; i < iRow; i++)     {         m_ppMine[i] = m_ppMine[0] + i * iRow;     }     for (i = 1; i < iRow; i++)     {         m_ppSweep[i] = m_ppSweep[0] + i * iRow;     }     memset(m_ppSweep[0], 0, iRow * iColumn * sizeof(int));     memset(m_ppMine[0], 0, iRow * iColumn * sizeof(int)); } WinMine::~WinMine() {     if (m_bMineflag)     {         if (m_ppMine[0]) delete[] m_ppMine[0];         if (m_ppMine) delete[] m_ppMine;     }     if (m_bSweepflag)     {         if (m_ppSweep[0]) delete[] m_ppSweep[0];         if (m_ppSweep) delete[] m_ppSweep;     } } //设置颜色 void WinMine::SetColor() {     system("color 0a"); } //初始化雷数 void WinMine::InitMine(int iMineMax)     {     int x, y,num = 0;     srand( (unsigned)time(NULL) );     for (int i = 0; num != iMineMax; i++)     {         x = rand()%m_row;         y = rand()%m_column;         if (MINE != m_ppMine[x][y])         {             m_ppMine[x][y] = MINE;             num++;         }     }     m_minenum = num; } //统计雷数 void WinMine::StatisticsMine() {     int i, j;     int n, m;     int num = 0; //保存雷数     //中间     for ( i = 1; i < m_row - 1; i++)     {         for ( j = 1; j < m_column - 1; j++)         {             if ( m_ppMine[i][j] == BLACK)             {                 for (n = i - 1; n <= i + 1; n++)                 {                     for (m = j - 1; m <= j + 1; m++)                     {                         if ( m_ppMine[n][m] == MINE )                             num++;                     }                 }                 m_ppMine[i][j] = num;                 num = 0;             }         }     }     //顶边     for ( i = 1; i < m_column - 1; i++)     {         if (m_ppMine[0][i] == BLACK)         {             for (n = 0; n < 2; n++)             {                 for (m = i - 1; m <= i + 1; m++)                 {                     if (m_ppMine[n][m] == MINE)                         num++;                 }             }             m_ppMine[0][i] = num;             num = 0;         }     }     //下边     for ( i = 1; i < m_column - 1; i++)     {         if (m_ppMine[m_row - 1][i] == BLACK)         {             for (n = m_row - 2; n < m_row; n++)             {                 for (m = i - 1; m <= i + 1; m++)                 {                     if (m_ppMine[n][m] == MINE)                         num++;                 }             }             m_ppMine[m_row - 1][i] = num;             num = 0;         }     }     //左边     for ( i = 1; i < m_row - 1; i++ )     {         if (m_ppMine[i][0] == BLACK)         {             for (n = i - 1; n <= i + 1; n++)             {                 for (m = 0; m < 2; m++)                     if (m_ppMine[n][m] == MINE)                         num++;                 }             m_ppMine[i][0] = num;             num = 0;         }     }     //右边     for ( i = 1; i < m_row - 1; i++ )     {         if (m_ppMine[i][m_column - 1] == BLACK)         {             for (n = i - 1; n <= i + 1; n++)             {                 for (m = m_column - 2; m < m_column; m++)                 {                     if (m_ppMine[n][m] == MINE)                         num++;                 }             }             m_ppMine[i][m_column - 1] = num;             num = 0;         }     }     //左上角     if (m_ppMine[0][0] != MINE)     {         if (m_ppMine[0][1] == MINE)             num++;         if (m_ppMine[1][1] == MINE)             num++;         if (m_ppMine[1][0] == MINE)             num++;         m_ppMine[0][0] = num;         num = 0;     }     //左下角     if (m_ppMine[m_row - 1][0] != MINE)     {         if (m_ppMine[m_row - 2][0] == MINE)             num++;         if (m_ppMine[m_row - 2][1] == MINE)             num++;         if (m_ppMine[m_row - 1][1] == MINE)             num++;         m_ppMine[m_row - 1][0] = num;         num = 0;     }     //右上角     if (m_ppMine[0][m_column - 1] != MINE)     {         if (m_ppMine[1][m_column - 1] == MINE)             num++;         if (m_ppMine[1][m_column - 2] == MINE)             num++;         if (m_ppMine[0][m_column - 2] == MINE)             num++;         m_ppMine[0][m_column - 1] = num;         num = 0;     }     //右下角     if (m_ppMine[m_row - 1][m_column - 1] != MINE)     {         if (m_ppMine[m_row - 2][m_column - 1] == MINE)             num++;         if (m_ppMine[m_row - 2][m_column - 2] == MINE)             num++;         if (m_ppMine[m_row - 1][m_column - 2] == MINE)             num++;         m_ppMine[m_row - 1][m_column - 1] = num;         num = 0;     } } //展开空白 bool WinMine::OpenWhites(int row, int column, int status) {     if (row < 0 || row > (m_row - 1) || column < 0 || column > (m_column - 1))         return true;     if (status == SWEEP &&  m_ppMine[row][column] == MINE)     {         return false;     }     if (status == FLAG)     {         m_ppSweep[row][column] = FLAG;         return true;     }     if (m_ppSweep[row][column] == NOSWEEP && m_ppMine[row][column] != MINE)     {         if (m_ppMine[row][column] > 0)         {             m_ppSweep[row][column] = SWEEP;              return true;         }         else         {             m_ppSweep[row][column] = SWEEP;             OpenWhites(row-1, column, status);             OpenWhites(row-1, column-1, status);             OpenWhites(row-1, column+1, status);             OpenWhites(row, column-1, status);             OpenWhites(row, column+1, status);             OpenWhites(row+1, column, status);             OpenWhites(row+1, column-1, status);             OpenWhites(row+1, column+1, status);         }     }     return true; } //地图 void WinMine::Map() {     SetColor();     int i, j;     for ( i = 0; i < m_row; i++)     {         for (j = 0; j < m_column; j++)         {             if (m_ppSweep[i][j] == SWEEP)             {                 if (m_ppMine[i][j] == 0)                 {                     cout << "□";                 }                 else if (m_ppMine[i][j] == 1)                 {                     cout << "①";                 }                 else if (m_ppMine[i][j] == 2)                 {                     cout << "②";                 }                 else if (m_ppMine[i][j] == 3)                 {                     cout << "③";                 }                 else if (m_ppMine[i][j] == 4)                 {                     cout << "④";                 }                 else if (m_ppMine[i][j] == 5)                 {                     cout << "⑤";                 }                 else if (m_ppMine[i][j] == 6)                 {                     cout << "⑥";                 }                 else if (m_ppMine[i][j] == 7)                 {                     cout << "⑦";                 }                 else if (m_ppMine[i][j] == 8)                 {                     cout << "⑧";                 }                 }             else if (m_ppSweep[i][j] == FLAG)             {                 cout << "⊙";             }             else                 cout << "▇";         }         cout << endl;     } } //游戏结束 void WinMine::GameOver() {     int i, j;     for ( i = 0; i < m_row; i++)     {         for (j = 0; j < m_column; j++)         {             if (m_ppMine[i][j] == MINE)                 cout << "★";             else                  cout << "□";         }         cout << endl;     } } //检查是否雷标记正确。 bool WinMine::GoodOver() {     int i, j;     int num = 0;     for (i = 0; i < m_row; i++)     {         for (j = 0; j < m_column; j++)         {             if (m_ppSweep[i][j] == FLAG && m_ppMine[i][j] == MINE)                 num++;         }     }     if (num == m_minenum)         return true;     else         return false; } //开始游戏 void WinMine::GameStart(int iMineMax) {     int x, y;     int flag; begin:     memset(m_ppSweep[0], 0, m_row * m_column * sizeof(int));     memset(m_ppMine[0], 0, m_row * m_column * sizeof(int));     InitMine(iMineMax);     StatisticsMine();     while (true)     {         system("cls");         Map();         cout << "请输入要扫的区域的坐标:" <<endl;         cout << "请输入纵坐标:";cin>>x;         cout << "请输入横坐标:";cin>>y;         if (x <= 0 || x > m_row || y <= 0 || y > m_column)         {             cout <<"输入错误请重新输入" <<endl;             Sleep(1000);             continue;         }         cout << "请输入是要做标记还是扫雷,扫雷请按1,标记请按2:" <<endl;         cin >> flag;         if ( false == OpenWhites(x-1, y-1, flag) )         {             int i;             system("cls");             GameOver();             cout << "游戏结束!" <<endl;             cout << "继续游戏请按1,退出游戏请按0:"<<endl;             cin >> i;             if (i == 1)                 goto begin;             else                  goto end;         }         else         {             if (GoodOver() == true)             {                 int i;                 cout << "扫雷成功!" <<endl;                 cout << "继续游戏请按1,退出游戏请按0:"<<endl;                 cin >> i;                 if (i == 1)                     goto begin;                 else                      goto end;             }         }     } end:     return; }

再为大家分享一位作者的文章:控制台版扫雷(支持鼠标操作)

//说明: 左键双击对应windows自带扫雷中的双键点击 #include <windows.h> #include <cstdlib> #include <ctime> #include <list> using namespace std; //数组索引转成坐标 #define X(v) (v) % WIDTH #define Y(v) (v) / WIDTH //坐标系统转换 #define BOARDX(x) ((x) - OFFSETX) / 2 #define BOARDY(y) (y) - OFFSETY #define SCREENX(x) 2 * (x) + OFFSETX #define SCREENY(y) (y) + OFFSETY #define BACKGROUND_WHITE (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED) #define FOREGROUND_WHITE (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED) typedef enum {     UNKNOWN,     DISPLAY,     MARKED } State; typedef enum {     NUMBER,     EMPTY,     MINE } MType; typedef struct {     State state;     MType mtype;     int val; } Cell; typedef bool (* CmpProc)(Cell& cell, void* pData); int HEIGHT   = 16; int WIDTH    = 16; int MINE_CNT = 40;    //地雷数 int CELL_CNT; //第一个格子的x, y偏移 int OFFSETX = 3; int OFFSETY = 3; int flagCnt;        //标记数 int mineLeft;        //地雷剩余 int unkwLeft;        //未知剩余 int liveLeft;        //生命剩余 COORD tmPos;        //计时坐标 COORD mnPos;        //地雷(剩余)坐标 COORD lvPos;        //生命坐标 bool bGameStart, bGameStop;        //游戏开始.结束标记 DWORD dwStart; HANDLE hOut, hIn; Cell cells[16][30]; void writeChar(LPCSTR pChar, COORD wrtCrd) {     DWORD wtn;     WriteConsoleOutputCharacter(hOut, pChar, strlen(pChar), wrtCrd, &wtn); } void fillChar(TCHAR cChar, DWORD len, COORD wrtCrd) {     DWORD wtn;     FillConsoleOutputCharacter(hOut, cChar, len, wrtCrd, &wtn); } void fillAttr(WORD attr, DWORD len, COORD wrtCrd) {     DWORD wtn;     FillConsoleOutputAttribute(hOut, attr, len, wrtCrd, &wtn); } bool isCell(int x, int y) {     return x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT; } bool isMine(int x, int y) {     return isCell(x, y) && cells[y][x].mtype == MINE; } bool cmpState(Cell& cell, void* pData) {     return cell.state == *(State*)pData; } bool cmpMtype(Cell& cell, void* pData) {     return cell.mtype == *(MType*)pData; } //四周格子作比较 int aroundCmp(int x, int y, CmpProc cmp, void* pData) {     int nRet = 0;     for (int y0=y-1; y0<=y+1; y0++)     {         for (int x0=x-1; x0<=x+1; x0++)         {             if (isCell(x0, y0)                  && !(x0 == x && y0 == y))        //not self             {                 nRet += cmp(cells[y0][x0], pData);             }         }     }     return nRet; } int aroundMines(int x, int y) {     int val = MINE;     return aroundCmp(x, y, cmpMtype, &val); } int aroundMarks(int x, int y) {     int val = MARKED;     return aroundCmp(x, y, cmpState, &val); } //扰乱数组的前n个元素 void ruffle(int* arr, int len, int n) {     for (int i=0; i<n; i++)     {         int j = rand() % len;         int tmp = arr[i];         arr[i] = arr[j];         arr[j] = tmp;     } } //计时 void setElapsedTime() {     if (bGameStart && !bGameStop)     {         DWORD dwDelt = (GetTickCount() - dwStart) / 1000;         if (dwDelt < 1000)         {             char buf[5] = {0};             sprintf(buf, "%.3d\0", dwDelt);             writeChar(buf, tmPos);         }         } } //剩余雷数(仅显示, 非实际) void setMinesLeft() {     char buf[5] = {0};     sprintf(buf, "%2d\0", MINE_CNT - flagCnt);     writeChar(buf, mnPos); } //剩余生命 void setLivesLeft(int delt = 0) {     char buf[5] = {0};     liveLeft += delt;     sprintf(buf, "%2d\0", liveLeft);     writeChar(buf, lvPos); } void drawCell(int x, int y) {     Cell* pCell = &cells[y][x];     COORD cellCrd = {SCREENX(x), SCREENY(y)};     char buf[3] = {0};     switch (pCell->state)     {     case UNKNOWN:         sprintf(buf, "□\0");         break;     case MARKED:         sprintf(buf, " P\0");             break;     case DISPLAY:         switch (pCell->mtype)         {         case MINE:             sprintf(buf, " *\0");             break;         case EMPTY:             sprintf(buf, "  \0");             break;         case NUMBER:             sprintf(buf, " %d\0", pCell->val);             fillAttr((WORD)pCell->val, 2, cellCrd);    //数字着色             break;         }         break;     }     writeChar(buf, cellCrd); } //初始化信息栏 void initInfoBar() {     char buf[50] = {0};     sprintf(buf, "生命: %2d   地雷: %2d   用时: 000\0", liveLeft, MINE_CNT);     COORD crd = {(80 - strlen(buf)) / 2, SCREENY(HEIGHT) + 1};        //水平居中     writeChar(buf, crd);     crd.X += 6;        lvPos = crd;     crd.X += 11;    mnPos = crd;     crd.X += 11;    tmPos = crd; } void clearScreen() {     COORD crd = {0, 0};     CONSOLE_SCREEN_BUFFER_INFO csbi;     GetConsoleScreenBufferInfo(hOut, &csbi);     fillChar(' ', csbi.dwSize.X * csbi.dwSize.Y, crd);     fillAttr(FOREGROUND_WHITE, csbi.dwSize.X * csbi.dwSize.Y, crd); } void initGame() {     srand((unsigned)time(NULL));     SetConsoleTitle("扫雷控制台版   F2: 初级; F3: 中级; F4: 高级");     clearScreen();     CELL_CNT = HEIGHT * WIDTH;     OFFSETX = (80 - WIDTH * 2) / 2;    //水平居中     int* idxs = new int[CELL_CNT];    //地雷索引     int i, x, y;     //init cells and indexs     for (i=0; i<CELL_CNT; i++)     {         cells[Y(i)][X(i)].mtype = EMPTY;         cells[Y(i)][X(i)].state = UNKNOWN;         idxs[i] = i;     }     ruffle(idxs, CELL_CNT, MINE_CNT);     //fill mines     for (i=0; i<MINE_CNT; i++)     {         cells[Y(idxs[i])][X(idxs[i])].mtype = MINE;     }     //fill nums && print the game     for (y=0; y<HEIGHT; y++)     {         for (x=0; x<WIDTH; x++)         {             if (!isMine(x, y))             {                 cells[y][x].val = aroundMines(x, y);                 cells[y][x].mtype = cells[y][x].val > 0 ? NUMBER : EMPTY;             }             drawCell(x, y);         }     }     delete[] idxs;     bGameStart = false;     bGameStop  = false;     mineLeft = MINE_CNT;     unkwLeft = CELL_CNT;     liveLeft = MINE_CNT / 20 + 1;    //每二十个雷加一条命     flagCnt  = 0;     initInfoBar(); } void showAll() {     for (int i=0; i<CELL_CNT; i++)     {         cells[Y(i)][X(i)].state = DISPLAY;         drawCell(X(i), Y(i));     } } void showTip(const char* tipMsg, WORD attr = FOREGROUND_WHITE) {     COORD tipCrd = {(80 - strlen(tipMsg)) / 2, 1};     writeChar(tipMsg, tipCrd);     fillAttr(attr, strlen(tipMsg), tipCrd); } void gameWin() {     if (!bGameStop)     {         showTip("恭喜你, 你赢了! ", FOREGROUND_GREEN | FOREGROUND_INTENSITY);         bGameStop = true;     } } void gameOver(int x, int y) {     setLivesLeft(-1);     if (liveLeft == 0)     {         showAll();         showTip("游戏结束, 请重新来过!", FOREGROUND_RED | FOREGROUND_INTENSITY);         bGameStop = true;     }     else     {         COORD crd = {SCREENX(x), SCREENY(y)};         WORD attr = FOREGROUND_WHITE;         for (int i=0; i<6; i++)        //触雷闪烁         {             attr = FOREGROUND_WHITE ^ FOREGROUND_RED ^ attr;             fillAttr(attr, 2, crd);             Sleep(100);         }     } } void showAround(int x, int y) {         list<COORD> lst;     COORD crd = {x, y};     lst.push_back(crd);     while (!lst.empty())     {         crd = lst.front();         lst.pop_front();         x = crd.X;         y = crd.Y;         for (int x0=x-1; x0<=x+1; x0++)         {             for (int y0=y-1; y0<=y+1; y0++)             {                 if (!isCell(x0, y0)    || (x0 == x && y0 == y))                 {                     continue;                 }                 Cell* pCell = &cells[y0][x0];                 if (pCell->state == UNKNOWN)                 {                     if (pCell->mtype == MINE)                     {                         gameOver(x0, y0);                         break;                     }                     else if (pCell->mtype == EMPTY)                     {                         crd.X = x0;                         crd.Y = y0;                         lst.push_back(crd);                     }                     unkwLeft--;                     pCell->state = DISPLAY;                     drawCell(x0, y0);                 }             }    //end for         }    //end for     } } void onCellLDBLClick(int x, int y) {     Cell* pCell = &cells[y][x];     //左双击对显示的数字格子起作用, 且该格子周围的标记数等于该数字     if (pCell->mtype == NUMBER && pCell->state == DISPLAY          && aroundMarks(x, y) == pCell->val)     {         showAround(x, y);     } } void onCellLClick(int x, int y) {     Cell* pCell = &cells[y][x];     //左击只对未知格子起作用     if (pCell->state == UNKNOWN)     {         if (pCell->mtype == MINE)         {             gameOver(x, y);         }         else         {             pCell->state = DISPLAY;             unkwLeft--;             drawCell(x, y);             if (pCell->mtype == EMPTY)             {                 showAround(x, y);             }         }     }     } void onCellRClick(int x, int y) {     Cell* pCell = &cells[y][x];     //右击对未知, 标记格子起作用     if (pCell->state != DISPLAY)     {         if (pCell->state == UNKNOWN)         {             pCell->state = MARKED;             mineLeft -= pCell->mtype == MINE ? 1 : 0;             unkwLeft--;             flagCnt++;         }         else         {             pCell->state = UNKNOWN;             mineLeft += pCell->mtype == MINE ? 1 : 0;             unkwLeft++;             flagCnt--;         }         drawCell(x, y);         setMinesLeft();     } } void onKeyDown(WORD keyCode) {     switch (keyCode)     {     case VK_F2:        //初级         HEIGHT   = 9;         WIDTH    = 9;         MINE_CNT = 10;         initGame();         break;     case VK_F3:        //中级         HEIGHT   = 16;         WIDTH    = 16;         MINE_CNT = 40;         initGame();         break;     case VK_F4:        //高级         HEIGHT   = 16;         WIDTH    = 30;         MINE_CNT = 99;         initGame();         break;     case VK_F12:         if (liveLeft < 99)         {             setLivesLeft(1);         }         break;     default:         break;     } } void afterMouseEvent() {     if (!bGameStart)     {         bGameStart = true;         dwStart = GetTickCount();     }     if (mineLeft == 0 && unkwLeft == 0)     {         gameWin();     } } int main(int argc, char* argv[]) {     hIn  = GetStdHandle(STD_INPUT_HANDLE);     hOut = CreateConsoleScreenBuffer(             GENERIC_WRITE,             0,             NULL,             CONSOLE_TEXTMODE_BUFFER,             NULL             );     CONSOLE_CURSOR_INFO cci;     cci.dwSize = 1;     cci.bVisible = FALSE;     SetConsoleCursorInfo(hOut, &cci);    //隐藏光标     SetConsoleActiveScreenBuffer(hOut);     initGame();     //监听事件     for (;;)     {         DWORD nEvts;         GetNumberOfConsoleInputEvents(hIn, &nEvts);         if (nEvts > 0)         {             INPUT_RECORD inpRec;             ReadConsoleInput(hIn, &inpRec, 1, &nEvts);             bool bClked = false;    //是否有合法鼠标事件发生             if (!bGameStop && inpRec.EventType == MOUSE_EVENT)             {                 int x = BOARDX(inpRec.Event.MouseEvent.dwMousePosition.X);                 int y = BOARDY(inpRec.Event.MouseEvent.dwMousePosition.Y);                 if (!isCell(x, y))                 {                     continue;                 }                 bClked = true;                 switch (inpRec.Event.MouseEvent.dwButtonState)                 {                 case FROM_LEFT_1ST_BUTTON_PRESSED:                     if (inpRec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)                     {                         onCellLDBLClick(x, y);                         break;    //处理过双击不再处理单击                     }                     onCellLClick(x, y);                     break;                 case RIGHTMOST_BUTTON_PRESSED:                     onCellRClick(x, y);                     break;                 default:                     bClked = false;                     break;                 }                 if (bClked)                 {                     afterMouseEvent();                 }             }             if (inpRec.EventType == KEY_EVENT)    //按键事件             {                 onKeyDown(inpRec.Event.KeyEvent.wVirtualKeyCode);                 Sleep(100);             }             FlushConsoleInputBuffer(hIn);         }         setElapsedTime();         Sleep(50);     }     return 0; }



c+ 程序 C++ 控制台

需要 登录 后方可回复, 如果你还没有账号请 注册新账号