Windows扫雷的设计思路与实现
????? 最近花了個把星期左右把Windows xp的掃雷實現了一下,在這里寫下設計思路與大概實現。這個是下載地址,
歡迎大家下載試玩,http://kuai.xunlei.com/d/LTACJFIRFVKB。其實其中還有有個隱藏的bug。看看你能不能發現,哈哈。源代碼我以后會補上,暫時不能上傳,請各位諒解!
???? 既然是游戲的話,只有會玩了才有可能知道是怎么實現的!數字n代表以它為中心3*3的方格范圍內
有n個雷。主要就是根據這個來判斷是否有雷。然后是空格子的話就代表它周圍沒有雷。然后就是鼠標的各種事件了。下面這個是一個列表。
之后主要是按照這個寫的,也有些改動,但是不大。
1.左鍵按下
?1.1.右鍵按下
??3*3方格變形
?1.2.右鍵未被按下
??當前方格變形
LBtnDown = TRUE;
2.右鍵按下
?2.1.左鍵按下
??3*3方格變形
?2.1.左鍵未被按下
??當前方格變形
RBtnDown = TRUE;
3.左鍵彈起
?3.1.之前左右鍵按下
??3.1.1.該數字的雷被找到
???調用展開算法 右鍵彈起失效
???RBtnDown = FALSE;
??3.1.2.沒找到
???3*3方格復原 右鍵彈起失效
???標記標多了也會調用展開算法
???RBtnDown = FALSE;??
?3.2.之前左鍵按下
??當前位置方格調用展開算法
LBtnDown = FALSE;
4.右鍵彈起
?4.1.之前左右鍵按下
??4.1.1.該數字的雷被找到
???調用展開算法 左鍵彈起失效
???LBtnDown = FALSE;
??4.1.2.沒找到
???3*3方格復原 左鍵彈起失效
?標記標多了也會調用展開算法
???LBtnDown = FALSE;
RBtnDown = FALSE;
5.鼠標滾動
?5.1.左鍵按下
??5.1.1.右鍵按下
???3*3方格移動
??5.1.2.右鍵彈起
???一個方格移動
這個是雷區初始化的代碼。主要就是先寫邊界,然后把前面n個元素改成雷,最后隨機分布。
?
void CMineView::SetMine() {int i, j, currenti, currentj, i1, i2, j1, j2;currenti = m_mine.minenumber % m_mine.width;if (currenti == 0) {//剛好除盡currenti = m_mine.minenumber/m_mine.width;currentj = m_mine.width;for (i = 1; i <= currenti; i++) {for (j = 1; j <= m_mine.width; j++) {m_mineMax[i][j] = -1;//初始化雷區}}currenti++;currentj = 1;} else {//除不盡currenti = (m_mine.minenumber/m_mine.width)+1;currentj = m_mine.minenumber%m_mine.width;for (i = 1; i < currenti; i++) {for (j = 1; j <= m_mine.width; j++) {m_mineMax[i][j] = -1;//初始化雷區}}for (j = 1; j <= currentj; j++) {m_mineMax[currenti][j] = -1;//初始化雷區}currentj++;}//初始化不是雷區的區域for (j = currentj; j <= m_mine.width; j++) {m_mineMax[currenti][j] = 0;}++currenti;for (i = currenti; i <= m_mine.height; i++) {for (j = 1; j <= m_mine.width; j++) {m_mineMax[i][j] = 0;}}srand(time(NULL));for (i = m_mine.height * m_mine.width - 1; i >= 2; --i) {//布雷currenti = rand() % i;//產生的隨機位置if (i%m_mine.width == 0) {//除的盡i1 = i / m_mine.width;j1 = m_mine.width;} else {//除不盡i1 = (i / m_mine.width) + 1;j1 = i % m_mine.width;}if (currenti == 0) {//就是第一個i2 = 1;j2 = 1;} else {if (currenti%m_mine.width == 0) {//除的盡i2 = currenti / m_mine.width;j2 = m_mine.width;} else {//除不盡i2 = (currenti / m_mine.width) + 1;j2 = currenti % m_mine.width;}}Swap(&m_mineMax[i1][j1], &m_mineMax[i2][j2]);} }
?? 展開算法的主要思路就是用一個大的數組(包括虛擬邊界)保存該算法對每一個方格的訪問次數的計數。
==1就不在訪問,分8個方向遞歸探測。碰到雷或者邊界就返回。具體代碼如下:
?
//8個方向探測 void CMineView::StretchMine(int i, int j) {if (m_mineVisit[i][j] == 1) {//走過的路不再走return ;}if (m_mineMax[i][j] == -2) {//碰壁了return ;}if (m_mineMax[i][j] == -1) {//撞雷了return ;} else {//上右下左遞歸探測if (m_minePic[i][j] != 1) {m_minePic[i][j] = 15 - m_mineMax[i][j];//根據位圖中數字的關系得到的公式} else {m_minePic[i][j] = 4;}if (m_mineMax[i][j] > 0) {//碰到了數字 就停止m_mineVisit[i][j] = 1;//已訪問return ;}m_mineVisit[i][j] = 1;//只有走得通的路才會被訪問,訪問次數+1StretchMine(i-1, j-1);StretchMine(i-1, j);//上邊StretchMine(i-1, j+1);StretchMine(i, j+1);//右邊StretchMine(i+1, j);//下邊StretchMine(i+1, j-1);StretchMine(i+1, j+1);之前碰到困難就是各個類直接自定義消息所用的句柄的獲取,最難的那個就是模態對話框和CMainFrame類的通信,最后發現,模態對話框在DoModal
之前會調用oninitdialog,在oninitdialog里面可以把句柄傳出來,這才實現了不同級別的繪制。然后就是繪圖了,主要還是用到了雙緩沖,之前雙緩沖
用的很不正宗,后來改了改,用了3個cdc對象,一個選擇位圖,一個裝圖像,然后把這個最后bitblt到pDC當中。這樣就避免了屏幕閃爍。
?繪圖代碼很固定。鼠標的各種消息會改變繪圖的數據,實現了動態繪制。我感覺難點還是在于理解鼠標各個事件。我花了1天多時間,結果沒
寫好,之后冷靜了想了下,然后把各種消息記錄下來。用的多的代碼寫成函數方便調用。
? 本身掃雷沒啥難的,只要你會玩了,你就基本上知道怎么寫了。就說這多把。大學已經結束了,已經要開始找工作了,這里預祝和我一樣的這些畢業生
早點找到一個合適的工作!90后 up!You can make it!
總結
以上是生活随笔為你收集整理的Windows扫雷的设计思路与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 5G蝴蝶效应:孕育万亿级产业
- 下一篇: java信息管理系统总结_java实现科