WIN32模拟WINDOWS XP扫雷程序课程设计目的与要求:本课程设计是计算机科学与技术专业重要的实践性环节之一,是对本程学习后进行的一次全面而综合的练习。
本次课程设计的目的与任务主要有:1.巩固和加深学生对C和C++语言的基本知识的理解与掌握。
2.掌握C和C++语言编程和调试的基本技能3.运用C和C++语言对程序的简单设计4.掌握程序设计说明文档的能力与技巧5.提高与运用C和C++语言解决能实际问题的能力一、题目描述:自行分析Windows XP系统自带扫雷游戏,查找规则并对主要功能进行模仿程序实现,对于实现过程中出现的bug进行调试解决。
二、使用语言:C和C++ 语言选用C++语言的原因,简而言之主要是因为C++的设计目标,就是要让C++既具有适合于系统程序设计的C语言所具有的可适应性和高效性,又能在其程序组织结构方面具有像其他的语言所支持的程序优势。
这即是说,C++所提供的抽象机制能够被应用于那些对效率和可适应性具有极高要求的程序设计任务之中。
三、编译以及运行环境:编译环境:Microsoft Visual C++ 6.0运行环境:Windows XP或其他兼容兼容系统四、题目分析:经过对游戏的初步分析,扫雷游戏含有如下规则:根据输入的信息,执行相应的挖雷,插旗,疑问标记,自动蔓延开挖等。
挖雷过程由计时器计时,由一个计数器统计插旗后雷的剩余个数。
如果选择了标记功能,那么单机右键会依次对未知点进行插旗,标记,取消插旗与标记。
如果点滴到插旗的如果点击到了未插旗子的雷区,如果是雷,则判定游戏失败,之后对雷区的点击进行屏蔽,不予响应。
如果是疑问标记则像正常区域对待。
如何判断胜利,如果所有的雷都被插旗或者点击后剩余的雷区,五、程序运行流程简介以及流程图:点击程序按默认参数进行初始化,输入,表情对鼠标左右键点击进行变化响应,对于雷区内点击进行规律响应,对雷区点击后果进行统计,判断失败与成功,失败或者成功之后,对于雷区内的输入也就是点击进行屏蔽,对菜单游戏级别、重新开始游戏按钮响应。
级别选择,重新游戏时时间归零、雷数显示刷新。
如此重复规则,直到点击退出。
程序简要流程图:六、函数实现:类:CMyWnd:(以公共方式继承自CFrameWnd类)主函数体,包含逻辑过程以及主要函数CMyHero:(以公共方式继承自CDialog类)吸取游戏数据比较后进行排名显示CMyRecrod:(以公共方式继承自CDialog类)询问是否对数据进行保存CSetYouself:(以公共方式继承自CDialog类)对游戏参数自己进行设置七、主要函数:以公共方式继承自CFrameWnd类的类CMyWnd:class CMyWnd : public CFrameWnd{Provide:int x;//记录左键落下与起来坐标是否一致int y;//记录左键落下与起来坐标是否一致int z;//记录前一个状态int Ch;//笑脸的状态int Color;//笑脸颜色int Tm;//时间int h;//时int m;//分int s;//秒int minenumber;//雷的个数int minenum;//当前雷的个数int minefir;//第一位int minesec;//第二位int minethi;//第三位int high;//雷区的宽度int wide;//雷区的高度int Fail;//是否失败,1为失败BOOL LeftButtondown;//1为按下去BOOL RightButtondown;//1为按下去public:CMyWnd();afx_msg void OnLButtonDown(UINT nFlags,CPoint point);//左右键起来落下afx_msg void OnLButtonUp(UINT nFlags,CPoint point);afx_msg void OnRButtonDown(UINT nFlags,CPoint point);afx_msg void OnRButtonUp(UINT nFlags,CPoint point);afx_msg void OnMouseMove(UINT nFlags, CPoint point);//移动鼠标afx_msg void OnTimer(UINT nIDEvent);//计时afx_msg void OnPaint();afx_msg void OnStart();afx_msg void OnJunior();afx_msg void OnMiddle();afx_msg void OnHigher();afx_msg void OnSetYouself(int,int,int);afx_msg void OnSign();afx_msg void OnColor();afx_msg void OnSound();afx_msg void OnHero();afx_msg void OnExit();afx_msg void OnContent();afx_msg void OnTheme();afx_msg void OnHelp();afx_msg void OnAbout();void DrawMineMap(CPaintDC &dc);//布雷void DrawMineChild(CPaintDC &dc);//画小人void DrawMineFrame(CPaintDC &dc);//画边框void DrawTime(CPaintDC& dc);//画时间void ReStart(void);void TaxCount(void);//游戏默认值int Spread(int x,int y);int MakeRand();int FindEveryone();//找出每一个位置前一个状态int Success();//判断是否胜利,胜利返回1,BOOL Start;struct MINE;virtual ~CMyWnd();DECLARE_MESSAGE_MAP()};主要函数说明://扩展函数,如果是安全区,并且不是提示区,则向四周八个方向检查扩散int CMyWnd::Spread(int i,int j)//是安全区域则向四周扩散,改变当前值{int x=0;int y=0;for(x = i - 1 ; x <= i+1 ; x ++ )for(y = j - 1 ; y <=j+1 ; y ++ )//周围八个方向挨个检查{if(x>=0&&y>=0&&x<high&&y<wide&&(x!=i||y!=j)){if(g_MineFlags[x][y].oldsta==15&&g_MineFlags[x][y].newsta==0){g_MineFlags[x][y].newsta=g_MineFlags[x][y].oldsta;Spread(x,y);}else if(g_MineFlags[x][y].newsta!=1)g_MineFlags[x][y].newsta=g_MineFlags[x][y].oldsta;}}return 0;}//对鼠标左键点下的响应void CMyWnd::OnLButtonDown(UINT nFlags,CPoint point)//1.鼠标左键{CRect rcBtn(16*high/2-3,15,16*high/2+23, 41);if(rcBtn.PtInRect(point)){Ch=0;}if(point.x>=12&&point.x<=16*high+12&&point.y>=57&&point.y<=16*wide+57){int suc=Success();if(!suc&&!Fail){LeftButtondown=true;point.x-=12;point.y-=57;x=point.x/16;y=point.y/16;//记住左键先前状态,以便当点击位置不一进行还原z=g_MineFlags[point.x/16][point.y/16].newsta;//如果已经插旗则不必对左键落下进行反应if(g_MineFlags[point.x/16][point.y/16].newsta!=1&&g_MineFlags[point.x/16][poi nt.y/16].newsta!=2){//如果区域还未点开则对左键落下进行反应if(g_MineFlags[point.x/16][point.y/16].newsta==0){g_MineFlags[point.x/16][point.y/16].newsta=15;}Ch=3;}}}::InvalidateRect(this->m_hWnd,NULL,false);}//对鼠标左键点下的响应void CMyWnd::OnLButtonUp(UINT nFlags,CPoint point){CRect rcBtn(16*high/2-3,15,16*high/2+23, 41);if(rcBtn.PtInRect(point)){Ch=4;::InvalidateRect(this->m_hWnd,NULL,false);Tm=0;ReStart();}if(point.x>=12&&point.x<=16*high+12&&point.y>=57&&point.y<=16*wide+57) {if(LeftButtondown){LeftButtondown=false;Ch=4;if(!Start){Start=SetTimer(TIMEREVENT, 1000, NULL);}point.x-=12;point.y-=57;if(x!=point.x/16||y!=point.y/16){g_MineFlags[x][y].newsta=z;}if(g_MineFlags[point.x/16][point.y/16].newsta!=1)//如果没有被标记则处理{if(g_MineFlags[point.x/16][point.y/16].oldsta==5){for(int i=0;i<high;i++)for(int j=0;j<wide;j++){if(g_MineFlags[i][j].oldsta==5&&g_MineFlags[i][j].newsta!=1)g_MineFlags[i][j].newsta=5;if(g_MineFlags[i][j].oldsta!=5&&g_MineFlags[i][j].newsta==1)g_MineFlags[i][j].newsta=4;if(i==point.x/16&&j==point.y/16)g_MineFlags[i][j].newsta=3;}Fail=1;Ch=2;}else if(g_MineFlags[point.x/16][point.y/16].oldsta==15)//安全区,向四周扩散{g_MineFlags[point.x/16][point.y/16].newsta=g_MineFlags[point.x/16][point.y/16].oldsta;Spread(point.x/16,point.y/16);Ch=4;}else // 提示区,点开后直接显示{g_MineFlags[point.x/16][point.y/16].newsta=g_MineFlags[point.x/16][point.y/16].oldsta;Ch=4;}}}}int suc=Success();if(suc||Fail){if(Start==1)KillTimer(TIMEREVENT);Start=0;if(Fail)Ch=2;//失败表情else{minenum=0;Ch=1;//胜利表情if(Tm<10){CMyRecrod dlg;dlg.DoModal();}}}::InvalidateRect(this->m_hWnd,NULL,false);}//对鼠标右键点下的响应void CMyWnd::OnRButtonDown(UINT nFlags,CPoint point) //2.鼠标左键按下状态移动坐标{RightButtondown=true;if(!LeftButtondown){int suc=Success();if(!suc&&!Fail)//!Fail)//不是白且不成功才能继续{int n=0;if(point.x>=12&&point.x<=16*high+12&&point.y>=57&&point.y<=16*wide+57){point.x-=12;point.y-=57;if(g_MineFlags[point.x/16][point.y/16].newsta==0){g_MineFlags[point.x/16][point.y/16].newsta=1; //插旗}else if(g_MineFlags[point.x/16][point.y/16].newsta==1){g_MineFlags[point.x/16][point.y/16].newsta=2; //疑问}else if(g_MineFlags[point.x/16][point.y/16].newsta==2){g_MineFlags[point.x/16][point.y/16].newsta=0; //还原}else{//AfxMessageBox("你单击了右键并计算出错");}}if(g_MineFlags[point.x/16][point.y/16].newsta==1)minenum--;if(g_MineFlags[point.x/16][point.y/16].newsta==2)minenum++;}}else{// AfxMessageBox("两件都按下去了");}int suc=Success();if(suc||Fail){if(Start==1)KillTimer(TIMEREVENT);Start=0;if(Fail)Ch=2;//失败表情else{minenum=0;Ch=1;//胜利表情if(Tm<10){CMyRecrod dlg;dlg.DoModal();}}}::InvalidateRect(this->m_hWnd,NULL,false);}//对鼠标左键起来的响应void CMyWnd::OnLButtonUp(UINT nFlags,CPoint point){CRect rcBtn(16*high/2-3,15,16*high/2+23, 41);if(rcBtn.PtInRect(point)){Ch=4;::InvalidateRect(this->m_hWnd,NULL,false);Tm=0;ReStart();}if(point.x>=12&&point.x<=16*high+12&&point.y>=57&&point.y<=16*wide+57) {if(LeftButtondown){LeftButtondown=false;Ch=4;if(!Start){Start=SetTimer(TIMEREVENT, 1000, NULL);}point.x-=12;point.y-=57;if(x!=point.x/16||y!=point.y/16){g_MineFlags[x][y].newsta=z;}if(g_MineFlags[point.x/16][point.y/16].newsta!=1)//如果没有被标记则处理{if(g_MineFlags[point.x/16][point.y/16].oldsta==5){for(int i=0;i<high;i++)for(int j=0;j<wide;j++){if(g_MineFlags[i][j].oldsta==5&&g_MineFlags[i][j].newsta!=1)g_MineFlags[i][j].newsta=5;if(g_MineFlags[i][j].oldsta!=5&&g_MineFlags[i][j].newsta==1)g_MineFlags[i][j].newsta=4;if(i==point.x/16&&j==point.y/16)g_MineFlags[i][j].newsta=3;}Fail=1;Ch=2;}else if(g_MineFlags[point.x/16][point.y/16].oldsta==15)//安全区,向四周扩散{g_MineFlags[point.x/16][point.y/16].newsta=g_MineFlags[point.x/16][point.y/16].oldsta;Spread(point.x/16,point.y/16);Ch=4;}else // 提示区,点开后直接显示{g_MineFlags[point.x/16][point.y/16].newsta=g_MineFlags[point.x/16][point.y/16].oldsta;Ch=4;}}}}int suc=Success();if(suc||Fail){if(Start==1)KillTimer(TIMEREVENT);Start=0;if(Fail)Ch=2;//失败表情else{minenum=0;Ch=1;//胜利表情if(Tm<10){CMyRecrod dlg;dlg.DoModal();}}}::InvalidateRect(this->m_hWnd,NULL,false);}//对结果进行判定int CMyWnd::Success(){int minenum=0;//雷的个数int signnum=0;//旗子的个数int nonenum=0;//没有被点开的个数int siminum=0;//旗子且是雷的个数//规则://1,未被点开的数目与差棋子的数目等于地雷的数//2,没有被全部点开情况下,旗子的数目等于雷的个数,且每个旗子对应一个雷for(int i=0;i<high;i++)for(int j=0;j<wide;j++){if(g_MineFlags[i][j].newsta==0)minenum++;if(g_MineFlags[i][j].newsta==1&&g_MineFlags[i][j].oldsta==5)siminum++;}int it=minenum+siminum;if(minenumber==minenum+siminum||minenumber==siminum){for(int i=0;i<high;i++)for(int j=0;j<wide;j++){if(g_MineFlags[i][j].oldsta==5)g_MineFlags[i][j].newsta=1;}return 1;}else{return 0;}}//计时函数void CMyWnd::OnTimer(UINT nIDEvent){//HRSRC hSrc;//HMODULE hMdl;// hMdl = AfxGetResourceHandle();//if(nIDEvent==TIMEREVENT){Tm++;// hSrc = FindResource(hMdl, MAKEINTRESOURCE(IDR_WA VE1), _T("WA VE"));}::InvalidateRect(this->m_hWnd,NULL,false);CWnd::OnTimer(nIDEvent);}//对显示变化及时刷新void CMyWnd::DrawTime(CPaintDC& dc){CDC cdM;CBitmap bitmapch;RECT rect;GetClientRect(&rect);//获取指针当前坐标信息if(Color)//Color=1时为彩图{bitmapch.LoadBitmap(MAKEINTRESOURCE(IDB_BITMAPTIME)); //下载位图信息}else{bitmapch.LoadBitmap(MAKEINTRESOURCE(IDB_BITMAPTIME2)); //下载位图信息}cdM.CreateCompatibleDC(&dc);cdM.SelectObject(bitmapch); //选择包//雷的个数与设置以及属性if(minenum<0){minefir=11;minesec=(-minenum)%100/10;minethi=(-minenum)%100%10;}else{minefir=minenum/100;minesec=minenum%100/10;minethi=minenum%100%10;}dc.StretchBlt(17+13*0,15,13,25, &cdM, 0, 23*(11-minefir)-1, 13, 26, SRCCOPY);//雷//正负dc.StretchBlt(17+13*1,15,13,25, &cdM, 0, 23*(11-minesec)-1, 13, 26, SRCCOPY);//雷//十位dc.StretchBlt(17+13*2,15,13,25, &cdM, 0, 23*(11-minethi)-1, 13, 26, SRCCOPY);//雷//个位//时间位置与设置以及属性if(Tm>=999){h=m=s=11;}else{h=Tm/100;m=Tm%100/10;s=Tm%100%10; //根据状态赋值}dc.StretchBlt(high*16+PIXEL+16-10-(13*3),15,13,25, &cdM, 0,23*(11-h)-1, 13, 26,SRCCOPY);//计时器//百位dc.StretchBlt(high*16+PIXEL+16-10-(13*2),15,13,25, &cdM, 0,23*(11-m)-1, 13, 26, SRCCOPY);//计时器//十位dc.StretchBlt(high*16+PIXEL+16-10-(13*1),15,13,25, &cdM, 0,23*(11-s)-1, 13, 26, SRCCOPY);//计时器//个位dc.Draw3dRect(17,15,13*3+1,25,RGB(0,0,0),RGB(255,255,255));dc.Draw3dRect(high*16+PIXEL+16-10-(13*3),15,3*13+1,25,RGB(0,0,0),RGB(255,255, 255));}void CMyWnd::DrawMineMap(CPaintDC& dc){CBitmap bitMap;CDC dcM;RECT Rect={STARTX+10,STARTY+55,high*16,wide*16}; //定义带坐标等信息的巨型LPCRECT LpcRect=&Rect; //定义一个指向矩形的指针if(Color)//Color=1时为彩图{bitMap.LoadBitmap(MAKEINTRESOURCE(IDB_BITMAP)); //下载位图信息}else{bitMap.LoadBitmap(MAKEINTRESOURCE(IDB_BITMAP2)); //下载位图信息}dcM.CreateCompatibleDC(&dc);dcM.SelectObject(&bitMap);for(int i=0;i<high;i++){for(int j=0;j<wide;j++){dc.BitBlt(16*i+12,16*j+57,16,16,&dcM,0,g_MineFlags[i][j].newsta*16,SRCCOPY);}}}void CMyWnd::DrawMineChild(CPaintDC& dc){CDC cdM;CBitmap bitmapch;//CBitmap bitmapch;//CBitmap bitmapch;// RECT rect;// GetClientRect(&rect);//获取指针当前坐标信息if(Color)//Color=1时为彩图{bitmapch.LoadBitmap(MAKEINTRESOURCE(IDB_BITMAPCHILD)); //下载位图信息}else{bitmapch.LoadBitmap(MAKEINTRESOURCE(IDB_BITMAPCHILD2)); //下载位图信息}cdM.CreateCompatibleDC(&dc);cdM.SelectObject(bitmapch); //选择包//笑脸的位置与设置以及属性dc.StretchBlt(16*high/2-2, 16, 24, 24, &cdM, 0, 24 * Ch, 24, 24, SRCCOPY);dc.Draw3dRect(16*high/2-3, 15, 26, 26, RGB(128, 128, 128), RGB(128, 128, 128));}void CMyWnd::DrawMineFrame(CPaintDC& dc){CBrush Brush; //定义画刷RECT Rect = {STARTX,STARTY,high*16+PIXEL+16,wide*16+PIXEL+63}; //定义带坐标等信息的巨型Brush.CreateSolidBrush(RGB(192,192,192)); //给画刷赋值LPCRECT LpcRect=&Rect; //定义一个指向矩形的指针dc.FillRect(LpcRect, &Brush); //调用函数填充颜色// 起点宽高dc.FillSolidRect(STARTX,STARTY,high*16+PIXEL+16,PIXEL,RGB(255,255,255));//左边dc.FillSolidRect(STARTX,STARTY, PIXEL,wide*16+PIXEL+63,RGB(255,255,255));//上//三维大的范围边框Rect.left=10;Rect.top=10;Rect.right=high*16+PIXEL+11;Rect.bottom=45;//坐标信息左上角右下角左上角颜色右下角颜色dc.Draw3dRect(LpcRect,RGB(0,0,0),RGB(255,255,255));Rect.left=10;Rect.top=55;Rect.right=high*16+PIXEL+11;Rect.bottom=wide*16+PIXEL+57;dc.Draw3dRect(LpcRect,RGB(0,0,0),RGB(255,255,255));}void CMyWnd::OnPaint(){CPaintDC dc(this);RECT Rect;CDC DcM;GetClientRect(&Rect);if(DcM.CreateCompatibleDC(&dc))//创建一个与指定设备兼容的内存设备上下文环境(DC){ //则返回内存设备上下文环境的句柄//if (bitmap.CreateCompatibleBitmap(&dc, rect.right, rect.bottom))//该函数创建与指定的//{ //函数原型:HBITMAP CreateCompatibleBitmap(HDC hdc,int nWidth,int nHeight)//设备环境相关的设备兼容的位图。