用了一个星期,终于把扫雷做的差不多了,其中遇到很多很多问题,但慢慢解决了,确实挺令人高兴,也许这就是编程的魅力所在吧。
下面记录扫雷的主要几个算法:
一:布雷
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
最后附一张截图,,纪念一下自己写的第一个游戏。