扫雷程序的实现


用了一个星期,终于把扫雷做的差不多了,其中遇到很多很多问题,但慢慢解决了,确实挺令人高兴,也许这就是编程的魅力所在吧。

 

下面记录扫雷的主要几个算法:

一:布雷

 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