资源描述
C语言程序设计课程设计扫雷
23
2020年4月19日
文档仅供参考,不当之处,请联系改正。
辽 宁 工 业 大 学
《C++语言程序设计》课程设计(论文)
题目: 扫雷
课程设计(论文)任务及评语
院(系):软件学院 教研室:软件教研室
学 号
学生姓名
专业班级
软件工程166班
课程设计(论文)题目
扫雷
课程设计(论文)任务
程序设计的任务与要求:
(1). 掌握面向对象程序设计语言C++的基本语法
(2). 掌握C++面向对象设计的思想
(3). 掌握VC++6.0与DEV C++ 开发工具的使用
(4). 运用标准C++规范设计应用程序
设计过程中,要严格遵守设计的时间安排,听从指导教师的指导。正确地完成上述内容,规范完整地撰写出设计报告。
指导教师评语及成绩
成绩: 指导教师签字:
年 月 日
目 录
第1章 课程设计目的与要求 1
1.1 设计目的 1
1.2实验环境 1
1.3预备知识 1
1.4设计要求 1
第2章 课程设计内容 2
2.1 课题描述 2
2.2 系统设计 2
2.2.1功能分析 2
2.2.2面向对象设计 3
2.2.2类成员描述 5
2.3程序实现 9
2.3.1源码分析 9
2.3.2运行结果 13
第3章 课程设计总结 14
参考文献 15
第1章 课程设计目的与要求
1.1 设计目的
将理论教学中涉及到的知识点贯穿起来,对不同的数据类型、程序控制结构、数据结构作一比较和总结,结合设计题目进行综合性应用,对所学知识达到融会贯通的程度。
经过课程设计,学生在下述各方面的能力应该得到锻炼:
(1)进一步巩固、加深学生所学专业课程《C++语言教程》的基本理论知识,理论联系实际,进一步培养学生综合分析问题,解决问题的能力。
(2)全面考核学生所掌握的基本理论知识及其实际业务能力,从而达到提高学生素质的最终目的。
(3)利用所学知识,开发小型应用系统,掌握运用C++语言编写调试应用系统程序,训练独立开发应用系统,进行数据处理的综合能力。
(4)对于给定的设计题目,如何进行分析,理清思路,并给出相应的数学模型。
(5)掌握面向对象程序设计的方法。
(6)熟练掌握C++语言的基本语法,灵活运用各种数据类型。
(7)进一步掌握在集成环境下如何调试程序和修改程序。
1.2实验环境
硬件要求能运行Windows 操作系统的微机系统。C++语言应用程序开发软件使用:VC++ 系统,或其它C++语言应用程序开发软件。
1.3预备知识
熟悉C++语言程序设计的基本知识及VC++编辑器的使用方法。
1.4设计要求
1.仔细分析设计题目,画出程序流程图,编写程序源代码。
2.积极上机调试源程序,增强编程技巧与调程能力。
3.认真书写课程设计预习报告,课程设计说明书。
4.遵守课程设计要求和机房管理制度,服从指导教师的安排,确保课程设计的顺利完成课程设计内容。
第2章 课程设计内容
2.1 课题描述
扫雷最原始的版本能够追溯到1973年一款名为“方块”的游戏。不久之后,“方块”被改写成了游戏Rlogic。在Rlogic里,玩家的任务是作为美国海军陆战队队员,为指挥中心探出一条没有地雷的安全路线,如果路全被地雷堵死就算输。两年后,汤姆·安德森在Rlogic的基础上又编写出了游戏地雷,由此奠定了现代扫雷游戏的雏形。1981年,微软公司的罗伯特和卡特两位工程师在Windows 3.1系统上加载了该游戏,扫雷游戏才正式在全世界推广开来。
本课程设计实现类似于Windows操作系统自带的扫雷游戏。在课程设计中,系统开发平台为Windows XP,程序设计语言采用Visual C++,程序运行平台为Windows /XP。在程序设计中,把整个雷区看成一个二维数组,把雷方块定义为具有所在雷区二维数组的行和列、当前状态、方块属性、历史状态的结构体。整个游戏程序包括了布雷、扫雷过程和结果三个阶段,在处理鼠标响应事件中伴随着GDI绘图。程序经过调试运行,实现了设计目标,能够同时满足扫雷游戏初学者和高手的需要。
2.2 系统设计
2.2.1功能分析
本章的课程设计使用C++语言编写一个与其类似的扫雷游戏。具体要求如下:
(1)选择级别后将出现相应级别的扫雷区域,这是用户使用鼠标左键单击雷区中任何一个方块便启动计时器。
(2)用户要揭开某个方块,可单击它。若所揭方块下有雷,用户便输了这一局,若所揭方块下无雷,则显示一个数字,该数字代表方块的周围的8个方块中共有多少颗雷。
(3)如果用户认为某个方块下埋着雷,单击右键能够在方块上标识一个用户认为是雷的图标,即给出一个扫雷标记。用户每标记出一个扫雷标记(无论用户的标记是否正确),程序将显示的剩余雷数减少一个。
(4)扫雷胜利后,显示游戏胜利,失败后显示再来一局。
(5)用户能够改变游戏界面的颜色外观。
(6)游戏中用户能够经过菜单重新开始新游戏。
2.2.2面向对象设计
1. 类的设计
本程序设计了CMineWnd类、CDlgCustom类、bomb类、cview类、CDlgHero类、CDlgNewRecord类等。
CMineWnd类作用:用于扫雷开始运行等操作。
cbombview类作用:扫雷工作补充。
bomb类作用:封装每颗雷的相关属性。
cview类作用:完成扫雷的大部分工作。
CDlgHero类作用:等级英雄榜。
CDlgNewRecord类作用:重新开始新的游戏。
基类为CMineWnd类、bomb类、cview类。
派生类CDlgHero类由CDialog应用程序类继承,cbombview类由cview类继承。
(1)定义类bomb,封装每颗雷的相关属性。
class bomb
{
public:
int isbomb;//决定初始时是否是雷
bool issel; //判断区域是否被处理过且周围有雷
bool isdone;//判断递归时是否被处理过
int num; //周围雷数
bool findbomb; //排雷者认为是雷时置一(可是不一定真是雷)
} ;
(2) 重载cmainframe中precreatewindow,并设置相应属性,使其窗体大小固定,这样就固定了显示区域的大小为初始10乘10个雷和外加雷区上部的控制区域,部分代码如下
cs.style=ws_overlapped|ws_sysmenu| ws_border|ws_minimizebox;
cs.cy = 10*15+6;
cs.cx = 10*15+60; //6和60分别是横纵的附加值,用于边框、菜单、标题条、控制区域。
(3) 重载cbombview中oncreate函数创立位图按钮,该位图按钮的两幅位图对应了正常、雷正确两种状态,当要显示被炸死的状态时应动态销毁该按钮,并重新创立一位图对应正常和被炸死两种状态,将该位图按钮的id号定为id_game_begin,这样一来当点击按钮时便可重新开始游戏,部分代码如下。
crect rcclient;
getclientrect(&rcclient);
crect rect(rcclient.cx/2-8,10,rcclient.cx/2+8,20);
m_button.create("new",bs_defpushbutton|ws_visible|
bs_ownerdraw,rect,this,id_game_begin);
m_button.loadbitmaps(idb_face1, idb_face2);
2.UML类图
CMineWnd
-CMineApp: int
-CMineWnd: int
-ExitInstance: int
-InitInstance: BOOL
+CMineWnd():virtual
+ResetRecord():void
+SetCustom():void
+LookUp(CData & data): int
+InitGame():void
+LoadBitmap():void
+FreeMines():void
+LayMines(UINT row, UINT col):void
bomb
CDlgHero
-isbomb:int
-issel:bool
-isdone:bool
-findbomb:bool
-num:intint
+DrawShell(CPaintDC &dc):void
+DrawButton(CPaintDC &dc):void
+SetBHolder(CString holder)
+SetBRecord(UINT record):void
+SetIHolder(CString holder)
图2.1 扫雷游戏程序的UML类图
3.系统总体流程图
结束
开始
开始
依照使用者初始设定
等待按键
左键键
右键
第一次按下方块
显示方块
1. 布置地雷
2. 启动计时器
按下方块是否为地雷
显示分数
是否再玩玩
结束
延按下方块周围展开非地雷方块
计时器
时间到
否
否
是
是
否
否
是
是
否
图2.2系统总体流程图
2.2.2类成员描述
1.程序编程中用到的类函数简单介绍:
CchildView:其中定义了
Drawboard——对扫雷棋盘进行了绘制
Drawbutton——将资源类中存有的脸的图片进行裁减选择加入到规定位置。
Drawcell——绘制雷区(即在资源类的cell的15个图片中根据需要选择标志,雷图标,以及数字标实经过裁减放到规定的坐标处)
DrawLCD——绘制记时器,调用资源类中的num数字图片用于记时
Expand——当鼠标点击处周围无雷时扩大范围
Gameover——游戏结束时的定义
Inbound——对游戏鼠标点击区域的限制
OnCreate——建立游戏
OnGameCustomize——游戏自定义设置
OnGameNew——游戏级别的初始化
OnGameRecord——扫雷英雄榜的判断记录
OnLButtonDown——左键按下时触发的动作和计算机所做的判断
OnLButtonUp——左键弹起时触发的动作和计算机所做的判断
OnRButtonDown——右键按下时触发的动作和计算机所做的判断
OnRButtonUp——右键弹起时触发的动作和计算机所做的判断
OnTimer——记时器设置
OnUpdateGameLevel——修改游戏等级
OnUpdateGameMark——修改游戏标志
wm_lbuttomdown消息响应函数onlbuttomdown是处理用户输入的主要执行者,函数首先判断点中位置是否是雷,是则关闭定时器,销毁原位图按钮,创立一对应正常和被炸死两种状态的新位图按钮,并调用setstate将其设置为pushdown(小人哭的状态),将m_bgameover,置为true标志游戏结束,否则先调用setstate 设置位图按钮为pushdown (小人笑的状态),并在onlbuttomup中设置位图按钮为正常状态,然后调用caculate函数记下周围雷的数目,最后调用invalidate使客户区无效,迫使ondraw函数重绘客户区域,在调用invalidate时不应重画背景,避免闪烁,这样就完成了在雷区按下左键的响应动作。
wm_rbuttomdown消息响应函数onlbuttomdown将被认为有雷位置的m_ibombnum.findbomb置一,减少左上角的雷记数,然后判断是否真正全部排完了雷,是则结束游戏弹出input对话框,让扫雷的人输入姓名,在响应idok通知码时将其写入注册表,没有全部排完则使客户区无效,迫使ondraw函数重绘客户区域完成在雷区按下右键的动作。
ondraw函数在每次点击左键或右键时都会被调用重雷区和控制区域,因为点击情况的复杂性和雷属性的多元化导致ondraw函数需要精心设计。
函数caculate计算某个雷周围的雷数,根据前面的分析知道,计算某个雷周围的雷数本身就是一个递归过程,在编制时应注意递归的边界条件,稍不注意会陷入无穷递归而耗尽了系统的资源。
2. 系统结构图如图2.3所示。
类模块
扫雷游戏
扫雷
窗
体
类模块
背景音乐
英雄榜
级别选择
鼠标
开始
窗体加载
鼠标函数
递归函数
重开函数
画图函数
音乐函数
图2.3 系统结构图
3. 雷区设计函数流程图如图2.4所示。
图2.4 雷区设计函数流程图
4.布雷函数流程图
随即获取一个状态为非雷的点,将它的属性标志为雷,重复这样的工作,直到布下足够的雷为止,其函数流程图如图2.5所示。
生成随机的雷方块的坐标(x,y)
开始
开始
生成随机的雷方块的坐标(x,y)
判断(x,y)区域是否已经布下雷
在(x,y)区域布雷,修改状态数据据。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
判断是否布下所有雷
结束
否
是
是
否
图2.5 布雷函数流程图
在CMineWnd类中添加游戏的布雷模块的处理函数,该函数的实现如下。
void CMineWnd::LayMines(UINT row, UINT col)
{
//埋下随机种子
srand( (unsigned)time( NULL ) );
UINT i, j;
for(UINT index = 0; index < m_uMineNum;)
{
//取随即数
i = rand() % m_uYNum;
j = rand() % m_uXNum;
if (i == row && j == col) continue;
if(m_pMines[i][j].uAttrib != ATTRIB_MINE)
{
m_pMines[i][j].uAttrib = ATTRIB_MINE;//修改属性为雷
index++;
}
}
}
2.3程序实现
2.3.1源码分析
程序源码分析:
1.//程序名:扫雷游戏;程序作者:孙庆贺; 程序版本:1.0;完成时间: .12;
//头文件Mine.h:定义类Mine的接口,完成初始化:
#if !defined
#define #if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h"
#include "MineWnd.h"
class CMineApp : public CWinApp
{public:
CMineApp();CMineWnd *m_pMineWnd;
//{{AFX_VIRTUAL(CMineApp)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
DECLARE_MESSAGE_MAP()
private:
UINT m_uXMineNum;
UINT m_uYMineNum;
};#endif
2.//源文件Mine.cpp,类Mine.cpp的实现文件:
#include "stdafx.h"
#include "Mine.h"
#include "MineDefs.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CMineApp, CWinApp)
END_MESSAGE_MAP()
CMineApp::CMineApp(){}CMineApp theApp;
const CString className = _T("MineClass");
BOOL CMineApp::InitInstance(){
SetRegistryKey("CSER_513_2");
m_uXMineNum=GetProfileInt(GAME_SETTING,
CUSTOM_XNUM, PRIMARY_XNUM);
m_uYMineNum=GetProfileInt(GAME_SETTING,
CUSTOM_YNUM, PRIMARY_YNUM);
//定义并注册MineWnd窗口
m_pMineWnd = new CMineWnd();WNDCLASS wc;
ZeroMemory(&wc, sizeof(wc));
wc.hInstance = AfxGetInstanceHandle();
wc.lpfnWndProc = ::DefWindowProc;
wc.hbrBackground = NULL;
wc.hCursor = LoadCursor(IDC_ARROW);
wc.hIcon = LoadIcon(IDR_MAINFRAME);
wc.lpszClassName = className;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
//注册窗口
if (!AfxRegisterClass(&wc)) {
AfxMessageBox("注册类失败!");
return FALSE;}
UINT uWidth = DEFAULT_FRAME_X + m_uXMineNum * MINE_WIDTH +
LINE_WIDTH_0 * 3 + SIDE_WIDTH_0 + SIDE_WIDTH_1;
UINT uHeight = DEFAULT_FRAME_Y + m_uYMineNum * MINE_HEIGHT +
LINE_WIDTH_0 * 3 + SIDE_WIDTH_0 * 2 + SIDE_WIDTH_1 + SHELL_S_H;
UINT uXPos = GetSystemMetrics(SM_CXSCREEN) / 2 - uWidth / 2;
UINT uYPos = GetSystemMetrics(SM_CYSCREEN) / 2 - uHeight / 2;
//创立窗口
if ( !m_pMineWnd->CreateEx( NULL, className, _T("扫雷"),
WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
uXPos, uYPos, uWidth, uHeight,
NULL, NULL) ) {
AfxMessageBox("创立主窗口失败!");
return FALSE;}
// 绑定该窗口为主窗口
m_pMainWnd = m_pMineWnd;
//显示窗口
m_pMineWnd->ShowWindow(SW_NORMAL);return TRUE;}
int CMineApp::ExitInstance() {delete m_pMineWnd;
return CWinApp::ExitInstance();}}
3.//鼠标左键点击事件的关键代码如下所示。
void CMineWnd::OnLButtonUp(UINT nFlags, CPoint point) {
//笑脸图按钮所在的区域
CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39);
//雷区所在的区域
CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP,
MINE_AREA_LEFT + m_uXNum * MINE_WIDTH,
MINE_AREA_TOP + m_uYNum * MINE_HEIGHT);
if (rcBtn.PtInRect(point))
{// 点击笑脸图
Invalidate();InitGame();}
else if (rcMineArea.PtInRect(point)) {
//点击雷区域
CString value;UINT around = 0;
//根据不同的游戏状态作处理
switch(m_uGameState) {
//游戏进行状态
m_pOldMine = GetMine(point.x, point.y);
if (!m_pOldMine) {
ReleaseCapture();
return;}
//检测判断当前状态是否为左右鼠标同时按下
if (m_bLRBtnDown) {
m_bLRBtnDown = FALSE;
OnLRBtnUp(m_pOldMine->uRow, m_pOldMine->uCol);
if (m_uGameState == GS_WAIT){
m_uBtnState = BUTTON_NORMAL;
Invalidate();
ReleaseCapture();
return;}
//假若周围已经标识的雷=周围真正的雷数,拓展
if (m_pOldMine->uState != STATE_FLAG){
OpenAround(m_pOldMine->uRow, m_pOldMine->uCol);
if (ErrorAroundFlag(m_pOldMine->uRow, m_pOldMine->uCol)) {
Dead(m_pOldMine->uRow, m_pOldMine->uCol);
ReleaseCapture()
return;}}
else
//启动定时器
m_uTimer = SetTimer(ID_TIMER_EVENT, 1000, NULL);
//布雷
LayMines(m_pOldMine->uRow, m_pOldMine->uCol);
// lay all the mines down
//改变游戏状态为"运行/GS_RUN"
m_uGameState = GS_RUN;}
if (m_pOldMine->uOldState == STATE_NORMAL){
//当该雷区域为正常未作标记才打开
//如果该区域为雷,则死亡
if (IsMine(m_pOldMine->uRow, m_pOldMine->uCol)) {
Dead(m_pOldMine->uRow, m_pOldMine->uCol);
ReleaseCapture();
return;}
// the special MINEWND is not a mine
//不是雷的时候,获取其周围的雷数目
around = GetAroundNum(m_pOldMine->uRow, m_pOldMine->uCol);
//标志为“?”问号的时候
m_pOldMine->uState = STATE_DICEY;}
//图形结束
void CSnakeView::close()
2.3.2运行结果
程序运行结果图2.6、图2.7。
①游戏初始界面:如下图
图2.6游戏初级初始界面
②游戏过程界面:如下图
图2.7游戏中级开始后界面
第3章 课程设计总结
本次C++课程设计我的题目是扫雷,题目不算难,但我做的很艰苦。主要就是动手能力太差,理论知识掌握的不全面,自以为会不少,但真做起来,却不知道从哪下手了。又回去温习理论知识,请教老师,上网查资料,忙的不亦乐乎。不过经过努力总算是做出来了,还经过此次课程设计,将我本学期所学的C++知识得到巩固和应用。在设计的过程中我遇到的很多问题,在老师的帮助和自己的思考下还是很好的完成了。这此课程设计我懂得了写程序不能脱离实际,只凭主观办事,要努力拓宽知识面,拓展思维。
事情就是如此,努力代表收获。经过这次课程设计,我才真正领悟到“艰苦奋斗”这一词的真正含义,我才感受到早期电子设计者为现代的社会付出。设计确实有些辛苦,但苦中也有乐,在如今单一的理论学习中,很少有机会能有实践的机会,但现在能够,这些天的设计中得到的东西却不比理论课上得到的少多少,我感觉我和C++的距离更加近了;我想说,确实很累,但当我看到自己所做的成果时,心中也不免产生兴奋; 学习有成果了么。
对C++编程有了一个基本的了解。这些天温习的内容越多,敲得代码越多,自己的学习积极性也越在提高,感觉也越充实。越来越发现现在学习的只是C++的基础,但涉及的面还是很广泛的,这些都为以后进一步学习C++的高级特性打下了扎实的基础。随着课程难度的慢慢加强,今后遇到的困难也必将会越来越多,但我相信自己一定能做好这些的。
在本次C++课程设计中,我要非常感谢我的指导老师翟老师,不但在课堂上教给了我很多的C++的编程知识,编程思想,而且在这次课程设计中更教会了我动手的能力,真正的编出了自己的东西,还要感谢我的同学,她们在我遇到困难时也给了我很多帮助。
参考文献
1.郑飞倩 编著 《C++面向对象程序设计》 上海:电子工业出版社
2.吴华恩 主编 《C++程序设计》 北京:机械工业出版社
3.洪永清 主编 《面向对象的系统分析》 天津:天津大学出版社
4.谭浩强 主编 《面向对象建模》 武汉:科技大学出版社
5.邵伟忠 主编 《常见算法程序集》 天津:人民大学出版社
6.徐世亮 编著 《C++大学教程》 北京:人民邮电出版社
7.徐孝凯 编著 《C++语言程序设计》 北京:清华大学出版社
8.吴访升 编著 《C++程序设计》 北京: 机械工业出版社
9.Decoder 主编 《C/C++程序设计》 北京:中国铁道出版社
10.徐静芬 主编 《C++语言程序设计》 辽宁:广播大学出版社
展开阅读全文