《2022年完整word版,C++扫雷.docx》由会员分享,可在线阅读,更多相关《2022年完整word版,C++扫雷.docx(28页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精选学习资料 - - - - - - - - - 扫雷1 1 嬉戏实现扫雷,是附带在 Window 里面的嬉戏, 是个简洁的嬉戏;因此我们就从扫雷开头我们的嬉戏旅程; 许多人都玩过这个嬉戏,只是不知道怎么用程序实现;不过仍有人不知道怎么玩,下面就先说说嬉戏的规章:开头:按左键开头嬉戏,按按钮或菜单重新开头;左键:按下时,是雷就终止,非雷就显示数字;数字:代表此数字四周一圈八格中雷的个数;右键:奇次按下表示雷,偶数按下表示对上次的否定;终止:左键按到雷终止,找出全部雷终止;接下来就该介绍嬉戏的编程过程了;不过要先交代一下一些内容;名师归纳总结 添加位图;第 1 页,共 15 页- - - - -
2、 - -精选学习资料 - - - - - - - - - 添加全局变量;画初始界面;可能要用到位图或变量,而变量的添加函数;为什么要按这种次序呢?由于我们在画初始界面时,定义又可能要对位图进行定义;这样的步骤的好处仍有:在做一步之后都可以运行,有错就改,无错就做下一步;上图是扫雷的一个画面;下面就一步一步地演示,以编程的思路进行,当然,由于编程过程中有一些函数中的代码是分成两三次写的,我们就不重复, 全部代码在第一次讲到时列出,而后面讲到时就只是提一下;新建单文档工程 2_1;2 2 资源编辑添加位图:前十二幅是在雷区的,后四幅是按钮;为了便于加载,必需各自保证其连续性;另外,为什么不添加一个
3、按钮而用位图呢?是由于即使我们添加了按钮也要添加四幅位图!位图的 ID 号:名师归纳总结 按扭位图:30*30 IDB_ANNIU1 、IDB_ANNIU 2、IDB_ANNIU3、 IDB_ANNIU4 第 2 页,共 15 页雷区位图:14*14 ID 号按下图依次为:IDB_BITMAP14;IDB_BITMAP25 位图:下图(图2-1);- - - - - - -精选学习资料 - - - - - - - - - 图 2-1 位图的 ID 号:按扭位图 30*30 IDB_BITMAP1 、IDB_BITMAP2、IDB_BITMAP3 、 IDB_BITMAP4 雷区位图 14*14
4、 ID 号按下图依次为:IDB_BITMAP5 IDB_BITMAP16 1 2 3 45 6 7 8 9 1011 12 13 14 15 16icon 3 3 变量函数名师归纳总结 - - - - - - -第 3 页,共 15 页精选学习资料 - - - - - - - - - 定义新类:对于雷,我们是单独定义一个类,这样有利于程序的操作;class Lei Mine public: /显示哪一个位图 int weitu; bitmap/这个位置相应的值 int shumu; index ; 并有如下规定(图 2-2):图 2-2 视图类变量:接着是在 View 类添加变量和函数:/剩下
5、雷数 int leftnum; /雷数 int leinum; minenum/终止 int jieshu; endflag /计时 short second; /开头计时 int secondstart; /位图数组 CBitmap m_Bitmap12; bitmap/按扭位图数组 CBitmap m_anniu4; button/雷区行数 int m_RowCount; row/雷区列数 int m_ColCount; line /最大雷区Lei lei5050; Mine mine/这个位置四周雷数为 0 void leizero; /计时器函数afx_msg void OnTimer
6、UINT nIDEvent; /鼠标按下左键 afx_msg void OnLButtonDownUINT nFlags, CPoint point; /鼠标按下右键 afx_msg void OnRButtonDownUINT nFlags, CPoint point; /初始化函数名师归纳总结 - - - - - - -第 4 页,共 15 页精选学习资料 - - - - - - - - - afx_msg int OnCreateLPCREATESTRUCT lpCreateStruct; /鼠标左键松开 afx_msg void OnLButtonUpUINT nFlags, CPoi
7、nt point; 4 4 详细实现删去状态栏和工具栏:开头执行程序, 就能见到一个有状态栏和工具栏的大的单文档,第一步就是整理框架:打开下面函数,把里面的一些语句去掉;如下所示:与上图不同, 所以我们int CMainFrame:OnCreateLPCREATESTRUCT lpCreateStruct if CFrameWnd:OnCreatelpCreateStruct = -1 return -1; /* if .m_wndToolBar.CreateExthis, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | | CBRS_TOP | CBRS_GRIP
8、PER | CBRS_TOOLTIPS | CBRS_FL YBY CBRS_SIZE_DYNAMIC | .m_wndToolBar.LoadToolBarIDR_MAINFRAME TRACE0Failed to create toolbarn; return -1; / fail to create if .m_wndStatusBar.Createthis | .m_wndStatusBar.SetIndicatorsindicators, sizeofindicators/sizeofUINT */ TRACE0Failed to create status barn; return
9、 -1; / fail to create / TODO: Delete these three lines if you dont want the toolbar to / be dockable m_wndToolBar.EnableDockingCBRS_ALIGN_ANY; EnableDockingCBRS_ALIGN_ANY; DockControlBar&m_wndToolBar; return 0; 设置窗口大小:运行附加的代码,仍能看到扫雷嬉戏的框架是不能调大小的,而且总是显示在最前面,这又是怎么实现的呢?在下面函数里添加语句,你能说出前三句是什么意思吗?注释已经被我去掉了
10、,假如不知道,不如按一下 F1;BOOL CMainFrame:PreCreateWindowCREATESTRUCT& cs if .CFrameWnd:PreCreateWindowcs return FALSE; / TODO: Modify the Window class or styles here by modifying 名师归纳总结 - - - - - - -第 5 页,共 15 页精选学习资料 - - - - - - - - - / the CREATESTRUCT cs cs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST; / cs.style
11、=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;/; /设置窗口大小:400*340 cs.cx=400; cs.cy=340; return TRUE; 构造函数:由于构造函数是程序运行时就执行的,所以, 除了对变量赋值之外,我们仍可以把嬉戏的核心结构即内部数组赋值:先是把全部格子的位图和雷数赋值为0,然后调用随机函数按指定雷数赋值为-1,最终把不是雷的格子的雷数赋值为相应的值;CMy2_1View:CMy2_1View / TODO: add construction code here forint ii=0;ii16;ii+ m_Bitmapii.Lo
12、adBitmapIDB_BITMAP14+ii; forint jj=0;jj4;jj+ m_anniujj.LoadBitmapIDB_ANNIU1+jj; /计时 second=0; /1 时开头计时secondstart=0; /行数 m_RowCount=25; /列数 m_ColCount=16; /雷数 leinum=80; /剩余雷数leftnum=leinum; /jieshu=1 时停止 jieshu=0; int aa=0; /初始化为 0 forint i=0;im_RowCount;i+ forint j=0;jm_ColCount;j+ leiij.shumu=0;
13、leiij.weitu=0; /猎取当前时间 CTime time=GetCurrentTime; int s; /猎取秒数 s=time.GetSecond; /设置 40 个雷 do 名师归纳总结 - - - - - - -第 6 页,共 15 页精选学习资料 - - - - - - - - - /以当前秒数为产生随机算法int k=rand*s%m_RowCount; int l=rand*s%m_ColCount; /为了防止一个位置同时算两个雷/只答应当前位置不是雷时赋值为雷ifleikl.shumu.=-1 leikl.shumu=-1; aa+; whileaa.=leinum;
14、 /给方格赋值,运算雷数forint a=0;am_RowCount;a+ forint b=0;bm_ColCount;b+ ifleiab.shumu=0 forint c=a-1;ca+2;c+ forint d=b-1;d=0&c=0&dFillRectmyrect1,&mybrush1; /画黑框 CBrush mybrush; mybrush.CreateSolidBrushRGB0,0,0; CRect myrect20,10,70,40; pDC-FillRectmyrect,&mybrush; CRect myrect2325,10,375,40; pDC-FillRectm
15、yrect2,&mybrush; CPen mypen; 名师归纳总结 - - - - - - -第 7 页,共 15 页精选学习资料 - - - - - - - - - CPen*myoldPen; mypen.CreatePenPS_SOLID,2,RGB255,255,255; myoldPen=pDC-SelectObject&mypen; /画黑框的白线pDC-MoveTo20,40; pDC-LineTo70,40; pDC-LineTo70,10; pDC-MoveTo325,40; pDC-LineTo375,40; pDC-LineTo375,10; /画雷区边线/左上角是白
16、线,右下角是黑线,以显示立体感forint i=0;im_RowCount;i+ forint j=0;jMoveTo10+i*15,50+j*15+14; pDC-LineTo10+i*15,50+j*15; pDC-LineTo10+i*15+14,50+j*15; pDC-SelectObjectmyoldPen; CPen mypen2; CPen*myoldPen2; mypen2.CreatePenPS_SOLID,1,RGB0,0,0; myoldPen2=pDC-SelectObject&mypen2; forint ii=0;iim_RowCount;ii+ forint j
17、j=0;jjMoveTo10+ii*15,50+jj*15+14; pDC-LineTo10+ii*15+14,50+jj*15+14; pDC-LineTo10+ii*15+14,50+jj*15; pDC-SelectObjectmyoldPen2; CDC Dc; ifDc.CreateCompatibleDCpDC=FALSE AfxMessageBoxCant create DC; /显示按钮Dc.SelectObjectm_anniu0; pDC-BitBlt180,10,160,160,&Dc,0,0,SRCCOPY; /判定显示什么位图/weitu=1 已按下的数字区/weit
18、u=2 显示旗/weitu=3 显示问号forint a=0;am_RowCount;a+ forint b=0;bBitBlta*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY; ifleiab.weitu=2 Dc.SelectObjectm_Bitmap9; pDC-BitBlta*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY; 名师归纳总结 - - - - - - -第 8 页,共 15 页精选学习资料 - - - - - - - - - ifleiab.weitu=3 Dc.SelectObjectm_Bitmap10; pD
19、C-BitBlta*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY; /终止ifjieshu=1&leiab.shumu=-1 Dc.SelectObjectm_Bitmap11; pDC-BitBlta*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY; Dc.SelectObjectm_anniu3; pDC-BitBlt180,10,160,160,&Dc,0,0,SRCCOPY; /显示黑框里的数字int nOldDC=pDC-SaveDC; pDC-SetTextColorRGB255,0,0; pDC-SetBkColorRGB
20、0,0,0; CFont font; if0=font.CreatePointFont160,Comic Sans MS AfxMessageBoxCant Create Font; pDC-SelectObject&font; CString str; /利用判定显示位数,不够三位前面加ifleftnumTextOut25,10,str; ifsecond10 str.Format00%d,second; else ifsecondTextOut330,10,str; pDC-RestoreDCnOldDC; 0 玩; 运行一下, 外观已经出来了,只是仍不能玩;当然, 假如你对程序已经有肯定
21、的体会的话,那我们就来添加一些功能函数,使它可以你就会指出上面的函数太长了;这并不太符合我们编程的要求;我们编程有一个讲究,就是尽量使函数的代码少,一般为一页左右,便于查看; 那么,我们可以把上面的函数细分为几个小函数,按下鼠标左键:然后在这个函数里面分别调用;用 if 语句判定,假如在按钮上面,就显示按钮按下位图;假如在扫雷区,先把按钮位 图改为张口位图,再判定按下的是否是雷,是就终止,重画,以显示全部的雷;否就,重画相应格子以显示数字;名师归纳总结 - - - - - - -第 9 页,共 15 页精选学习资料 - - - - - - - - - void CMy2_1View:OnLBu
22、ttonDownUINT nFlags, CPoint point / TODO: Add your message handler code here and/or call default /猎取指针 pdc CDC *pDC=GetDC; CDC Dc; ifDc.CreateCompatibleDCpDC=FALSE AfxMessageBoxCant create DC; /显示按下按钮 ifpoint.x180&point.x10&point.yBitBlt180,10,160,160,&Dc,0,0,SRCCOPY; ifpoint.x=10&point.x=50&point.y
23、BitBlt180,10,160,160,&Dc,0,0,SRCCOPY; / secondstart 为 1 时计时有效 secondstart=1; /鼠标坐标转换为数组坐标 int a=point.x-10/15; int b=point.y-50/15; ifleiab.weitu=0|leiab.weitu=3 ifleiab.shumu=-1 jieshu=1; /终止时,释放 Timer KillTimer1; /重画,由于这次重画将显示全部的雷,/不能用部分重画 Invalidate; else leiab.weitu=1; CRect rect; rect.left=a*15
24、+10; rect.right=a*15+25; rect.top=b*15+50; rect.bottom=b*15+65; InvalidateRect▭ CView:OnLButtonDownnFlags, point; 假如你现在运行的话,你会发觉按下按钮时并不仍原,这就涉及到鼠标函数:OnLButtonUpUINT nFlags, CPoint point 松开鼠标左键:名师归纳总结 - - - - - - -第 10 页,共 15 页精选学习资料 - - - - - - - - - 松开左键时,显示按钮没有按下的位图;再判定,假如终止,就要显示失败的位图;另外,假如是在按
25、钮上松开按钮,即表示我们已经按下了重新开头的按钮,必需调用重新开头函数 OnStart;由于 OnStart 函数是与菜单里的开头共有的,去掉最终两行;此处先保留不说, 如有必要运行, 可以先void CMy2_1View:OnLButtonUpUINT nFlags, CPoint point / TODO: Add your message handler code here and/or call default CDC *pDC=GetDC; CDC Dc; ifDc.CreateCompatibleDCpDC=FALSE AfxMessageBoxCant create DC; /显
26、示按钮Dc.SelectObjectm_anniu0; pDC-BitBlt180,10,160,160,&Dc,0,0,SRCCOPY; ifjieshu=1 /显示按扭位图 Dc.SelectObjectm_anniu2; pDC-BitBlt180,10,160,160,&Dc,0,0,SRCCOPY; /假如按下的是按扭,重新开头ifpoint.x180&point.x10&point.y=10&point.x=50&point.y=290 int a=point.x-10/15; int b=point.y-50/15; ifleiab.weitu=0|leiab.weitu=3 l
27、eiab.weitu=2; leftnum-; 名师归纳总结 ifleiab.weitu=2 第 11 页,共 15 页else - - - - - - -精选学习资料 - - - - - - - - - leiab.weitu=3; leftnum+; /重画剩下雷数CRect rect2; rect2.left=20; rect2.right=70; rect2.top=10; rect2.bottom=40; InvalidateRect&rect2; /重画打击格子 CRect rect; rect.left=a*15+10; rect.right=a*15+25; rect.top=
28、b*15+50; rect.bottom=b*15+65; InvalidateRect▭ CView:OnRButtonDownnFlags, point; 显示没有雷的区域:运行, 玩一下, 你会发觉当按下的是一个四周没有雷的格子是它并不会象 Window 里面的扫雷嬉戏一样显示它四周的格子雷数;怎么实现呢?添加一个如下函数:/扫描,假如是已经被按下且雷数为 0,显示它四周的八个格,并重画void CMy2_1View:leizero forint i=0;im_RowCount;i+ forint j=0;jm_ColCount;j+ ifleiij.shumu=0&leiij
29、.weitu=1 forint n=i-1;ni+2;n+ forint m=j-1;m=0&n=0&m0 secondstart+; /二十次为一秒ifsecondstart=20 secondstart=1; second+; /重画时间 CRect rect3; rect3.left=325; rect3.right=375; rect3.top=10; rect3.bottom=40; InvalidateRect&rect3; CView:OnTimernIDEvent; 扫雷嬉戏就这样就是了;修改菜单:下面是附加内容, 它将说明菜单的添加和重新开头函数的算法;5 5 附加内容嬉戏已
30、经可以玩了,只是点到雷之后就完了,无法重新开头;仍有,菜单仍没有改;下 面就修改菜单并实现重新开头功能:名师归纳总结 把菜单改为如下图2-3;第 13 页,共 15 页- - - - - - -精选学习资料 - - - - - - - - - 图 2-3 并在 View 函数中按下图添加开头函数:OnStart函数(图 2-4):图 2-4 OnStart函数其实只是构造函数的再版;void CMy2_1View:OnStart SetTimer1,50,NULL; / TODO: Add your command handler code here second=0;/计时 secondst
31、art=0;/1 时开头计时/ num=0; leftnum=leinum;/ 剩余雷数jieshu=0;/jieshu=1 时停止 int aa=0; /初始化 0 forint i=0;im_RowCount;i+ 名师归纳总结 - - - - - - -第 14 页,共 15 页精选学习资料 - - - - - - - - - forint j=0;jm_ColCount;j+ leiij.shumu=0; leiij.weitu=0; /设置 leinum 个雷do int k=rand%m_RowCount; int l=rand%m_ColCount; ifleikl.shumu.
32、=-1 leikl.shumu=-1; aa+; whileaa.=leinum; /给方格赋值forint a=0;am_RowCount;a+ forint b=0;bm_ColCount;b+ ifleiab.shumu=0 forint c=a-1;ca+2;c+ forint d=b-1;d=0&c=0&dm_ColCount ifleicd.shumu=-1 leiab.shumu+; Invalidate; 这样,整个程序完成了;6 6 小结当然,这个嬉戏比 Window 自带的简洁; 但就目前来说, 离它其实也不远; 添加菜单项,并相应修改参数值:m_RowCount 、 m_ColCount 、leinum ,并重新初始化界面就行了;本书的例子都只是一些最基本的嬉戏算法,它教你怎样去实现嬉戏,而至于嬉戏的扩展,我只是提一些建议,让你自己去实现;名师归纳总结 - - - - - - -第 15 页,共 15 页