本文实例为大家分享了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;
}