Easyx-----c++实现经典Windows扫雷
生活随笔
收集整理的這篇文章主要介紹了
Easyx-----c++实现经典Windows扫雷
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一些說明
關于掃雷的基本實現,我在這篇博客已經詳細介紹Easyx-----c語言實現簡易版掃雷_考拉愛睡覺鴨~的博客-CSDN博客
這里不再描述,主要是以c++單例設計模式的方式實現掃雷,多加了右鍵點擊笑臉作弊功能,不會掃雷的小伙伴也可以愉快玩耍了
效果展示
?
?
?
右鍵點擊笑臉作弊,點擊左鍵還原
?
?Common.h?????????公共的頭文件
#pragma once #include <graphics.h> #include <iostream> #include <string> #include <map> #include<array> #include <list> #include <thread> #include <vector> #include <ctime> #include <mmsystem.h> #pragma comment(lib,"winmm.lib") using namespace std;Res.h????????資源文件加載?
#pragma once #include "Common.h" class Res { private:Res(); public:static int WIDTH(string name);static int HEIGHT(string name);static Res* GetInstance();static void Draw_IMG(int x, int y, string name); //背景圖片繪制static void DrawIMG(int x, int y, string name,int preIndex); //其他圖片繪制static DWORD WINAPI PlayMusic(LPVOID lparame); //播放音樂~Res(); public:static map<string, IMAGE*> img; //圖片static map<string, string> music; //音樂static int MineNum; //雷的數量static int ROW; //行|列static int COL; };Res.cpp
#include "Res.h" map<string, IMAGE*> Res::img; //圖片 map<string, string> Res::music; //音樂 int Res::MineNum = 10; //雷的數量 int Res::ROW = 9; //行|列 int Res::COL = 9; /*———————————————————————————————————————————加載 和 初始化 圖片相關內容————————————————————————————————————————————*/ Res::Res() {//背景string background = "./res/background.png";//磚塊string block[2] = { "./res/block/common_block.png","./res/block/press_block.png" };//笑臉標識 smile victory fail error(外掛)string face[4] = { "./res/face/smile.png","./res/face/victory.png","./res/face/fail.png","./res/face/error.png" };//地雷 未踩雷 標記雷 踩中雷string mine[3] = { "./res/mine/unstep_mine.png","./res/mine/sign_mine.png","./res/mine/step_mine.png" };//標識 旗幟 問號 按壓問號string sign[3] = { "./res/sign/flag.png","./res/sign/question.png","./res/sign/press_question.png" };//普通數字 1-8for (int i = 1; i <= 8; i++) {string init = "./res/numbers/";string strURL = "0";strURL[0] += i;strURL += ".png";strURL = init + strURL;img[to_string(i - 1)] = new IMAGE; //img["0"]loadimage(img[to_string(i - 1)], strURL.c_str());}//倒計時數字 0-9for (int i = 0; i <= 9; i++) {string init = "./res/timeing/";string strURY = "0";strURY[0] += i;strURY += "_1.png";strURY = init + strURY;img[to_string(i - 0)+"_"] = new IMAGE; //img["0_"]loadimage(img[to_string(i - 0) + "_"], strURY.c_str());//cout << strURL << endl;}img["背景"] = new IMAGE;img["磚塊"] = new IMAGE[2];img["笑臉"] = new IMAGE[4];img["地雷"] = new IMAGE[3];img["標識"] = new IMAGE[3];loadimage(img["背景"], background.c_str()); //370-250=120 479-320=159for (int i = 0; i < 3; i++){loadimage(img["地雷"] + i, mine[i].data());loadimage(img["標識"] + i, sign[i].data());}for (int i = 0; i < 4; i++){loadimage(img["笑臉"] + i, face[i].data());}for (int i = 0; i < 2; i++){loadimage(img["磚塊"] + i, block[i].data());} } //獲取圖片的高度 int Res::WIDTH(string name) {return GetInstance()->img[name]->getwidth(); }int Res::HEIGHT(string name) {return GetInstance()->img[name]->getheight(); }Res* Res::GetInstance() {static Res* res = new Res;return res; } //只有一張圖片的貼圖: 背景圖貼圖 void Res::Draw_IMG(int x, int y, string name) {putimage(x, y, GetInstance()->img[name]); } void Res::DrawIMG(int x, int y, string name, int preIndex) {putimage(x, y, GetInstance()->img[name] + preIndex); } DWORD __stdcall Res::PlayMusic(LPVOID lparame) {return 0; }Res::~Res() {delete img["背景"];delete[]img["磚塊"];delete[]img["笑臉"];delete[]img["地雷"];delete[]img["標識"];}Data.h????????數據的處理
#pragma once #include"Common.h" //根據鼠標消息,做數據的改變 class Data {public:void Set(); //設置雷|按鍵開蓋|設置標記void constValue(int i, int j, int value); //設置數據(地圖中的值) 限定數據|改變數據void changeValue(int i, int j, int value);array<array<int, 9>, 9>& getMap(); //在外面畫圖要訪問數據,提供外部訪問接口 protected:array <array< int, 9 >, 9 > map = {0};};?Data.cpp
#include "Data.h" #include "Res.h" //用到資源 #include"Common.h" void Data::constValue(int i, int j, int value) {map[i][j] = value; }void Data::changeValue(int i, int j, int value) {map[i][j]+= value; }void Data::Set() {//設置隨機數種子srand((unsigned)time(NULL));//把map全部初始化為0for (int i = 0; i < Res::ROW; i++) {for (int j = 0; j < Res::COL; j++){map[i][j] = 0;cout << map[i][j]<<"\t";}cout << endl;}cout << endl;//隨機設置十個雷 用-1表示 for (int i = 0; i < Res::MineNum; ){//數組的有效下標 [0,9]int r = rand() % Res::ROW;int c = rand() % Res::COL;//隨機下標可能有重復的---需要判斷當前位置是否有設置為雷if (map[r][c] == 0){changeValue(r, c, -1);//只有執行了這里的代碼,才成功設置了雷 -1 后++i++;}}//把以雷為中心的九宮格數據都+1,雷除外for (int i = 0; i < Res::ROW; i++){for (int k = 0; k < Res::COL; k++){//找到雷,并遍歷雷所在的九宮格if (map[i][k] == -1){for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//對周圍的數據加1,注意要防止出現數組下標為-1的情況(越界)if ((r >= 0 && r < Res::ROW && c >= 0 && c < Res::COL) && map[r][c] != -1){changeValue(r, c, 1);//++map[r][c];}}}}}}//加密格子 遍歷每一個元素,對每一個元素加一個數處理,讓它與原來不同,就不會輸出原來對應的圖片for (int i = 0; i <Res::ROW; i++){for (int k = 0; k <Res::COL; k++){changeValue(i,k,20); //所有的都需要加密}}} array<array<int, 9>, 9>& Data::getMap() {// TODO: 在此處插入 return 語句return map;}timeer.hpp????????定時器制作
#pragma once #include "Common.h" class MyTimer { public:static bool Timer(int duration, int id) //時間間隔 id{static int startTime[10]; //開始時間---靜態變量自動初始化為0int endTime = clock(); //結束時間if (endTime - startTime[id] >= duration)//結束時間-開始時間>=時間間隔{startTime[id] = endTime; //把原來的結束時間改為新的開始時間return true;}return false;} };button.h????????封裝按鈕
#pragma once #include "Common.h" #include"DrawImg.h" class Data; /*———————————————————————————————————————————鼠標按鍵控制 分兩種情況: 1.鼠標是游戲控制的按鍵 2.鼠標是地圖變化的按鍵————————————————————————————————————————————*/ class Button { public:Button(int ImgSize = 24); //地圖變化的按鍵 void ClickButton(ExMessage msg, Data* pData); /*鼠標操作的事件響應: 鼠標點擊...*/void boomBlank(Data* pData,int row,int col); //標記格子和連環炸開空白格子int judge(Data* pData, int row, int col); //游戲結束條件 protected://圖片的大小int ImgSize; };button.cpp
#include "button.h" #include"Common.h" #include"Res.h" #include "Data.h" Button::Button(int ImgSize) {this->ImgSize = ImgSize;Res::DrawIMG(105, 20, "笑臉", 0); }void Button::ClickButton(ExMessage msg, Data* pData) {int r = (msg.x - 16) / ImgSize; //xint c = (msg.y - 84) / ImgSize; //y//游戲控制的邊框if ((msg.x >= 105 && msg.y >= 20) && (msg.x <= 141 && msg.y <= 56)){//printf("%d %d\n", msg.x, msg.y);if (msg.message == WM_LBUTTONDOWN) //左鍵按下還原游戲{Res::DrawIMG(105, 20, "笑臉", 0);for (int i = 0; i < Res::ROW; i++){for (int k = 0; k < Res::COL; k++) {if (pData->getMap()[i][k] >= -1 && pData->getMap()[i][k] <= 8) //數字的還原pData->changeValue(i, k, 20);if(pData->getMap()[i][k] >= 39 && pData->getMap()[i][k] < 59) //旗子的還原pData->changeValue(i, k,-20);if (pData->getMap()[i][k] >= 59) //問號的還原pData->changeValue(i, k, -40);}}}else if (msg.message == WM_RBUTTONDOWN) //右鍵按下開啟bug{Res::DrawIMG(105, 20, "笑臉", 3);for (int i = 0; i < Res::ROW; i++){for (int k = 0; k < Res::COL; k++){if (pData->getMap()[i][k] >= 19 && pData->getMap()[i][k] <= 28)pData->changeValue(i, k, -20);}}}}//地圖的邊框if ((msg.x >= 16 && msg.y >= 84) && (msg.x <= 232 && msg.y <= 300)){//鼠標左鍵按下,有事件響應,左鍵打開格子if (msg.message == WM_LBUTTONDOWN){printf("%d %d\n", msg.x, msg.y);printf("%d %d\n", r, c);//什么時候能夠打開,沒有打開的時候就打開(只能點擊1次有效數字不會再變化)if (pData->getMap()[r][c] >= 19 && pData->getMap()[r][c] <= 28){pData->changeValue(r, c, -20); //map[r][c] -= 20 boomBlank(pData, r, c); //檢測一下是不是空白格子,是,炸開,不是直接退出}}//鼠標右鍵按下,有事件響應,右鍵標記格子else if (msg.message == WM_RBUTTONDOWN){//是否能夠標記:如果沒有打開就能標記if (pData->getMap()[r][c] >= 19 && pData->getMap()[r][c] <= 28){pData->changeValue(r, c, 20); //再次加密 map[r][c] += 20}else if (pData->getMap()[r][c] >= 39 && pData->getMap()[r][c] < 59){pData->changeValue(r, c, 20); //再次點擊能夠出現問號 再次加密 map[r][c] += 20}else if (pData->getMap()[r][c] >= 59) //再次點擊能夠取消格子 雙層解密 map[r][c] -= 20{pData->changeValue(r, c, -40);}}}}void Button::boomBlank(Data* pData, int row, int col) {//判斷row col位置是不是空白格子(如果不是直接退出)if (pData->getMap()[row][col] == 0){for (int r = row - 1; r <= row + 1; r++) //遍歷九宮格,是空白直接炸開{for (int c = col - 1; c <= col + 1; c++){if ((r >= 0 && r < Res::ROW && c >= 0 && c < Res::COL) //沒越界&& pData->getMap()[r][c] >= 19 && pData->getMap()[r][c] <= 28) //沒有打開{pData->changeValue(r, c, -20); //map[r][c] -= 20boomBlank(pData, r, c); //繼續遍歷新的九宮格,繼續打開}}}} } //游戲結束條件 [每點擊一次就判斷一下] 輸了返回 -1 沒結束返回 0 贏了返回 1 int Button::judge(Data* pData, int row, int col) {if (!(row >= 0 && col >= 0 && row< Res::ROW && col< Res::COL)){return 0;}//點到了雷,結束 輸了if (pData->getMap()[row][col] == -1 || pData->getMap()[row][col] == 19) //任何時候都可以判斷{return -1;}//點完了格子,結束 贏了 點開了81 - 10 = 71 個格子(都點開了)int cnt = 0;for (int i = 0; i < Res::ROW; i++){for (int k = 0; k < Res::COL; k++){//統計打開的格子的數量if (pData->getMap()[i][k] >= 0 && pData->getMap()[i][k] <= 8){++cnt; //最終有71個}}}if (Res::ROW * Res::COL - Res::MineNum == cnt){return 1;}return 0; }?DrawImg.h????????繪制圖片
#pragma once #include"Common.h" #include"Data.h" class Data; class Draw { public:Draw();void Game_Draw(); //根據數據畫圖片|數據的處理封裝在Game中void showData();Data* getData() { return pData; }int& getTime() { return timeCnt; } protected:Data* pData; //游戲需要用到數據,包含數據的指針int timeCnt = 0; //秒數變量 };?DrawImg.cpp?
#include "DrawImg.h" #include"Res.h" #include"Data.h" #include"time.hpp" Draw::Draw():pData(new Data) {pData->Set();//背景initgraph(Res::WIDTH("背景"), Res::HEIGHT("背景"), EW_SHOWCONSOLE);Res::Draw_IMG(0, 0, "背景");Res::Draw_IMG(21, 21, "0_");Res::Draw_IMG(21 + 20, 21, "1_");Res::Draw_IMG(21 + 20 * 2, 21, "0_");Res::Draw_IMG(21 + 20 * 6 + 25, 21, "0_");Res::Draw_IMG(21 + 20 * 8 + 4, 21, "0_");Res::Draw_IMG(21 + 20 * 9 + 4, 21, "0_"); } void Draw::showData() {for (int i = 0; i < Res::ROW; i++){for (int k = 0; k < Res::COL; k++){cout << pData->getMap()[k][i] << "\t";}cout << endl;}cout << endl; } void Draw::Game_Draw() {int ge=0, shi=0, bai=0;if (MyTimer::Timer(1000, 0)){getTime()++; //秒數變量的疊加}ge = getTime() % 10;shi = getTime() / 10 % 10;bai = getTime() / 100; //geRes::Draw_IMG(21 + 20 * 9 + 4, 21,to_string(ge) + "_"); //shiRes::Draw_IMG(21 + 20 * 8 + 4, 21, to_string(shi) + "_"); //baiRes::Draw_IMG(21 + 20 * 6 + 25, 21, to_string(bai) + "_");for (int i = 0; i < Res::ROW; i++){for (int k = 0; k < Res::COL; k++){//周圍全是雷中間是8---周圍沒有雷中間是0if (pData->getMap()[i][k] >= 0 && pData->getMap()[i][k] <= 8) //范圍[0,8]{ switch (pData->getMap()[i][k]) { //0 1 2 3 4 5 6 7 case 0:Res::DrawIMG(16 + 24 * i, 84 + 24 * k, "磚塊",1); break;case 1: Res::Draw_IMG(16 + 24 * i, 84 + 24 * k, "0"); //對應數字1break;case 2: Res::Draw_IMG(16 + 24 * i, 84 + 24 * k, "1"); //對應數字2break; case 3: Res::Draw_IMG(16 + 24 * i, 84 + 24 * k,"2"); //對應數字3break; case 4: Res::Draw_IMG(16 + 24 * i, 84 + 24 * k, "3"); //對應數字4break; case 5: Res::Draw_IMG(16 + 24 * i, 84 + 24 * k, "4"); //對應數字5break; case 6: Res::Draw_IMG(16 + 24 * i, 84 + 24 * k, "5"); //對應數字6break; case 7: Res::Draw_IMG(16 + 24 * i, 84 + 24 * k, "6"); //對應數字7break;case 8:Res::Draw_IMG(16 + 24 * i, 84 + 24 * k, "7"); //對應數字8break;}}else if (pData->getMap()[i][k] == -1){Res::DrawIMG(16 + 24 * i, 84 + 24 * k, "地雷",0);}else if (pData->getMap()[i][k] >= 19 && pData->getMap()[i][k] <= 28) //畫蓋子---范圍判斷 最小和最大的{Res::DrawIMG(16 + 24 * i, 84 + 24 * k, "磚塊",0);}else if (pData->getMap()[i][k] >= 39 && pData->getMap()[i][k] < 59) //-1 + 20 + 20{Res::DrawIMG(16 + 24 * i, 84 + 24 * k,"標識",0); //旗子}else if (pData->getMap()[i][k] >= 59){Res::DrawIMG(16 + 24 * i, 84 + 24 * k, "標識", 1);//問號}}} }掃雷.cpp? ? ? ? 主函數部分
#include"DrawImg.h" #include"Data.h" #include"button.h" #include"Res.h" int main() {Draw draw;Button* pp = new Button(); //按鈕ExMessage msg; //定義鼠標消息while (true){while (peekmessage(&msg, EM_MOUSE)) //獲取鼠標消息{switch (msg.message){case WM_LBUTTONDOWN: //鼠標左鍵和右鍵點擊case WM_RBUTTONDOWN:pp->ClickButton(msg, draw.getData());draw.showData(); //顯示數據int ret=pp->judge(draw.getData(), (msg.x - 16) / 24, (msg.y - 84) / 24); //每點擊一次,判斷一次printf("judge:%d\n", ret); //根據返回值判斷是贏了還是輸了if (ret == -1) //輸了,輸出哭臉|彈出對話框{ //句柄|對話|標題|按鈕draw.Game_Draw(); //繪制Res::DrawIMG(105, 20, "笑臉", 2);Res::DrawIMG(16 + 24 * ((msg.x - 16) / 24), 84 + 24 * ((msg.y - 84) / 24), "地雷", 1);int select_1=MessageBox(GetHWnd(), "不會吧?初級掃雷都玩不過?敢不敢再來一把?", "c++掃雷",MB_OKCANCEL); //看用戶的選擇if (select_1 == IDOK) //再來一把{//重新初始化 Res::DrawIMG(105, 20, "笑臉", 0);draw.getTime() = 0;draw.getData()->Set();}else //退出{ exit(0);}}else if (ret == 1) //贏了,輸出帥臉|彈出對話框{Res::DrawIMG(105, 20, "笑臉", 1);int select_2 = MessageBox(GetHWnd(), "不錯哦!要不要再來一把?", "c++掃雷", MB_OKCANCEL);if (select_2 == IDOK) //再來一把{//重新初始化draw.getData()->Set();Res::DrawIMG(105, 20, "笑臉", 0);}else //退出{exit(0);}}break;}}draw.Game_Draw(); //繪制}return 0; }部分素材展示
總結
以上是生活随笔為你收集整理的Easyx-----c++实现经典Windows扫雷的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Good Luck!(KMP)
- 下一篇: a50指数的研究,大家知道A50指数的有