掃雷程序的實現


用了一個星期,終於把掃雷做的差不多了,其中遇到很多很多問題,但慢慢解決了,確實挺令人高興,也許這就是編程的魅力所在吧。

 

下面記錄掃雷的主要幾個算法:

一:布雷

 1 void CMineButton::Reset(CWnd* pParent)//參考與小張上傳中的程序,,對butto進行初始化
 2 {
 3         
 4     CMINEMFCApp *app = (CMINEMFCApp *)AfxGetApp(); 
 5 
 6     app->m_pParent = pParent;
 7 
 8     int nI;
 9 
10     for(nI=0;nI<100;nI++)
11     {
12         if (app->m_aLandMine[nI]!=NULL)
13             delete app->m_aLandMine[nI];
14     }
15     for(nI=0;nI<100;nI++)
16     {
17     
18         app->m_aLandMine[nI] = new CMineButton;
19     
20     }
21 
22     
23     int nCurMines=0;
24     int nCurMine;
25     int curi = 0;
26     srand( (unsigned)time( NULL ));
27 
28     while(nCurMines<10)
29     {
30         nCurMine=rand()%(100);//獲取10個雷的分布
31         (app->m_theRealMine[curi]) = nCurMine;
32         if(app->m_aLandMine[nCurMine]->GetMineNum() != -1)//該寫法的作用是初始化10個雷周圍button的雷的數量
33         {
34             app->m_aLandMine[nCurMine]->SetMineNum(-1);
35             int nMineRound,nMineRound1;
36             //right;
37             nMineRound = app->m_aLandMine[nCurMine]->GetRight(nCurMine);
38             if(nMineRound>=0)
39             {
40                 if (app->m_aLandMine[nMineRound]->GetMineNum() != -1)
41                     ++(*app->m_aLandMine[nMineRound]);
42                 //right top
43                 nMineRound1 = (app->m_aLandMine[nMineRound]->GetTop(nMineRound));
44                 if(nMineRound1>=0 && app->m_aLandMine[nMineRound1]->GetMineNum() != -1)
45                 {
46                     ++(*app->m_aLandMine[nMineRound1]);
47                 }
48                 //right bottom
49                 nMineRound1 = app->m_aLandMine[nMineRound]->GetBot(nMineRound);
50                 if(nMineRound1>=0 && app->m_aLandMine[nMineRound1]->GetMineNum() != -1)
51                 {
52                     ++(*app->m_aLandMine[nMineRound1]);
53                 }
54             }            
55             //left
56             nMineRound = app->m_aLandMine[nCurMine]->GetLeft(nCurMine);
57             if(nMineRound>=0)
58             {
59                 if(app->m_aLandMine[nMineRound]->GetMineNum() != -1)
60                     ++(*app->m_aLandMine[nMineRound]);
61         
62                 //Left top
63                 nMineRound1 = app->m_aLandMine[nMineRound]->GetTop(nMineRound);
64                 if(nMineRound1>=0 && app->m_aLandMine[nMineRound1]->GetMineNum() != -1)
65                 {
66                     ++(*app->m_aLandMine[nMineRound1]);
67                 }
68                 
69                 //Left bottom
70                 nMineRound1 =  app->m_aLandMine[nMineRound]->GetBot(nMineRound);
71                 if(nMineRound1>=0 && app->m_aLandMine[nMineRound1]->GetMineNum() !=分公司的72                 {
73                     ++(*app->m_aLandMine[nMineRound1]);
74                 }
75             }
76             //Top
77             nMineRound = app->m_aLandMine[nCurMine]->GetTop(nCurMine);
78             if(nMineRound>=0 && app->m_aLandMine[nMineRound]->GetMineNum() != -1)
79             {
80                 ++(*app->m_aLandMine[nMineRound]);
81             }
82 
83             //Bottom
84             nMineRound = app->m_aLandMine[nCurMine]->GetBot(nCurMine);
85             if(nMineRound>=0 && app->m_aLandMine[nMineRound]->GetMineNum() != -1)
86             {
87                 ++(*app->m_aLandMine[nMineRound]);
88             }
89             nCurMines++;
90             curi ++ ;
91         }
92     }
93 }

二:空白雷區的實現

 

 

BOOL CMINEMFCDlg::RecordMine(int nCurMine)//也是根據另一個程序打開空白的周圍的算法,,是一個循環隊列的使用
{ CMINEMFCApp *app = (CMINEMFCApp *)AfxGetApp(); int nRoundMine,nRoundMine1; int aMine[500]; int nTop=0,nTail=0; aMine[nTop++] = nCurMine; while(nTop!=nTail) { int nCurrent=aMine[nTail]; nTail = (nTail+1)%500; switch((app->m_aLandMine[nCurrent])->OpenMine(nCurrent)) { case 0:        // Mine number is zero
            nRoundMine = (app->m_aLandMine[nCurrent])->GetLeft(nCurrent); if(nRoundMine!=-1) { aMine[nTop] = nRoundMine; nTop = (nTop+1)%500; nRoundMine1 = (app->m_aLandMine[nCurrent])->GetTop(nRoundMine); if(nRoundMine1!=-1) { aMine[nTop] = nRoundMine1; nTop = (nTop+1)%500; nRoundMine1 = (app->m_aLandMine[nCurrent])->GetTop(nRoundMine); } nRoundMine1 = (app->m_aLandMine[nCurrent])->GetBot(nRoundMine); if(nRoundMine1!=-1) { aMine[nTop] = nRoundMine1; nTop = (nTop+1)%500; nRoundMine1 = (app->m_aLandMine[nCurrent])->GetTop(nRoundMine); } } nRoundMine = (app->m_aLandMine[nCurrent])->GetRight(nCurrent); if(nRoundMine!=-1) { aMine[nTop] = nRoundMine; nTop = (nTop+1)%500; nRoundMine1 = (app->m_aLandMine[nCurrent])->GetTop(nRoundMine); if(nRoundMine1!=-1) { aMine[nTop] = nRoundMine1; nTop = (nTop+1)%500; nRoundMine1 = (app->m_aLandMine[nCurrent])->GetTop(nRoundMine); } nRoundMine1 = (app->m_aLandMine[nCurrent])->GetBot(nRoundMine); if(nRoundMine1!=-1) { aMine[nTop] = nRoundMine1; nTop = (nTop+1)%500; nRoundMine1 = (app->m_aLandMine[nCurrent])->GetTop(nRoundMine); } } nRoundMine = (app->m_aLandMine[nCurrent])->GetTop(nCurrent); if(nRoundMine!=-1) { aMine[nTop] = nRoundMine; nTop = (nTop+1)%500; } nRoundMine = (app->m_aLandMine[nCurrent])->GetBot(nCurrent); if(nRoundMine!=-1) { aMine[nTop] = nRoundMine; nTop = (nTop+1)%500; } break; case 1: break; case -1: return FALSE;        // fail
 } } return TRUE; }

下面講講自己遇到的一些困難和新get的技能吧:

1,invalidate函數

 

Invalidate()之后:(MFC的,順便了)
OnPaint()->OnPrepareDC()->OnDraw()
所以只是刷新在OnPaint()和OnDraw()函數中的繪圖語句。其它地方沒有影響。

Invalidate標記一個需要重繪的無效區域,並不意味着調用該函數后就立刻進行重繪。類似於PostMessage(WM_PAINT),需要處理到WM_PAINT消息時才真正重繪。以為您Invalidate之后還有其他的語句正在執行,程序沒有機會去處理WM_PAINT消息,但當函數執行完畢后,消息處理才得以進行。

Invalidate只是放一個WM_PAINT消息在隊列里,不做別的,所以只有當當前函數返回后,進入消息循環,取出WM_PAINT,才執行PAINT,所以不管Invalidate放哪里,都是最后的。

 

其實我遇到了就是把drawbutton放在了onpaint里面,導致其不斷的刷新。。。。

 

invalidateRect是通過消息來調用OnPaint
RedrawWindow除了有InvalidateRect的效果,還會立即調用一次OnPaint(不經過消息隊列,類似 UpdateWindow),這個redrawwindow會立即調用ONpaint。

2.

解決 unresolved external symbol 無法解析 _send@16

 

這個一般都是lib庫沒有設置好而導致的。。

 

 

3, 

VC6.0常見錯誤之::Debug Assertion Failed!

 

這個比較多,,發一個網址吧http://blog.csdn.net/xjkstar/article/details/6922259。

 

3

//聲明:
SetWindowPos(
  hWnd: HWND;            {窗口句柄}
  hWndInsertAfter: HWND; {窗口的 Z 順序}
  X, Y: Integer;         {位置}
  cx, cy: Integer;       {大小}
  uFlags: UINT           {選項}
): BOOL;

//hWndInsertAfter 參數可選值:
HWND_TOP       = 0;        {在前面}
HWND_BOTTOM    = 1;        {在后面}
HWND_TOPMOST   = HWND(-1); {在前面, 位於任何頂部窗口的前面}
HWND_NOTOPMOST = HWND(-2); {在前面, 位於其他頂部窗口的后面}

//uFlags 參數可選值:
SWP_NOSIZE         = 1;    {忽略 cx、cy, 保持大小}
SWP_NOMOVE         = 2;    {忽略 X、Y, 不改變位置}
SWP_NOZORDER       = 4;    {忽略 hWndInsertAfter, 保持 Z 順序}
SWP_NOREDRAW       = 8;    {不重繪}
SWP_NOACTIVATE     = $10{不激活}
SWP_FRAMECHANGED   = $20{強制發送 WM_NCCALCSIZE 消息, 一般只是在改變大小時才發送此消息}
SWP_SHOWWINDOW     = $40{顯示窗口}
SWP_HIDEWINDOW     = $80{隱藏窗口}
SWP_NOCOPYBITS     = $100; {丟棄客戶區}
SWP_NOOWNERZORDER  = $200; {忽略 hWndInsertAfter, 不改變 Z 序列的所有者}
SWP_NOSENDCHANGING = $400; {不發出 WM_WINDOWPOSCHANGING 消息}
SWP_DRAWFRAME      = SWP_FRAMECHANGED; {畫邊框}
SWP_NOREPOSITION   = SWP_NOOWNERZORDER;{}
SWP_DEFERERASE     = $2000;            {防止產生 WM_SYNCPAINT 消息}
SWP_ASYNCWINDOWPOS = $4000;            {若調用進程不擁有窗口, 系統會向擁有窗口的線程發出需求}

//舉例:
procedure TForm1.Button1Click(Sender: TObject);
begin
  SetWindowPos(Handle, HWND_TOPMOST, 0,0, 100,200, SWP_SHOWWINDOW);
end;

4,在鼠標右擊響應函數中這樣來寫

BOOL CMINEMFCDlg::PreTranslateMessage(MSG* pMsg) //對於右擊鼠標的響應
{ // TODO: Add your specialized code here and/or call the base class
    CMINEMFCApp *app = (CMINEMFCApp *)AfxGetApp(); CClientDC dc(this); CFont font; font.CreateFont(20, 15, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, 0, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,   DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, _T("新宋體")); CFont *pOldFont=dc.SelectObject(&font); dc.SetBkColor(RGB(237,237,237)); if(pMsg->message==WM_RBUTTONDOWN)//鼠標點擊右鍵
 { CRect rc; CPoint ptCursor; ::GetCursorPos(&ptCursor);//獲取鼠標的位置信息
          int pos; for(pos=159;pos<259;pos++) { GetDlgItem(pos)-> GetWindowRect(&rc);//獲取控件的位置信息
            
        
               if(PtInRect(&rc,ptCursor))//右鍵點擊位置在某一個控件上
 { CMineButtonVisual* pMineButton = (CMineButtonVisual*)GetDlgItem(pos); if(pMineButton->rButClickedFlags  == 0) { SetDlgItemText(pos,""); pMineButton->rButClickedFlags = (pMineButton->rButClickedFlags +1)%3; m_recordRealMine[m_recordRealMineFlags] = pos; m_recordRealMineFlags ++ ; CString str; str.Format("剩余雷數:%d",(10-m_recordRealMineFlags)); GetDlgItem(IDC_STATIC_MINENUM)->SetWindowText(str); } else if(pMineButton->rButClickedFlags  == 1) { SetDlgItemText(pos,"?"); pMineButton->rButClickedFlags  =(pMineButton->rButClickedFlags +1)%3; m_recordRealMineFlags -- ; CString str; str.Format("剩余雷數:%d",(10-m_recordRealMineFlags)); GetDlgItem(IDC_STATIC_MINENUM)->SetWindowText(str); } else { SetDlgItemText(pos," "); pMineButton->rButClickedFlags  = (pMineButton->rButClickedFlags +1)%3; } //m_minenum--; //if(flg[pos-1000]==1) //mine[0]--;
 } } if(m_recordRealMineFlags == 10) { int curflags = 0; for(int curj = 0;curj<m_recordRealMineFlags;curj++) for(int curi = 0;curi<10;curi++) { if (m_recordRealMine[curi] == (app->m_theRealMine[curj]+159)) { curflags ++ ; break; } } if(curflags == 10) { MessageBox("恭喜你!!!掃雷成功!!你碉堡了!!!"); bFail = 1; } } // GetDlgItem(1100)-> GetWindowRect(&rc);//獲取開始按鈕的位置信息
         /*if(PtInRect(&rc,ptCursor))//右鍵點擊位置在某一個控件上 { for(int i=1;i<=mine[0];i++) { SetDlgItemText(mine[i]+1000,"*"); } }*/ } return CDialog::PreTranslateMessage(pMsg); }

5.ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1, IDC_BUTTON10, OnButtonClicked)的使用。

 

6.創建一個指針,,delete掉。

    for(int curi = 0; curi < 100 ;curi++) { if(m_btn[curi]->m_hWnd != 0) { delete m_btn[curi]; m_btn[curi] = new CMineButtonVisual; } }

7.定時器的用法

 

settimer(1,1000,null)

ontimer()則響應。

killtimer則銷毀settimer

 

最后附一張截圖,,紀念一下自己寫的第一個游戲。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM