分类

课内:
不限
类型:
不限 毕业设计 课程设计 小学期 大作业
汇编语言 C语言 C++ JAVA C# JSP PYTHON PHP
数据结构与算法 操作系统 编译原理 数据库 计算机网络 软件工程 VC++程序设计
游戏 PC程序 APP 网站 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
年份:
不限 2018 2019

资源列表

  • 基于C++实现的迷你数据库

    1 引言1.1 目的为了深入学习和了解数据库以及小学期课程需要,我们小组决定自己编写一个简单的mini-database。
    1.2 背景1970年,IBM的研究员,有“关系数据库之父”之称的埃德加•弗兰克•科德(Edgar Frank Codd或E. F. Codd)博士在刊物《Communication of the ACM》上发表了题为“A Relational Model of Data for Large Shared Data banks(大型共享数据库的关系模型)”的论文,文中首次提出了数据库的关系模型的概念,奠定了关系模型的理论基础。20世纪70年代末,关系方法的理论研究和软件系统的研制均取得了很大成果,IBM公司的San Jose实验室在IBM370系列机上研制的关系数据库实验系统System R历时6年获得成功。1981年IBM公司又宣布了具有System R全部特征的新的数据库产品SQL/DS问世。由于关系模型简单明了、具有坚实的数学理论基础,所以一经推出就受到了学术界和产业界的高度重视和广泛响应,并很快成为数据库市场的主流。20世纪80年代以来,计算机厂商推出的数据库管理系统几乎都支持关系模型,数据库领域当前的研究工作大都以关系模型为基础。
    本项目的主要命令都参考mysql完成。MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 最流行的关系型数据库管理系统,在 WEB 应用方面MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,它分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。
    1.3 术语


    序号
    术语/缩略语
    说明




    1
    B+tree
    B+树


    2
    SGA
    System Global Area 系统全局区


    3
    shared pool
    共享池


    4
    data buffer area
    数据缓冲区


    5
    redo log buffer
    日志缓冲区


    6
    library cache
    库缓存区


    7
    data directory cache
    数据字典缓存区


    8
    SMON
    System Monitor


    9
    DBWR
    Data Base Writer


    10
    LGWR
    Log Writer


    11
    CKPT
    Check point



    2 软件基本结构软件由实例和数据库组成:
    数据库由数据文件(包含表头文件、纪录文件、索引等数据)、控制文件(包括每个表的操作信息)、日志文件(数据操作sql语句)、参数文件(分配内存区域并定位控制文件的位置)、口令文件、日志归档文件(归档模式下)(服务器崩溃、硬盘损坏情况下,通过日志恢复时用)
    实例由内存结构(memory strutct) 和后台进程(background processor)组成。
    SGA: System Global Area 系统全局区,主要是给实例使用,包括共享池(shared pool 、数据缓冲区( data buffer area) ,日志缓冲区( redo log buffer)。
    2.1 共享池(shared pool)包括library cache 、data directory cache 组成,其中 library cache 主要保存最近的sql 检查、编译、执行计划, 下次有同样语句过来的时候,可以重用这些,避免重复的检查编译执行计划。 data directory cache 主要保存数据库数据表的字段定义、索引数据等, shared pool 的大小直接影响到数据库的性能。
    data buffer area : 主要保存用户对数据的修改,查询操作。该内存区域的大小直接影响数据库的性能
    redo log buffer area: 主要保存最近用户对数据库的操作记录,该大小对数据库性能没有多大影响

    SMON(System Monitor)监控SGA的健康情况,收集SGA碎片内存,监控实例健康情况
    DBWR(Data Base Writer)维护data buffer area 和物理表数据的一致性
    LGWR(Log Writer)维护redo log buffer area 内存数据和日志文件的一致性
    CKPT(Check point)设置检查点,在oracle 实例出现问题的时候,可以恢复到实例失败前的情况


    3 系统模块划分与设计3.1 词法分析模块主要是处理用户的输入,将用户的输入转换成程序可执行的语句。它拟提供以下功能:程序使用简要说明,对用户输入进行词法分析并提取参数及关键字,对于错误输入报错并提示正确的输入格式,将用户输入的信息备份在日志中。



    Analysis()
    从输入流中取出主要命令,调用各命令对参数的分析




    CommandHelp()
    当输入出现错误时对用户提供帮助


    Use()
    提供USE命令的句法分析


    Back()
    提供BACK命令的句法分析


    CreateDataBase()
    提供CREATE DATABASE命令的句法分析


    CreateTable()
    提供CREATE TABLE命令的句法分析


    Inster()
    提供INSTER命令的句法分析


    Update()
    提供UPDATE命令的句法分析


    Delete()
    提供DELETE命令的句法分析


    Select()
    提供SELECT命令的句法分析


    Add()
    提供ADD命令的句法分析


    Save()
    提供SAVE命令的句法分析



    3.2 核心处理模块:对已从磁盘加载进内存中的数据进行处理,并利用索引实现增删改查等功能,将结果显示在控制台上。



    CoreProcessing()
    创建日志文件并且写入





    Analysis ()
    判断命令内容调用相关处理函数
    string& cmd传入命令指针


    UseDataBase ()
    进入文件夹(使用数据库)
    string,传入数据库名称


    CreateDataBase ()
    创建数据库(即创建文件夹)
    string,传入文件夹名称


    ReadLog ()
    读取日志内容
    string文件夹名称



    3.3 文件处理模块将内存与磁盘数据同步(日志、表单读取、新建库或表单)。



    ChangePath ()
    根据输入参数提取出文件路径





    CreateFolder ()
    创建文件夹(即库)
    string传入文件路径


    DeleteFolde()
    删除文件夹
    string传入文件路径


    Rename()
    更改名称
    string原名称,string现名称


    WriteTxt()
    将记录写入txt文件中
    string表名,vector记录内容


    ReadTxt()
    从txt中读出记录
    string表名,vector记录内容



    3.4 table记录处理相关操作


    Table()
    将记录数和关键词数初始化为0





    CreateTable()
    创建表单时将表头的内容写入
    vector表头内容


    Insert()
    将记录写入表单
    vector,传入记录内容


    Update ()
    更新记录内容
    vector,需要更新条目的条件及新内容


    Delete ()
    删除记录内容
    vector,需要删除条目的条件


    Select()
    输出符合条件的条目
    vector,需要输出条目的条件


    Add()
    添加一个表头
    vector,添加的表头内容及数据类型


    Save()
    将内存数据写入磁盘



    4 接口设计4.1 用户接口用户在控制台输入与SQL命令类似的语句来操作软件,具体的语句格式见需求分析文档。
    本项目中Analysis()是从控制台获取用户输入并且进行分析的主要函数,他从输入中提取到关键命令后将调用函数对参数进行进一步提取。而后CreateDataBase(),CreateTable()等函数将在提取完参数后调用核心处理模块。进而完成用户接口的功能。
    4.2 外部接口本软件主要通过文件处理模块与磁盘就行交互。
    外部接口

    CreateFolder (),DeleteFolde(),Rename()等文件及文件夹的创建删除等功能
    WriteTxt()和ReadTxt()函数主要负责完成内存和磁盘的同步

    4.3 内部接口将上述三个模块封装为三个类,模块之间用类的成员函数进行调用,尽量在设计类时减小它们间的耦合度,实现内部接口功能。
    4.4 数据结构
    表头为结构体数组,结构体包含字段名、数据类型等
    数据记录结构为一系列数组,每一列数据对应一个数组,将角标相同的各数组元素逻辑上视为一条记录中的成员。
    索引结构为B+树,每个节点指向一个记录的角标

    5 算法设计5.1 关键字设计
    CREATE:在文件夹中新建一个表头和一个数据文件,表头内容由词法分析模块提供的参数确认
    INSTER:将插入的数据保存在每一个对应数组的最后一个,也就是指数据的存盘是追加的形式
    UPDATE:循环加判断,找到所有符合条件的值进行替换,先在内存中处理再进行数据的存盘
    DELETE:用循环,找到删除以后直接break,先在内存中处理再进行数据的存盘
    SELECT: 循环

    直接按格式将内容输出在取完整条数据内容后加条件输出在循环时取指定内容进行判断,符合条件的输出先按要求排序(如果数据结构支持则不需要这一步),然后按照INSTER算法进行输出其中的排序和查找由B+树本身的性质就可以高效实现

    5.2 B+树索引算法5.2.1 B+树叶子节点定义struct LeafNode { vector<Key> keys; vector<Value> values; PagePointer next_page; };
    5.2.2 B+树内部节点定义struct InteriorNode { vector<Key> keys; vector<PagePointer> pointers; };
    5.2.3 search操作/** * finds the leaf node that _should_ contain the entry with the specified key */ LeafNode search(Node root, Key key); /** * Inserts a key/val pair into the tree. * Returns the root of the new tree which _may_ be different * from the old root node. */ InteriorNode insert_into_tree(InteriorNode root, Key newk4.ey, Value val);
    5.2.4 insert操作
    寻找insert的正确的目标leaf node
    向目标leaf node中尝试insert操作
    InteriorNode insert_into_tree(InteriorNode root, Key newkey, Value val) { LeafNode leaf = search(root, newkey); return insert_into_node(leaf, newkey, val); }

    其中,insert_into_node中,要做如下的一些事:

    /** * Tries to inserts the (newkey/val) pair into * the node. * * If `target` is an interior node, then `val` must be a page pointer. */ InteriorNode insert_into_node(Node target, newkey, val) { if( ... CASE 1 ... ) { /* handle CASE 1 */ } else if( ... CASE 2 ... ) { /* handle CASE 2 */ } else if( ... CASE 3 ... ) { /* handle CASE 2 */ } }

    其中三个不同的case包括:

    目标leaf node有足够的空间保存key
    目标leaf node已满,但是它的parent node(父节点)有足够的空间保存key
    目标leaf node和它的parent node已满。

    5.2.5 delete操作删除算法是insert算法的逆过程。
    6 技术难点及其解决方案
    词法分析模块对于用户多变的输入,如何正确地判段输入的合法性,再提取出关键字和参数是相当麻烦的,我们暂拟定用正则表达式来实现主体部分
    对记录的数据结构方面,我们开始打算使用变长的结构体,然后发现并不能在程序运行后来确定结构体大小,所以我们就使用一系列数组来实现,只是要将角标相同的元素逻辑上视为一个记录结构体的成员就行
    对于索引方面,首先B+树这种结构该如何存盘就是个非常棘手的问题,如果我们不能找到有效的方法的话,我们将采用二叉查找树来代替B+树

    -文本文件的读写可能会出现意外情况,而这方面我们了解不多
    7 测试程序主界面

    命令提示
    1 评论 52 下载 2018-11-06 10:34:21 下载需要10点积分
  • 基于Android Studio实现的学生蹭课APP

    1 任务概述1.1 项目来源及背景本小组项目是小组成员集体讨论时,提出的一个满足大学生在课余时间的蹭课需求的安卓端app。既可以供大家查阅自己感兴趣课程的相关信息,又可以在公告板跳转到教务处网页及时收到通知,还可以在社区板块查看别人的讨论、留言、以及对相关课程的点评。
    1.2 项目要达到的目标本项目是为了让同学们能够在课余时间更有针对性的去获取自己喜欢的课程的相关信息。为此我们还设计了关联教务系统、社区讨论和个人信息的模块,以使得用户获得更好的蹭课体验。鉴于前期可行性分析中本校学生的蹭课需求较高,该软件的出现必然迎合大家的需要,因而具有广阔的市场空间。
    1.3 开发环境
    Android Studio
    1.3 系统整体结构图A-1给出了系统的物理组成结构。

    系统工作流程如图A-2所示:

    2 数据描述2.1 静态数据本系统支持本地时间同步、用户个人信息存储以及偏好存储。因此,本系统需要存储数据库部分信息,用户个人信息和本地发言以及此时同步的网络发言记录。
    2.2 动态数据
    用户登陆信息
    用户搜索结果
    社区实时留言
    用户个人信息

    2.3 数据库描述本软件采用云端数据库Bmob后端云的方式保存相关信息,因此可以不用静态数据库。如果使用,采用MS access 或 MS SQL 即可。(具体版本参照实验室版本)。
    2.4 数据字典


    数据项名
    代号
    数据类型
    数据长度
    取值范围




    用户编码
    Uid
    Varchar (11)
    11
    合法手机号


    留言
    MicroBlog
    Varchar(256)
    256



    用户昵称
    Uname
    VarChar(10)
    10



    用户院系
    Uposition
    VarChar(10)
    10



    本地年份
    Year
    int (4)
    4
    2018~2028


    本地月份
    Month
    int (2)
    2
    1~12


    本地日子
    Day
    int (2)
    2
    1~31


    本地小时
    Hours
    int (2)
    2
    00~23


    本地分钟
    Minutes
    int (2)
    2
    00~59


    本地秒钟
    Seconds
    int(2)
    2
    00~59


    课程名称
    Cname
    VarChar(24)
    24



    课程编号
    Cnumber
    VarChar(10)
    10



    课程类型
    Ctype
    VarChar(14)
    14



    开课学院
    College
    VarChar(16)
    16



    授课老师
    Cteacher
    VarChar(8)
    8



    上课时间
    Ctime
    VarChar(40)
    40



    上课地点
    Cplace
    VarChar(20)
    20



    学分
    Credit
    Float(2)
    2
    0.5-6


    学期
    Semester
    VarChar(11)
    11



    用户验证码
    Password
    VarChar (6)
    6
    000000—-999999


    偏好课程学期
    XQ
    VarChar(11)
    11



    偏好课程名称
    KCname
    VarChar (24)
    24



    偏好课程编号
    KCdm
    VarChar (10)
    10
    3000000000—3999999999


    偏好课程学分
    XF
    Float(2)
    2
    0.5—-6


    偏好课程类型
    KCLB
    VarChar(14)
    14



    偏好开设学院
    KSXY
    VarChar (16)
    16



    偏好课程老师姓名
    Tname
    VarChar (8)
    8



    偏好课程上课地点
    SKDD
    VarChar(20)
    20



    偏好课程上课时间
    SKSJ
    VarChar(40)
    40



    教材名字
    Bookname
    VarChar (20)
    20



    2.5 实体类类图2.5.1 个人信息类类图
    2.5.2 课程表类类图
    2.5.3 博客类类图
    2.6 数据采集系统运行时需要用户输入手机号完成短信码验证。社区数据需要网络同步,搜索及个人信息(包括用户个人偏好)均可本地设置。
    3 功能需求3.1 功能划分3.1.1 系统功能组成
    系统初始化设置
    用户登录
    用户管理
    搜索相关课程
    社区讨论
    公告板服务(对教务系统和百度等网站的跳转)
    个人页面

    3.1.2 功能编号和优先级系统功能优先级如表A-2所示。



    编号
    名称
    优先级
    描述
    主要发起者




    1
    系统初始化设置
    次要
    数据库交互
    系统


    2
    用户登录
    重要
    数据库提供短信服务
    用户


    3
    用户管理
    次要
    用户验证与注册
    管理员


    4
    搜索相关课程
    重要
    按需搜索课程
    用户


    5
    社区讨论
    重要
    发言、浏览其他用户发言
    用户


    6
    公告板服务
    重要
    对相关网站快捷跳转
    用户


    7
    个人页面
    重要
    用户完善个人信息页面
    用户



    3.1.3 功能定义
    设置系统初始化:设置基本参数,包括与云端数据库的交互,以及未登陆时可以访问的相关页面,并记录在系统文件或注册表中。系统在启动时自动从文件或者注册表中装载这些信息。用户调研该功能并能改变这些设置
    用户登录:通过Bmob后端云数据库的短信服务,将用户登陆验证方式确定为输入手机号并获取验证码的方式
    用户管理:进行用户信息管理,包括注册用户,更新用户,注销用户,以及登陆验证
    搜索相关课程:这一部分是我们所做的app最主要的功能之一,为了满足广大同学蹭课需求,我们将搜索做的多元化。一共提供三种搜索方式:分别是按上课时间,按老师,按课程名字(可具体可含关键字)
    社区讨论:为注册了的用户提供保存并记录发言的服务,同时可以浏览其他用户的发言。未注册的用户只可以浏览其他用户的发言
    公告板服务:当前app到教务处的跳转以及到百度等实用网页的跳转
    个人页面:为注册了的用户实现对个人相关信息的完善,包括昵称、院系等个人信息,同时为用户记录搜索过的相关课程的用户个人偏好

    3.2 功能描述3.2.1 功能说明
    设置系统初始化:设置基本参数,包括与云端数据库的交互,以及未登陆时可以访问的相关页面
    注册用户:创建新用户
    更新用户:更新用户信息
    注销用户:删除用户信息
    登陆验证:系统登录验证

    由于可获得的数据不是很多,我们这次做的初始版本是建立在本院以及理学院大一至大四的课表之上,其中涵盖了全校基础必修课以及本院专业特色课程。所以在1.0版本中,用户登陆验证仅支持通过特定口令验证的用户。通过验证之后,用户可以注册一个自己的账号,保存社区发言的相关信息。后随着数据库的提升,我们将用户登录改为短信验证方式。

    社区讨论:为注册了的用户提供保存并记录发言的服务,同时可以浏览其他用户的发言。未注册的用户只可以浏览其他用户的发言
    拓展服务:考虑到很多同学在初始问卷中反馈到接收教务系统通知不及时的问题,我们增加了这一项服务,实现了当前app到教务处的跳转以及到百度等实用网页的跳转
    个人页面:显示并定义个人信息,同时展示搜索偏好

    3 .2.2 详细描述采用活动图和类模型的方法建立模型。
    3.2.2.1 登陆子系统:实现用户的手机号验证及登陆
    3.2.2.2 蹭课查询子系统:实现按不同条件搜索及显示出搜索的最终结果

    3.2.2.3 公告板子系统:实现跳转不同网站

    3.2.2.4 社区页面子系统图:实现发言、浏览的功能

    3.2.2.5 个人信息子系统图:实现个人信息的设置和显示

    4 总体设计4.1 软件结构软件结构图如下所示,主要分为两大部分:

    登陆
    系统总控界面

    系统总控模块又分为四个模块:

    课程搜索
    社区留言
    查看公告板
    设置个人信息


    4.2 类图实际类与类之间的关系:下图A-2体现了实际编程过程中产生的类与类之间的依赖关系。Fragment依赖于对应的activity,而activity与调用它的源activity也保持依赖关系。

    主要模块类与类的关系细化:如图A-3所示,WelcomeActivity借助一个安卓封装的轻量级类判断程序是否过的执行状态,然后转移至LoginActivity。LoginActivity实现数据库服务的初始化与登陆验证功能,然后登陆成功后即可进入应用,访问四个主模块的功能。

    4.3 模块基本信息4.3.1 蹭课搜索子模块
    输入:查询课程的条件,例如上课时间、课程名称、任课老师等
    输出:符合所要求条件的课程,从上到下依次排列
    功能:完成对用户所输入信息的保存,完成对数据库的查询,完成对数据库所查信息的保存,并在界面上显示出来
    性能:在网络良好的条件下,要求1s内完成

    4.3.2 公告板子模块
    输入:用户选择需要使用的功能
    输出:跳转到用户选择的链接
    功能:根据用户的选择提供相应的界面供用户浏览
    性能:在网络良好的条件下,要求1s内完成

    4.3.3 社区子模块
    输入:用户希望的留言类型和留言内容
    输出:将用户的留言内容显示在界面上
    功能:完成对用户所输入信息的保存,并将数据库中已有的留言和用户的新留言一起显示在界面上
    性能:在网络良好的条件下,要求1s内完成

    4.3.4 我的子模块
    输入:用户根据自己的需要做出相应的选择
    输出:用户的基本信息、用户的偏好课程,并将它们显示在界面上
    功能:完成对用户所输入信息的保存,完成对数据库的查询,完成对数据库所查信息的保存,并在界面上显示出来
    性能:在网络良好的条件下,要求1s内完成

    4.4 程序逻辑登陆子模块程序逻辑顺序图

    搜索蹭课子程序逻辑顺序图

    社区子模块程序逻辑顺序图

    公告板子模块程序逻辑顺序图

    个人子模块程序逻辑顺序图

    4.5 算法4.5.1 登陆子模块
    欢迎界面初始化,通过相关状态判断是否第一次运行app
    如果第一次运行app,进入登陆界面,输入手机号并获取验证码进行验证
    如果不是第一次运行app,进入app主界面(搜索课程界面)

    4.5.2 搜索子模块
    选择相应搜索方式
    输入搜索关键词,并按下搜索按钮
    按钮触发事件,向数据库发送查询请求
    显示查询结果

    4.5.3 社区子模块
    向云端数据库发送请求,获取留言板已有留言
    定义留言类型按钮,同时在输入框输入文字,并点击发送按钮时实现字符串的连接,使得留言包含选择按钮的对应类型,并写入数据库
    通过数据库接口更新现有留言,显示出最新添加的留言

    4.5.4 公告板子模块
    定义按钮触发事件,跳转不同网站
    按钮按下时触发不同类型事件

    4.5.5 个人信息子模块
    设置个人信息按钮触发,进入个人信息设置界面
    通过文本框获得用户的昵称和院系,并保存写入本地,使得个人信息模块主页的昵称和院系更新为用户自定义的语句
    通过数据库接口,查询用户偏好课程的相关信息,并显示在偏好界面

    4.6 接口本程序需要云端数据库和云端短信服务的外部接口。
    搜索子模块需要和数据库之间进行信息交换,公告板子模块需要调用手机自带的浏览器以进行信息交换,社区模块需要与数据库之间进行数据交换,我的子模块需要与数据库之间进行数据交换。
    4.7 测试要点各个子模块主要测试输入接口与输出接口是否正确,以及模块内部的调用关系是否正确。可采用白盒测试技术设计测试用例以及处理测试逻辑,利用黑盒测试技术来测试接口。
    5 程序测试用户第一次登录,输入不合法手机号

    用户输入正确手机号,获得验证码

    选择按课程搜索,输入正确的课程名称,获得正确课程结果

    选择按上课老师名字搜索,输入正确的老师名,得到正确课程结果

    选择通过上课地点搜索,输入正确的上课地点,获得正确的课程结果

    选择按上课老师搜索,输入上课地点,得不到课程的搜索结果

    选择按课程搜索,输入不存在的课程名称,得不到正确的课程结果

    在网络正常连接状态,在公告板界面选择跳转到教务系统,正常跳转

    在网络连接正常情况下,在社区讨论界面选择评价课程,然后发表自己的看法,成功发表

    联网情况下查看自己的讨论发言,成功看到留言

    查看偏好课程,成功得到结果
    1 评论 58 下载 2018-11-06 10:29:29 下载需要8点积分
  • 基于C++实现的猴子选大王-各种排序-纸牌游戏

    1 课程设计任务和具体技术参数1.1 项目一1.1.1 任务一堆猴子都有编号,编号是1,2,3…m, 这群猴子(m个)按照1-m的顺序围坐一圈,从第1开始数,每数到第N个,该猴子就要离开此圈,这样依次下来,直到圈中只剩下最后一只猴子,则该猴子为大王。
    1.1.2 要求
    输入数据:输入m, nm, n为整数, n<m
    输出形式:中文提示按照m个猴子,数n个数的方法,输出为大王的猴子是几号,建立一个函数来实现此功能

    1.2 项目二1.2.1 任务用程序实现插入法排序、选择法排序、起泡法改进算法排序;利用插入排序、选择法排序和冒泡法的改进算法,将用户随机输入的一列数按递增的顺序排好。
    1.2.2 要求
    输入的数据形式为任何一个正整数,大小不限
    输出的形式:数字大小逐个递增的数列

    1.3 项目三1.3.1 任务编号为1-52张牌,正面向上,从第2张开始,以2为基数,是2的倍数的牌翻一次,直到最后一张牌;然后,从第3张开始,以3为基数,是3的倍数的牌翻一次,直到最后一张牌;然后…从第4张开始,以4为基数,是4的倍数的牌翻一次,直到最后一张牌;…再依次5的倍数的牌翻一次,6的,7的直到以52为基数的翻过,输出:这时正面向上的牌有哪些?要求有翻牌过程说明。
    2 项目一2.1 对设计任务内容的概述接收用户输入的猴子数来形成一个圈,再接收用户输入的淘汰间隔来不断淘汰对应位置的猴子,最后剩下的即为王。
    2.2 需求分析或功能描述用m来接收用户输入的猴子数,用n来接收用户输入的淘汰间隔,然后生成一个m个节点的循环单链表,通过头结点的移动n次找到淘汰对象进行淘汰,并输出淘汰情况,最后当尾节点指向自己时,表示未最后一个猴子,即输出此猴子为王。
    2.3 概要设计或程序流程图接收用户输入m、n,创建m长度的单向循环链表,以n为间隔不断淘汰。判断最后剩下的为王。以下为流程图:

    2.4 详细设计或源代码说明Monkey.cpp文件
    #include "Monkey.hpp"Monkey::Monkey(){ int m = 0,n = 0; //用来接收用户输入 while(m <= n && n > 1){ //m不大于n将无线循环 cout << "#请输入m,n(m必须大于n): "; cin >> m >> n; } /* * 创建长度为m的单项循环链表 */ LinkNode *L; //头结点 creatList(L,m); /* * 循环删除第n个结点 */ while(L -> next != L){ listDeleteN(L,n); } cout << "@@@大王就是,第" << L -> data <<"号猴子@@@" <<endl;}void Monkey::creatList(LinkNode *&L,int m){ int *a = new int[m]; for(int i = 1;i <= m;i++){ //给数组里顺序赋值 a[i - 1] = i; } LinkNode *s,*r; L = (LinkNode *)malloc(sizeof(LinkNode)); r = L; for(int i = 0;i < m;i++){ s = (LinkNode *)malloc(sizeof(LinkNode)); s -> data = a[i]; r -> next = s; r = s; } r -> next = L -> next; //把最后的指针指向头指针的下一个变为循环链表 //让L不参与删除}void Monkey::destroyList(LinkNode *&L){ LinkNode * pre = L,*p = L -> next; while(p != NULL){ free(pre); pre = p; p = pre ->next; } free(pre);}void Monkey::listDeleteN(LinkNode *&L,int n){ LinkNode *s,*p; for(int i = 0;i < n-1;i++){ //循环n次让头结点指向要删除的上一个 L = L -> next; } s = L -> next; Sleep(1); cout << "#" << s -> data << "号猴子已被淘汰" << endl; p = s; s = s -> next; L -> next = s; free(p);}
    2.5 程序模块及其接口描述Monkey(); // 构造函数void creatList(LinkNode *&L,int m); // 创建循环链表void destroyList(LinkNode *&L); // 摧毁链表void listDeleteN(LinkNode *&L,int n); // 传入变量n,删除第n个元素
    2.6 程序的输入与输出描述

    输入:两个数
    输出:淘汰情况和最终结果

    2.7 调试分析或程序测试
    2.8 尚未解决的问题或改进方向可以把界面改进更好看点。
    2.9 对软件的使用说明进入猴子选王界面后,需输入m与n用空格隔开,且m一定需要大于n,否则会要求重新输入。
    3 项目二3.1 对设计任务内容的概述对数组进行各种各样的排序。
    3.2 需求分析或功能描述需要用户输入数组的长度和数组内容,然后给用户选择排序方法,并可以看到排序的整个过程,并可以返回重新选择,则排序的数组并不能是原数组,需要每次用户选择时创建一个新的数组用来排序。
    3.3 概要设计或程序流程图
    3.4 详细设计或源代码说明Sorts.cpp文件
    #include "Sorts.hpp"Sorts::Sorts(int t){ n = t;}//插入排序//直接插入排序void Sorts::insertSort(int r[]){ int tmp,j; for (int i = 0; i < n; i++) { if(r[i] < r[i-1]){ tmp = r[i]; for (j = i - 1;j >= 0 && r[j] > tmp; j--) { r[j+1] = r[j]; } r[j+1] = tmp; } showArray(r); } system("pause");}//折半插入排序void Sorts::binInsertSort(int r[]){ int i,j,low,high,mid,tmp; for (i = 1; i < n; i++) { if(r[i] < r[i-1]){ tmp = r[i]; low = 0; high = i-1; while(low <= high){ mid = (low + high) / 2; if(tmp < r[mid]){ high = mid - 1; }else{ low = mid + 1; } } for (j = i-1; j >= high+1;j--) { r[j+1] = r[j]; } r[high+1] = tmp; } showArray(r); } system("pause");}//选择排序void Sorts::selectSort(int r[]){ int k; for (int i = 0; i < n-1; i++) { k = i; for (int j = i+1; j < n; j++) { if(r[j] < r[k]){ k = j; } } if(k != i){ swap(r[i], r[k]); } showArray(r); } system("pause");}//改进冒泡排序void Sorts::bubbleSort(int r[]){ bool exchange; for (int i = 0; i < n-1; i++) { exchange = false; for (int j = n-1; j > i; j--) { if(r[j] < r[j-1]){ swap(r[j], r[j-1]); exchange = true; } } if(!exchange){ return; } showArray(r); } system("pause");}//打印整个数组void Sorts::showArray(int r[]){ for (int i = 0; i < n; i++) { cout << r[i] << "\t"; } cout << endl; Sleep(1000);}
    3.5 程序模块及其接口描述//插入排序Sorts(int n);//直接插入排序void insertSort(int r[]);//折半插入排序void binInsertSort(int r[]);//选择排序void selectSort(int r[]);//冒泡改进排序void bubbleSort(int r[]);//打印整个数组void showArray(int r[]);
    3.6 程序的输入与输出描述3.6.1 输入
    3.6.2 输出直接插入排序

    折半插入排序

    选择排序

    冒泡排序

    4 项目三4.1 对设计任务内容的概述纸牌1-54号,基数从1到54,当号数能整除基数则翻面。
    4.2 需求分析或功能描述需要定义一个数组存储54个1表示正面,然后循环基数,当号数能整除基数即取反,1变为0,0变为1。
    4.3 概要设计或程序流程图用到双重循环,第一个循环遍历数组,从0到53,第二层循环从号数到最后一个,循环里面判断 号数%基数是否为0,为0则需让其值取反。
    4.4 详细设计或源代码说明#include "Card.hpp"Card::Card(){ for (int i = 0; i < 54; i++) { //全部初始化为正面(1为正面,0为反面) card[i] = 1; } for (int i = 2; i < 54; i++) { for (int j = i; j < 54; j++) { if (j % i == 0) { card[j] = !card[j]; } } system("cls"); showCard(); //每改变一次清空界面,显示新的结果 cout << "#现在的基数为:" << i ; Sleep(1000); }}void Card::showCard(){ //用来输出整个数组 for (int i = 1; i <= 54; i++) { cout << card[i-1] << "\t"; if (i % 7 == 0) { cout << endl; } } cout << endl;}
    4.5 程序模块及其接口描述// 构造函数,所有执行都在里面表示,创造对象即可执行,无需调用其他函数Card(); // 用来遍历显示整个数组void showCard();
    4.6 程序的输入与输出描述4.6.1 输入无需输入。
    4.6.2 输出
    4.7 尚未解决的问题或改进方向界面只用0和1表示正反面,可以用更好看的来表示。
    4.8 对软件的使用说明进入界面即可,界面不断变化表示翻转的变化。
    5 总结这次课程设计选择的三个题目分别为猴子选大王、各种排序、纸牌游戏分别用到了循环单向链表、多种排序算法和数组的灵活运用。多方面的对数据结构的概念运用起来,让在学习数据结构课程过程中留下的“学这些用来干什么?”疑问得到了解答,同时加强了自己C++的编程能力。同时在完成课程设计过程中也遇到了各种各样的问题,比如实现猴子选大王时,淘汰猴子时多了一个猴子,经过设断点发现带着头指针一起淘汰了,就多了一个淘汰名额,最后通过把头指针分离出循环链表来改正了这个错误。还有在排序过程中,太多排序方法有点混淆,最后通过翻书确认最后完成了这个模块。最后通过不断改进,不断调试完成了界面整合,也对一些防止用户错误输入进行了判断,整体变得更加一体性。
    参考文献[1]《数据结构实验教程(C/C++语言版)(第二版)》,张仕等,厦门大学出版社,2018
    [2]《数据结构(C语言版)》,董树锋,科学出版社,2018
    [3]《数据结构(C语言版)》,严蔚敏 吴伟民,清华大学出版社,1997
    [4]《Data Structures Using C数据结构(C语言版)》,R Krishnamoorthy、G Indirani Kumaravel,清华大学出版社,2009
    [5]《C++数据结构与程序设计 (美)Robert L.Kruse/Alexander J.Ryba著/钱丽萍译》,清华大学出版社,2004
    [6]《计算机算法设计与分析(第2版)》,王晓东, 电子工业出版社, 2004
    1 评论 4 下载 2018-11-06 10:00:56 下载需要3点积分
  • 基于Python实现的简单生命游戏

    一、引言1.1 开发背景康威生命游戏,又称康威生命棋,是英国数学家约翰•何顿•康威在1970年发明的细胞自动机。 它最初于1970年10月在《科学美国人》杂志上马丁•葛登能的“数学游戏”专栏出现。在游戏的进行中,杂乱无序的细胞会逐渐演化出各种精致、有形的结构;这些结构往往有很好的对称性,而且每一代都在变化形状。一些形状已经锁定,不会逐代变化。有时,一些已经成形的结构会因为一些无序细胞的“入侵”而被破坏。但是形状和秩序经常能从杂乱中产生出来。对于生成的形状和秩序我们称作 pattern。或者在这里,我们也把它称作 creature。“生命游戏”并不是通常意义上的游戏,它没有游戏玩家之间的竞争,也谈不上输赢,甚至可以说游戏的一开始就注定了结果。
    1.2 开发目的和意义本游戏是小组共同开发的课程设计项目,实现了基础的康威生命游戏规则,能够模拟生命繁殖演化的基本过程,实现了必要的图形界面。
    开发生命游戏,让“仿真生物”生存于计算机上,在计算机上生存、死亡,从而模拟生命的演化,通过计算机的模拟,了解生命在一定规则下,开始条件对最终结果的影响,突发事件对最终结果的影响。
    二、需求分析2.1 设计内容和要求制作用户图形界面,使得游戏在运行时,用户能在图形界面上进行操作和直观的看到演化过程与结果。
    按钮,开始、暂停、重置,用来控制繁衍进程。
    用户界面的要求:一个N*N的二维格子界面和对应开始、暂停、重置的按钮,每一个格子代表一个生命,亮为生、暗为死,每一次格子的生与死都显示在屏幕上。
    一个细胞在下一个时刻生死取决于相邻八个方格中活着的或死了的细胞的数量。用代码实现生命游戏中的规则,通过算法控制,计算格子在每一刻的生死状态。
    使用鼠标添加或删去细胞。
    添加游戏说明,方便用户使用。
    2.2 技术上的可行性分析2.2.1 游戏功能在一个二维矩形世界中,每个方格里居住着一个活着的或死了的细胞,每个细胞有两种状态-存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。
    一个细胞在下一个时刻生死取决于相邻八个方格中活着的或死了的细胞的数量,模拟生命繁衍。
    可以通过按钮控制繁衍进程,使用鼠标添加或删去细胞。
    2.2.2 游戏规则
    人口过少:当周围低于2个(不包含2个)存活细胞时, 本单元活细胞死亡
    稳定:当周围有2个或3个存活细胞时, 本单元细胞保持原样
    人口过剩:当周围有3个以上的存活细胞时,本单元活细胞死亡
    繁殖:当周围有3个存活细胞时,本单元细胞存活/活化

    2.2.3 游戏界面
    背景世界地图为黑色,画有灰白的网格线,作为各细胞间的分界
    单个活细胞为矩形,红色,死亡细胞为黑色,构成背景
    地图右侧放置按钮,开始、暂停、重置,用来控制繁衍进程
    添加游戏说明,方便用户使用

    经查阅资料并进行分析,利用python及其标准化的库,可以实现我们的设计要求
    2.3 开发环境与工具使用
    操作系统:Windows
    开发工具:PyCharm Community Editon 2016.1.3、Java Pydev
    开发语言:Python
    编码方式:UTF-8
    团队管理工具:leangoo
    版本控制工具:Git
    自动单元测试框架:pyunit
    性能分析:profile
    代码检查:pylint

    三、总体设计3.1 总体结构
    3.2 各功能模块描述
    Button :定义按钮的图像以及具体的位置
    Cell:定义细胞类,包括细胞的大小和颜色,获取细胞位置在画布上绘制细胞
    Data:画布,以及程序相关的具体的数据
    Draw:将画布擦除后,画上按钮,格子以及具体的网格线,然后遍历网格数组中的细胞状态
    next_generation:定义细胞更新的规则:当一个细胞周围有两个或三个细胞时细胞状态为存活,当周围细胞过多或者过少时定义为细胞死亡
    States:将整个游戏世界设定为二维数组,每个网格的状态值分为0,1两种,定义按钮功能,含开始运行、暂停、重置三个方法

    开始运行:获取当前鼠标的状态和位置随时更新画布,并且根据细胞规则随时更新细胞暂停:根据鼠标状态随时更新画布重置:初始化整个画布,数组用0填充
    main:程序的开始入口,设置界面的大小,定义状态机的三种状态:运行状态,暂停状态,以及重置,然后进入游戏的主循环

    3.3 主要模块设计状态机三种状态的设置:开始,暂停,以及重置,主要在States模块中实现:

    States:将整个游戏世界设定为二维数组,每个网格的状态值分为0,1两种,定义按钮功能,含开始运行、暂停、重置三个方法

    开始运行:获取当前鼠标的状态和位置随时更新画布,并且根据细胞规则随时更新细胞
    暂停:根据鼠标状态随时更新画布
    重置:初始化整个画布,数组用0填充


    3.4 核心代码设计next_generation:细胞规则的制定是核心代码的一部分,具体设计。遍历二维数组,更新接下来各个细胞的状态:
    def next_generation(): nbrs_count = sum(np.roll(np.roll(pygame.world, i, 0), j, 1) for i in (-1, 0, 1) for j in (-1, 0, 1) if (i != 0 or j != 0)) pygame.world = (nbrs_count == 3) | ((pygame.world == 1) & (nbrs_count == 2)).astype('int')
    四、测试分析4.1 游戏开始测试测试点击开始按钮游戏界面立即作出响应,并且可以按照细胞规则进行正确的更新。
    4.2 游戏重置测试点击重置按钮,程序立即作出响应,并且画布被擦除。
    4.3 使用工具进行分析测试
    自动单元测试框架:pyunit
    性能分析:profile
    代码检查:pylint

    分析测试细节详情请见对应的工具使用文档。
    五、具体的使用说明
    打开程序,出现游戏界面
    在界面上选择点击相应格子,左键添加细胞,右键擦除细胞
    点击开始,程序自动运行,最终在界面上显示结果,或为一有各个格子组成的特殊图形,或一直杂乱的进行演化
    也可在任意时刻点击暂停按钮,查看到这一时刻生命游戏在一定规则下生成的结果
    玩家可以随时在画布上添加或者擦除细胞
    点击重置按钮可以清空画布,重新来过

    运行截图演示:




    1 评论 20 下载 2018-11-06 09:56:14 下载需要5点积分
  • 基于SDL类库实现的射死大鸡怪3D游戏

    1 游戏架构介绍整个游戏分为三个层次:游戏逻辑层,游戏引擎层和软件渲染层。

    游戏逻辑层用于控制游戏逻辑,如大鸡怪移动,玩家发子弹,陨石移动,判断输赢这类,这些事比较高层的
    中层的渲染引擎,提供较为底层的渲染支持,包括模型、图片、虚拟摄像机、灯光等等的对象。有一个渲染器,获取渲染对象来进行渲染。同时还获取了一些底层的支持
    最后一层就是软件渲染层,用CPU来实现了directx/openGL这些很底层的渲染API的功能,在CPU上模拟,实现最底层的3D渲染的逻辑

    这里还有必要再提示一下游戏逻辑层。我们的这个游戏是状态驱动的,整个游戏的运行是由状态及驱动的。在一个状态就循环运行对应的逻辑。
    为了开发说明,具体说明一下。

    中层的是Engine文件夹里面的渲染引擎,提供较为底层的渲染支持,包括模型,图片,虚拟摄像机,灯光等等的对象
    VS工程里面renderer文件夹,作为渲染器,获取scene文件夹下的渲染对象(具体的图形数据),画出来
    _Core文件夹下的是底层支持(例如数学、文件解析与I/O)
    RenderPiline3d.cpp /.h负责用CPU模拟软件渲染,执行最底层的3D渲染的逻辑

    2 技术细节2.1 透视投影
    2.2 双线性插值
    2.3 直线和三角形求交
    2.4 透视校正插值在3D渲染中,输入数据是一些primitive信息,包括顶点位置、颜色、纹理坐标等等。在光栅化阶段,primitive(一般为三角形)被转化成一 系列的fragment(或者称为像素),这些fragment接下来要做ps操作,此时每个fragment都有位置、颜色、纹理坐标这些属性信息,这 些属性信息通过顶点属性用插值方法得到的。比如下面的primtive,输入数据中只有a、b、c三个顶点的信息,则三角形内部经过扫描转化得到的像素f 的颜色则是通过插值得到,d是a、b的差值,e是a、c的差值,然后f又是d、e的插值。

    下图是clip裁剪锥体的xz平面,从图中可以看出,在投影平面的均匀插值(一系列蓝色的标记),它们实际位置距离并不是均匀的,距离投影平面越远,实际位置距离越长,所以这是我们采用线性插值的话,可能最终的结果并不是我们所想要的。

    那么如何得到均匀的顶点属性插值呢?稍等一下,我们先看看深度插值:
    点O是视点位置,从视点观察物体的投射线和投影平面相交的点即为物体在投影平面上的投射点,比如(x1,z1)在投影平面上的投射点为(p1,-e),投 射线的方程为ax+bx =c , 其中c不能等于0,假设点(x,z)的和O在投影平面的交点为(p,-e)(注意z坐标总是-e),则有

    解出x,并把它带入到ax+b=c中,得到

    假定p3=(1-t)p1+tp2 (0<=t<=1),即p3是投影平面上2个端点的线性差值的x分量,则有下面的推导公式:

    可见,z的倒数是线性插值,所以我们可以用顶点的z值来插值求得primitive内部fragment的属性值,比如颜色等等。假定的颜色为b1, 的颜色为把b2,则的颜色为b3为:

    可见用深度导数来插值顶点属性是合适的。
    2.2 PPM/PGM/PBM图像文件格式ppm文件是一种图像文件,有其自己的文件格式。ppm文件由两个部分组成:第一个部分是三行ASCII码,这个部分决定了图像的存储格式以及图像的特征;第二个部分就是图像的数据部分,图像就是由这个部分组成的。
    ppm的第一部分由三行ASCII码组成

    第一行是P2/P3/P6
    第二行是图像的大小,先是列像素数,后是行像素数,中间有一个空格
    第三行是一个介于1和65535之间的整数,而且必须是文本的,用来表示每一个像素的一个分量用几个比特表示

    三行之后是图像的数据流

    从左到右,从上到下。在进行图像数据存储的时候,需要进行数据的格式,假如需要的像素值在0~255之间,那么在进行 数据文件保存的时候,所写入文件的值就必须是以%c的形式输入,而且数据之间没有明显的分离字符,图像处理软件会自动地识别这些像素的值,并给予处理
    3 游戏界面游戏主界面

    游戏场景选择界面

    1 评论 1 下载 2018-11-06 09:35:20 下载需要6点积分
  • 基于B树实现的图书管理系统

    1 需求分析1.1 数据结构分析图书管理系统中图书管理模块包括图书类型定义:书号(int),现存量(int),总存量(int),出版时间(int),价格(float),书名,作者名为字符型,借阅指针为读者类型;
    读者类型定义:ID号(int),姓名为字符型。
    B树(2-3树)类型定义:关键字个数和关键字数组为整型,另外还有指向双亲的指针,指向子树的指针;
    B树查找结果类型定义:结点指针,关键字序号和查找标志变量为整型。
    1.2 输出的形式输出界面以用户于计算机的交互方式进行,在输出窗口上显示“特定的提示信息”之后,由用户按提示在键盘上输入演示程序中规定的运算命令,相应的输入数据和运算结果显示在下面。由于时间和能力有限,该管理系统没有用文件存放数据,所有数据放在内存中存放(后来做了改进版就有了),但是选做的功能就还没有实现。其基本业务都是以书号为关键字进行,采用了(2-3树)对书号建立索引,以提高效率。
    1.3 程序所能达到的功能1.3.1 采编入库
    新书购入,将书号,书名,作者,册数,出版时间以及价格添加入图书管理系统中,如果这种书在系统中已存在,则只将总库存量增加,每增加一个书号则以凹入表的形式显示B树形状。
    1.3.2 清除库存
    实现某本书的全部信息删除操作,每清除一个书号则以凹入表的形式显示B树形状。
    1.3.3 图书借阅
    如果树的库存量大于零时则执行出借,登记借阅者的图书证号和姓名。
    1.3.4 图书归还
    注销借阅者信息,并改变该书的现存量。
    1.3.5 查看图书馆全部图书
    用表格输出所有图书的信息。
    1.3.6 查看某图书信息
    查看指定某一本书的全部信息。
    1.3.7 查看某本书的借阅者信息
    表格输出某本书的全部借阅者信息。
    1.3.8 读取图书信息
    从文件中读取所有图书的信息以及所有借阅者的信息
    1.4 测试数据
    入库书号:35, 16, 18, 70, 5, 50, 22, 60, 13, 17, 12 , 45, 25, 42, 15, 90, 30, 7
    然后清除:45, 90, 50, 22, 42
    其余数据自行设计。由空树开始,每插入删除一个关键字后就显示B树的状态。

    2 概要设计2.1 所有数据类型的定义采用KeyType类型(本次实验默认为int)为元素类型实现抽象数据类型BTree。
    ADT BTree{
    数据对象
    T是具有相同特征的数据元素集合。
    数据关系
    若D为空集,则称为空树;

    树中每个结点最多含有m棵子树
    若根结点不是叶子结点,则至少有2个子树
    除根结点之外的所有非终端结点至少有┌m/2┐棵子树
    每个非终端结点中包含信息:(n,A0,K1,A1,K2,A2,…,Kn,An)。其中:

    Ki(1<=i<=n)为关键字,且关键字按升序排序指针Ai(0<=i<=n)指向子树的根结点,Ai-1指向子树中所有结点的关键字均小于Ki,且大于Ki-1
    关键字的个数n必须满足:┌m/2┐-1<=n<=m-1。 (5)所有的叶子节点都在同一层,子叶结点不包含任何信息


    基本操作
    result SearchBTree(BTree T, int k);

    初始条件:树T存在
    操作结果:在m阶B数T上查找关键字k,返回p{pt,i,tag}

    Status InsertBTree(BTree &T, int k, BTree q, int i, Record *recptr);

    初始条件:树T存在
    操作结果:在B树T上结点p->pt的key[i]和key[i+1]之间插入关键字k

    Status DeleteBTree(BTree &T, int k);

    初始条件:B树上p结点存在
    操作结果:删除B树T上结点p->pt的关键字k

    void BTreeTraverse(BTree T, void(*visit)(BTree));

    初始条件:树T存在
    操作结果:用visit()函数遍历B树

    void DestroyBTree(BTree T);

    初始条件:树T存在操作结果:销毁B树
    } ADT BTree
    ADT Library{
    数据对象
    T是具有相同特征的数据元素集合。
    数据关系
    数据元素同属于一个集合。
    基本操作
    void InitLibrary(BTree &L);

    操作结果:初始化书库L为空书库
    void InsertBook(BTree &L, BookType B, result res);

    初始条件:书库L和B存在,result包含B书在书库中的位置或应该插入的位置
    操作结果:如果书库中已存在B树,则只将B树库存量增加,否则插入B书到书库L中

    int DeleteBook(BTree &L, BookType B);

    初始条件:书库L和B存在
    操作结果:如果书库中存在B书,则从书库中删除B书的信息,并返回OK,否则返回ERROR

    void BorrowBook(BTree L, BookType B, ReaderType R);

    初始条件:书库L存在,B书时书库中的书并且可被读者R借阅
    操作结果:借出一本B书,并登记借阅者信息

    int ReturnBook(BTree L, int booknum, int IDnum, BookType &B, ReaderType &R);

    初始条件:书库L存在
    操作结果:若书库L中有读者R借阅B书的记录,则注销该记录,改变B书现存量,并返回OK,书不存在或物该读者记录则返回ERROR

    void PrintAllbooks(BTree L);

    初始条件:书库L存在
    操作结果:显示所有图书的信息

    int ShowBookinfo(BTree L, int booknum);

    初始条件:书库L存在
    操作结果:若书库L中存在书B,则显示B书基本信息并返回OK,否则返回ERROR

    void PrintBorrower(ReaderType R);

    操作结果:输出某本书所有借阅者的信息
    } ADT Library
    2.2 主程序的流程
    2.3 各程序模块之间的调用关系
    3 详细设计函数和过程的调用关系图

    4 调试分析4.1 调试过程中遇到的问题是如何解决的以及对设计与实现的回顾讨论和分析此次的课程设计的重难点应该在于B树的定义以及删除操作,由于我设计性实验选的也是B树,有几个操作函数大同小异,不过要在原来的基础上增加一些东西,例如在原有的关键字的基础上加上与关键字对应的图书结点,因此算法需要一些小改动。
    一开始程序跑不起来,一看居然68个错误,可是大致看下来都是不太正常的提示,所以在这个地方卡了蛮久的时间,好在经过不断的调试,发现是头文件里各个数据结构的顺序放倒了,更改顺序后只剩下寥寥几个小错误,大大增长了把程序做好的希望。
    此次实验的不足在于这个图书管理系统的存储是建立在内存上的,故程序退出数据得不到保存,每次都得重新输入(经过改进已经解决这个问题)。每个功能比较独立,相互联系不算多,仅仅是完成各部分需求的算法,采编入库,清除库存和显示信息相对逻辑关系强一点。由于个人能力的局限以及时间上的紧迫,此次的选做要求没有实现,系统功能的不够完整和联系不够紧密是我以后要提高的地方。
    4.2 算法的时空分析(包括基本操作和其他算法的时间复杂度和空间复杂度的分析)和改进设想设B树的阶为m,(书号)关键字个数为N

    SearchBTree最好情况为O(1),最坏时比较的结点数不超过log[m/2]((N+1)/2)+1
    因为B树总是在最后一层插入,因此InsertBTree操作比较的结点数也不超过log[m/2]((N+1)/2)+1
    DeleteBTree最好情况为被删关键字在最下层结点而且删除后该结点关键字个数不小于m/2,时间复杂度O(1);最坏情况为删除后需要合并父节点直到到根节点,需比较2 *(log[m/2]((N+1)/2)+1)次
    InsertBook、DeleteBook时间复杂度与B树的插入和删除基本相同
    BorrowBook、ReturnBook除了需要SearchBTree,还与该书借阅人数成正比

    4.3 经验和体会
    按照指导书给出的实习报告规范的步骤,先进行需求分析、概要设计,再进行详细设计,能使实际问题从抽象到具体,能从整体上把握程序的功能方向
    通过划分成几个模块,单独编写每个模块的基本操作,再组合在一起,细分了程序的功能,降低设计的难度,方便了程序的调试、修改和组合
    本次设计实在被B树的指针折磨透了,我深深的体会到:编码时必须对程序的算法了如指掌,对可能出现的每一种情况都处理周到,不然对于复杂的(像B树的删除)函数将会无所适从
    编码时就应该尽量把程序写正确,避免产生错误,这样可能远比调试时才来发现问题、解决问题用的时间少得多,效率高得多
    测试时要注意测试的完备性
    编码时要形成一种自己的风格,同时要注意这种风格应该是大众所接受的,要保持程序的可读性

    5 用户使用说明
    本程序的运行环境为Windows 10操作系统,编译环境是VS 2015
    执行文件为BTree_Library.exe,打开BTree_Library.exe,显示欢迎界面



    输入管理员密码:5372


    进入图书管理系统


    选择1新书入库后提示输入入库书号,读入书号后程序会查找是否已存在,如已存在则提示输入新增加数量,如不存在则提示输入图书其他书名、著者、等信息,插入后显示B树状态
    选择2清除库存后,提示输入删除书号,如果存在该书则提示是否确认删除,如无该书则提示不存在。删除后显示B树状态
    选择3图书出借后,提示输入书号,如该书存在则显示该书,提示输入借阅证号和借阅者姓名,判断如果能借阅则输出借阅成功,否则输出不能借阅;如无该书则提示不存在该书
    选择4图书归还后,提示输入归还书号和借阅证号,如存在该借阅记录则提示还书成功,否则提示不存在该书或无该读者借书记录
    选择5查看图书馆所有图书后,以表格形式输出图书管理系统的总库存
    选择6查看某图书信息后,以表格形式输出该图书的库存情况以及作者等相关信息
    选择7查看某树借阅者信息后,以表格形式输出该图书的所有借阅者的信息
    选择8将文件中的图书内容和借阅者资料导入
    选择0则退出系统

    6 测试结果列出你的测试结果,包括输入和输出。这里的测试数据应该完整和严格,最好多于需求分析中所列。
    将全部数据输入后用凹入表形式显示B树:

    使用功能5:用表格输出图书馆总库存:

    选择功能2:清空某一本书的库存

    清除45后的凹入表:

    用功能2依次清除:45, 90, 50, 22, 42后的凹入表表示如下:

    选择功能3:借阅图书,输入要借的图书号,借阅者的姓名和ID号

    选择功能6:查看某一本图书的信息,并以表格形式输出。

    选择功能4:归还图书

    当图书号不存在时,输出书库中不存在此书

    当借书时该图书的库存已空,则提示库存不足,借阅失败!

    选择功能7:查看某本书的借阅者信息

    输入功能8:从文件中导入图书信息和借阅者信息
    1 评论 99 下载 2018-11-05 22:49:53 下载需要10点积分
  • 基于C++的图书管理系统

    1 需求分析图书管理系统的功能如下:

    用户查找书目,可按照书名或者作者名查找
    用户添加或删除数目,添加书目时若原来存在,则增加数目;若不存在,则新建书 目;添加时可选择添加本数
    用户借阅或归还书目,可提示用户数目库存并根据借阅情况修改书目列表

    2 实现思路2.1 功能结构图
    本图书管理系统主要分为增加或删除,借阅或归还,查询三大模块,分别对增加,删除,借阅,归还和查询的操作进行管理。

    增加或删除模块中,对于增加模块,如果列表中存在这种书目,则增加库存;若不存在,则新建书目;当增加书目时,可选择增加数量
    而对于借阅或归还模块,如果用户想要借阅的书不存在,会返回与管理员联系的提示,否则显示本书库存
    归还模块中,如果不存 在要归还的书,会先新建书目,然后记录入列表。对于查询模块,可以按照书名查找或者按 照作者名查找,为用户提供了方便

    3 数据设计struct Book{ stringname; // 书名 stringauthor; // 作者名 intnum=0; // 现有数量 inttotal=0; // 总库存 };
    4 函数设计voidcheckbook(stringstr); // 通过书名查找书目voidcheckauthor(stringstr); // 通过作者查找书目voidborrowbook(stringstr); // 用户借阅书目子函数voidreturnbook(stringstr); // 用户归还书目子函数voidaddbook(stringstr); // 增加书目 voiddelebook(stringstr); // 删除书目 voiddesktop(); // 主菜单界面显示 voidreadlist(); // 从 booklist 文档中读取书目列表 voidbaocun(); // 将新更改信息写入 booklist 文档中
    5 输入输出通过系统主菜单界面提示,用 cin 读取用户每步操作,用 cout 输出信息,其中包括书名,作者名,现有数量,总库存等信息。
    程序主界面
    1 评论 39 下载 2018-11-05 22:08:15 下载需要3点积分
  • 基于C++实现的多项式计算器系统

    1 实验目的
    本实验面向 C++语言的初学者。
    主要让实验者熟悉面向对象的编程思想以及类的使用。

    2 实验环境
    本实验可基于Visual Studio 或Eclipse 或Dev C++平台开发,参考主流的编码规范,如Google C++Style Guide(中文版)
    2.1 编程语言和开发工具
    编程语言: ANSI C++
    开发工具: Dev C++

    2.2 编码规范要求遵循良好的程序设计风格来设计和编写程序。基本编码规范:

    标识符的命名要到达顾名思义的程度
    关键代码提供清晰、准确的注释
    程序版面要求:

    不同功能块用空行分隔
    一般一个语句一行
    语句缩进整齐、层次分明。


    3 实验内容通过 C++的类及运算符重载与其它相关知识,编写一个多项式计算器系统的源代码,生成可执行程序,进行辅助简单多项式计算。
    4 分析与设计简要描述程序设计的过程,包括设计思路,设计要点及特色;程序的不足与改进等。要求画出程序的简单流程图。
    4.1 需求分析通过代码生成的可执行程序,辅助进行简单的多项式计算,如加法减法乘法等等,并含有储存读写功能。
    4.2 类结构设计class polynomial{ public: double xishu[20]; //多项式各次系数 int mi[20]; //多项式各次幂 string name; //多项式名字 polynomial() { //构造函数 for(int i=0; i<20; i++) { xishu[i]=0.0; mi[i]=0; } name=""; } friendostream &operator<<(ostream&os,polynomialother); polynomial &operator=(polynomiala); friend polynomial operator+(polynomial a1,polynomial a2); friend polynomial operator-(polynomial a1,polynomial a2); friend polynomial operator*(polynomial a1,polynomial a2); friend polynomial operator*(polynomial b,int changshu); friend bool operator==(polynomial a1, polynomial a2); polynomial qiudao(); double qiuzhi(int a);};
    类中定义了多项式的名字,系数和幂,以及初始构造函数和各种运算符 的重载,只有一个类,没有类之间关系图。
    4.3 细节设计数据成员设计
    double xishu[20]; // 多项式各次系数 int mi[20]; // 多项式各次幂 string name; // 多项式名字
    成员函数
    polynomial(){ //构造函数 for(int i=0;i<20;i++) { xishu[i]=0.0; mi[i]=0; } name=""; } friend ostream &operator<<(ostream &os,polynomial other); polynomial &operator=(polynomial a); friend polynomial operator+(polynomial a1,polynomial a2);friend polynomial operator-(polynomial a1,polynomial a2); friend polynomial operator*(polynomial a1,polynomial a2);friend polynomial operator*(polynomial b,int changshu);friend bool operator==(polynomiala1,polynomiala2); polynomial qiudao();double qiuzhi(inta);
    5 实验结果主界面

    计算测试

    经过 17 个错误,36 个错误,27 个错误,26 个错误等等的数次检查,在没有语言错误时却出现了程序停止工作,最后发现在长度为 20 的数组循环时出现了低级失误,写成了 i=0;i <=20;。改正过后,在前几次运行中,不管输入幂为几,最后 的计算结果在每项上的幂都是 0,检查了好长时间没有发现错误,最后进行在运算符重载函数中添加赋值语句,解决了问题。
    6 设计心得每一次的项目都是一次长久煎熬,基本是好多地方不会打,和小组讨论很多关键地方,统一了想法,却又不能打出相似的代码导致被罚分,真的是心力交瘁。自己打的过程中更是难上加难,打一段时间就出现了空白或者短路,甚至焦躁,再加上让人无力的 debug,简直要作死我自己。这次的多项式计算器系统,在文件的读取和写入部分,一直不是很了解,所以还要去过多参考了解其他同学的思想。老师规定了使用类以及运算符重载,我们还试着去完成多余的三个功能,并且尽力使操作简单,界面美观。总之,希望以后的日子里慢慢提升。
    1 评论 19 下载 2018-11-05 22:04:12 下载需要2点积分
  • 基于Linux的教务选课系统

    1 目的
    实现教务选课系统(包括学生端,教师端以及教务端)
    2 实验环境
    Linux下(g++编译)
    3 需求分析根据自己的选课体验,选课系统应该有如下功能:

    4 实现思路4.1 功能结构图
    4.2 数据与函数设计:表示选课系统的system类

    这个类的数据包含:

    全部课程信息(Class类的vector)
    全部学生的信息(student的vector)
    全部老师的信息(teacher类的vector)
    全部教务员信息(education administer类的vector)

    这个类的接口(功能函数):

    打印系统功能(包括登陆、注册)print_func( )
    登陆功能 login()
    注册功能 register()
    添加成员(如果是注册就需要添加成员)add_member( )
    登陆/注册以后载入函数信息 load()
    把文档中成员信息写入程序write_in()
    推出程序之前把信息保存到文档place_in_file()

    课程类class

    数据内容包括课程名字,上课时间、地点,老师名字,每学期学分,最大容量,现有人数,课程状态(已通过批准或者还未通过教务员批准)
    成员类person

    作为学生,老师,教务员的父类。
    数据成员:
    用户id,用户名(相当于每个人的名字,可以更改),用户密码,用户身份(分为学生,老师,教务员三种)
    函数成员(也即所有成员都可以执行的操作):

    虚函数(这个两个函数会根据具体身份调用其子类的函数)
    virtual void print_func(); virtual int select_func();
    更改密码或者用户名
    void change_password(string s); void change_username(string s);
    列出所有课程
    void list_all();
    根据名称或者老师查找课程:
    void find_by_classname(string name); void find_by_tchname(string name);

    Person的子类student、teacher、education administer

    学生类,相比于父类,多出来的数据成员有

    装载该学生拥有的所有课程的vector —— myclass
    虚函数:
    void print_func (); int select_func();
    多出来的操作即学生的操作:
    void list_myclass(); // 列出自己的课程void shield_conflict(); // 隐藏冲突课程void shield_full(); // 隐藏满员课程void select_class(string name); // 选择课程void delete_class(string name); // 退课

    老师类,相比父类,多出来的数据成员有

    装载该老师已开放并通过审核的课程的vector —— have_opened
    以及正在申请对学生开放的课程的vector —— to_be_review

    虚函数:
    void print_func (); int select_func();
    多出来的函数成员:
    void list_myclass(); // 列出课程void open_class(Class a); // 开课void delete_class(Class a); // 删除课程

    教务员,相比父类

    多出来的数据成员有待审核的所以课程to_be_review
    虚函数:
    void print_func ();int select_func();
    多出来的函数:
    void show_need_review(); // 展示所有待审核课程void approve_class(Class a); // 通过某一课程的审核void disapprove_class(Class a); // 将某一课程下架(可以让该课程不再对学生开放)
    4.3 设计思路1.将所有代码及程序文件和数据保存文件分别放在两个不同的文件夹中,当程序打开时,write_in()打开数据文件并把文档中成员信息写入程序。
    2.然后进入登陆/注册环节,审核通过以后注册成功。

    登陆:核对用户的id与密码是否相符合注册:需要用户提供相应的代码来确定用户的身份(是学生还是老师还是教务员)
    3.载入用户信息load函数。
    4.进入操作环节

    步骤三的load函数返回一个person类的引用temp然后用temp调用虚函数print_func根据具体载入的用户类型调用具体类型的打印函数再用temp调用虚函数select_func根据具体载入的用户类型调用具体类型的选择操作
    公共操作:

    更改用户名、密码(这个直接改,很简单)列出所有课程(这个直接遍历vector<Class> c_all 打印即可)查找相应课程(遍历vector,如果该课程name与输入相符,打印即可)
    差别操作:
    学生的:
    void list、_myclass();列出自己的课程,遍历vector<Class>myclass 即可

    隐藏冲突课程—— void shield_conflict();这个函数通过比较class类的time信息来判断具体课程是否与该学生的课程(myclass)的time冲突,如果冲突,就不打印该课程
    隐藏满员课程—— void shield_full();如果某课程的最大容量等于当前学生人数(即Class类的capacity==stu_num),就不打印该课程
    选择课程void select_class(string name);即在该学生的vector\<Class\>myclass中加入这个课程并且所有相应的存有stu_num的数据都惊醒stu_num++的操作
    退课void delete_class(string name);即在该学生的vector<Class>myclass中删除(erase)这个课程,并且所有相应的存有stu_num的数据都惊醒stu_num—的操作

    老师的:

    列出课程void list_myclass(); 遍历vector <Class>have_opened和 vector \<Class>to_be_review 即可
    开课void open_class(Class a); 定义一个Class对象,要求老师输入课程名称并且完善相应课程信息到该对象,并且判断老师的课程是否存在重名、时间,地点冲突等问题。完成以后,将该对象插入到该老师的vector \<Class\>to_be_review当中,并且插入所有教务员的vector <Class>to_be_review中
    删除课程void delete_class(Class a);遍历vector <Class>have_opened和 vector <Class>to_be_review找到名字和对象a的名字相同的成员,删除该成员,然后遍历所有教务员e_all的vector <Class>to_be_review和所有学生s_all的vector<Class>myclass,找到同名的对象并删除

    教务员的:

    展示所有待审核课程void show_need_review(); 遍历该教务员的vector <Class>to_be_review
    通过某一课程的审核void approve_class(Class a); 遍历该教务员的vector <Class>to_be_review,删除名字与对象相同的成员;在全局的c_all中加入这个对象;遍历所有老师的vector <Class>to_be_review,找到相同名字的成员并删除
    将某一课程下架(可以让该课程不再对学生开放)void disapprove_class(Class a); 在所有教务员的vector <Class>to_be_review中加入这个对象,stu_num置为0,表示这个对象需要重新审核;把这个课程对应的老师的vector <Class>have_opened和 vector <Class>to_be_review分别减少和增加一个该对象,stu_num置为0;遍历所有学生的vector<Class>myclass找到同名课程,删除掉

    5.操作完成退出程序
    5 输入与输出进入登陆界面

    5.1 教务员端



    5.2 教师端




    5.3 学生端




    6 心得体会我不提供老师修改课程的函数,如果要修改课程,应该先删除原有课程,然后再新建课程,这样也刚刚好可以给教务员进行批准。
    其实应该把所有的class都放在一个容器里面,这样既节省了空间,又节省了时间,现在搞成这样简直想死,各种改来改去,我都怕了,作了大死啊,真的是写了好久啊,以后一定要先想好怎么写啊啊啊啊啊啊啊啊,气死了,吃力不讨好。
    其实冷静一点就只要在每个函数做一点点的,但是这次真的是气的不行,一开始的设计有问题,导致了事倍功半。
    1 评论 6 下载 2018-11-05 21:54:23 下载需要3点积分
  • 基于C++实现校园卡管理系统

    1 实验目的
    本实验面向 C++语言的初学者
    主要让实验者熟悉面向对象的编程思想以及类的使用

    2 实验环境本实验可基于Visual Studio 或Eclipse 或Devc++平台开发,参考主流的编码规范,如Google C++Style Guide(中文版)
    2.1 编程语言和开发工具
    编程语言: ANSI C++
    开发工具: dev cpp

    2.2 编码规范要求遵循良好的程序设计风格来设计和编写程序。基本编码规范:

    标识符的命名要到达顾名思义的程度
    关键代码提供清晰、准确的注释
    程序版面要求:

    不同功能块用空行分隔一般一个语句一行语句缩进整齐、层次分明

    3 实验内容编写校园卡管理系统,进行对校园卡,储蓄卡的管理和绑定,其中包括新建,消费,转账,查询,存款等操作。
    4 分析与设计简要描述程序设计的过程,包括设计思路,设计要点及特色;程序的不足与改进等。要求画出程序的简单流程图。
    4.1 需求分析校园卡的消费,查询;储蓄卡的消费,转账,查询,其中可转账给其他储蓄卡或者校园卡,可以透支;绑定卡的校园卡可以在无存款时透支储蓄卡上的金额。
    4.2 类结构设计类关系图

    4.3 细节设计数据成员
    class Account{ //流水账类 public: string adress; double amount; long id; long time; bool xaiofei=0; bool zhuanru=0; bool zhuanchu=0; bool cunru=0; };class Card{ //基类 card 类 public: card(){} long id; string name; double overage; int listnum; Account *listarray; virtual void pay(){} virtual void inquire(){} };class Campuscard:public Card{ //继承类校园卡类 public: campuscard(); void pay(string adress, double amount); void inquire(); string school; bool isbinding; long bindid;};class Debitcard:public Card{ //继承类储蓄卡类 public: debitcard(); void pay(string adress,double amount); void inquire(); void transfers1(Debitcard &othercard); void transfers2(Campuscard &othercard); void debit(double amount); int getYear(){ return year; } int getMon(){ return mon; } int getDay(){ return day; } private: long timee; double limit; //透支额度 double moneyed; //已用透支数额 double surplus; //剩余额度 };
    成员函数
    virtual void pay(){} virtual void inquire(){} card(){}campuscard(); void pay(string adress,double amount); void inquire();debitcard(); void pay(string adress,double amount); void inquire(); void transfers1(Debitcard &othercard); void transfers2(Campuscard &othercard); void debit(double amount);
    5 设计心得上课要认真听讲,下来要多练习,然后其实也不太会。其实还是学到了很多,尤其是在不太懂的地方请教别人。本来说用文件输入输出,结果发现自己还是不会,然后就放弃了。感觉看看自己前两个项目又会收获很多。
    6 程序主界面
    1 评论 100 下载 2018-11-05 21:43:13 下载需要5点积分
  • 基于WIN32 API图形界面实现的楼盘管理系统

    1 绪论1.1 课题背景房地产产业是中国最近关注度非常高的一门产业。房地产商需要去管理整个公司的楼盘信息,而用户需要查询对应的楼盘信息,因此制作一个系统来满足双方的需求就显得尤为重要。一个方便的系统能够减少客户四处咨询的时间,同时也方便了公司对房地产的管理。因此,我们需要一个楼盘的管理系统来满足用户的需求。
    1.2 课题研究的目的与意义
    给出了管理和查询的必要功能,可以实现基本的插入、修改、删除功能。方便客户与房地产商的使用
    实现了图形化界面的处理,模仿大部分Windows应用程序的设计思路,使设计更标准化,尽量使用户的体验达到更好

    2 系统整体设计本实验设计的系统为楼盘信息管理系统,功能为管理不同地区的不同楼盘、楼栋、房间的信息。主体功能模块分为五个部分,如图1.1所示。接下来将依次介绍五个主要功能模块。

    2.1 文件模块文件模块主要分为四个部分:数据文件导入、数据保存、退出系统、放弃本次修改,如图1.2所示。具体功能介绍如下:

    2.1.1 保存通过该功能将已经通过系统做的修改、增添和删除保存至磁盘文件。具体实现方法如下:当用户单击菜单中的“保存”时,若磁盘中无对应文件则激活“另存为”,若磁盘中已有对应文件,则直接将修改写入至磁盘对应文件。
    2.1.2 另存为若为“保存”激活,则保存文件至磁盘某一位置;若为直接点击,则为该文件在磁盘上创造一个副本。具体实现方法如下:

    当单击菜单中的“另存为”时(或对未保存至磁盘的文件单击“保存”),将弹出一个Windows中常用的保存窗口,如图2.3所示;
    用户可以通过这个窗口中选择将要保存的位置,以及将要保存的文件形式(目前系统仅支持*.led格式,该格式为自定义的引导文件格式);
    用户若单击取消,则恢复原状。若用户单击确定,则文件保存至磁盘相应目录下。用户可到磁盘中查询到四个文件:一个引导文件Leading Files(*.led),三个数据文件(*.bin),如图2.4所示。其文件名为系统自动确定,不允许用户更改。


    2.1.3 新建新建一个空的文件,供用户进行操作(添加、修改、删除等)。实际操作中可跳过这一步,直接在空的系统中操作后保存。

    2.1.4 导入选择磁盘中的某一个文件(要求为Leading Files(*.led)文件)导入该管理系统,并将文件中的所有数据读入链表,同时在系统的窗口中显示。具体实现方法如下:

    点击导入之后,弹出一个类似于“保存”的窗口。可通过选择文件格式来筛选文件(默认格式为*.led),单击文件表示选择。
    若点击确定,则将该文件下的数据文件导入链表,并在系统中显示第一个楼盘的信息,如图2.5所示。若点击取消,则恢复原状。


    2.1.5 退出退出实现功能与点击右上角的退出按钮相同。首先确认文件是否保存和做过修改。若已修改但未保存,将会弹出窗口提示是否要保存,如图2.6所示,否则直接退出系统。

    2.2 显示模块显示模块不存在于菜单中。为了方便用户浏览信息,实现编辑、统计、添加的同步显示,做到“所见即所得”,本系统设计了显示模块。显示模块允许用户在除菜单外的客户区进行单击、双击操作,同时为其它许多功能的操作提供了便利,带来了良好的用户体验。下面具体描述显示的具体过程。

    当进入系统导入文件之后,显示的是第一级,楼盘与该楼盘下所属的楼栋信息,如图2.7所示;


    单击每一个楼盘,在右上方蓝色信息区会显示该楼盘的具体信息,同时在右下方的列表中显示该楼盘下的所有楼盘。同时信息区右下角的两个按钮“编辑”与“删除”提供的快速删除、编辑当前楼盘的有效路径;
    在2的基础上单击右下角列表中每一个楼栋,在右上方蓝色信息区会显示对应的楼栋信息。同时信息区右下角的两个按钮“编辑”与“删除”提供的快速删除、编辑当前楼栋的有效路径;
    在2的基础上双击右下列表中的楼栋,将可以进入该楼栋,即在右上角显示该楼栋的信息,在右下角显示该楼栋下的所有房间及基本信息。同时信息区右下角的两个按钮“编辑”与“删除”提供的快速删除、编辑当前楼栋的有效路径,如图2.8所示;
    在4的基础上单击右下角列表中的房间,将在右上角蓝色信息区中显示该房间的所有信息,如图2.9所示。同时信息区右下角的两个按钮“编辑”与“删除”提供的快速删除、编辑当前房间的有效路径;
    在4的基础上,单击右下方列表中的第一行楼栋基本信息,将显示该楼栋所有信息,并提供“编辑”与“删除”楼栋功能。双击右下方列表中的第一行楼栋基本信息,将返回上一级,即右下列表中显示该楼盘下所有楼栋信息,右上信息区中显示该楼栋的所有信息。同时信息区右下角的两个按钮“编辑”与“删除”提供的快速删除、编辑当前房间的有效路径;



    2.3 编辑模块编辑模块主要功能为对导入的数据进行编辑。包括更改、增添、删除三大部分,如图2.10所示。每部分的详细内容如下:

    2.3.1 更改功能更改功能又称编辑,可以通过两种方式触发:单击菜单中的“更改”项或在浏览房间/楼栋/楼盘信息之时点击当时所在的房间/楼栋/楼盘信息右下角的编辑按钮。具体实现功能如下:

    通过以上两种方法触发弹出更改功能对话框,如图2.11所示
    对话框会默认将目前所在房间/楼栋/楼盘的信息输入对应的编辑框,允许用户在编辑框上更改相关的数据(有一些编辑框如电话号码不允许输入数字以外的符号)
    若用户点击确定,系统将检查所输入的楼栋号(或房间号、楼盘名)是否与已有数据重复,若重复,则弹出警告,如图2.12所示,要求用户更改所输入的数据。若成功编辑房间,则同时更新该楼盘、楼栋的平均价格,若成功编辑楼盘,则同时更新当前楼盘下的所有楼栋、房间的“所在楼盘”数据。若用户点击取消,则不做更改
    更改完成后,重绘整个客户区,将数据更新。用户可以通过系统显示判断更改是否成功


    2.3.2 添加功能添加功能有分为三大部分:添加楼盘,添加楼栋和添加房间。
    2.3.2.1 添加房间添加房间允许在系统任何的显示状态下进行。当单击菜单中“添加 – 添加房间”时,会弹出对话框。若显示当前信息区显示为楼盘,则会在对话框中自动输入默认楼盘的相关信息;若当前信息区显示为楼栋,则会在对话框中自动输入默认楼栋的相关信息,如图2.13所示。
    在添加房间的对话框中使用了Edit,Static,Combo Box(下拉选择框),Check Box等许多控件。其中下拉选择框中储存了所有的房间类型信息共34条,方便用户选择。
    在输入完毕后,用户若点击确定,则系统会检测是否有重复的房间号,若有则报错,要求用户重新输入信息,则添加成功,用户可在列表框中查看到新添加的房间,或点击查看具体信息;若点击取消,则放弃添加,系统恢复原状。

    2.3.2.2 添加楼栋添加楼栋允许在系统任何的显示状态下进行。当单击菜单中“添加 – 添加楼栋”时,会弹出对话框,且会在对话框中自动输入当前信息区显示楼盘的相关信息,如图2.14所示。
    在输入完毕后,用户若点击确定,则系统会检测是否有重复的房间号,若有则报错,要求用户重新输入信息,若无,则添加成功,用户可在列表框中查看到新添加的楼栋,或点击查看具体信息;若点击取消,则放弃添加,系统恢复原状。

    2.3.2.3 添加楼盘添加楼盘允许在系统任何的显示状态下进行。当单击菜单中“添加 – 添加楼栋”时,会弹出对话框,用户输入需要添加的楼盘即可。
    在输入完毕后,用户若点击确定,则系统会检测是否有重复的楼盘名,若有则报错,要求用户重新输入信息,若无,则添加成功,系统自动按照顺序添加楼盘号,用户可在左边列表中查看到新添加的楼盘名称,或点击查看具体信息;若点击取消,则放弃添加,系统恢复原状。
    2.3.3 删除功能删除功能提供两种操作方式:准确查找删除与快速删除。
    2.3.3.1 准确查找删除该种删除方式在菜单栏中的“删除”中,分为删除楼盘、楼栋和房间三种。
    点击“删除楼盘”时,会弹出对话框,如图2.15。允许选择性地输入楼盘名称或楼盘编号,选择其中一项是,另一项的输入框会变灰色,不允许输入。若点击确定,则直接删除该楼盘;若点击取消,则放弃删除。
    点击“删除楼栋”时,要求选择性地输入所在楼盘名称或楼盘编号,以及准确的楼栋编号。若点击确定,则直接删除该楼栋;若点击取消,则放弃删除。
    点击“删除房间”时,要求选择性地输入所在楼盘名称或楼盘编号、所在楼栋的准确的楼栋编号,以及准确的房间号。若点击确定,则直接删除该房间;若点击取消,则放弃删除。
    2.3.3.2 快速删除考虑到用户很有可能忘记或者记不清准确的编号信息,系统提供快速删除的功能。即用户在浏览楼盘、楼栋或房间的具体信息可以直接对相关结构进行删除。
    具体操作为单击信息栏的删除按钮,系统会自动判断需要删除的是楼栋、楼盘或房间,然后弹出提示框确认是否删除(防止误点),如图2.16所示,若用户点击确认,则删除该结构,若用户点击取消,则放弃删除。


    2.4 查询模块查询模块主要功能体现在菜单中单击“查询”弹出的对话框中,如图2.17所示。查询功能主要分为查询楼盘,查询楼栋,查询房间三个部分,通过对话框中的选择按钮选择将要查询的部分,后面对应的信息栏将会按照选择相应的变灰,即不允许输入。

    选择好将要输入的信息后,用户可以在编辑框、选择框中输入自己所想要搜索的信息,但不要求准确。具体提供的搜索功能见图2.17。
    系统将会录入用户所输入的搜索信息,并根据用户的选择,将用户所输入的信息与系统中的每一个结构进行比对。系统内部会将每一条信息的重要性分配权值,并计算每一个结构与所输入每一条信息的相似度,然后所有信息相似度的加权平均值作为这一个结构与输入信息的相似度。系统会汇总所有的相似度不为0(即至少有一条信息与所输入信息相符)的结构,并按照权值排序作为搜索结果。最终,系统将会将搜素结果按照相似度从高到低在左边列表中输出。若在搜索中输入房间号为1,楼栋号为1,点击确定,则搜索结果如图2.18所示。同时,会在列表的最后加上一条“退出搜索”的按钮。

    显示搜索结果后,用户为了确认是否为自己想要搜索的项目,可以单击左边搜索栏中的每一个搜索结果,其全部信息将会在右边的蓝色信息区中显示。进入搜索状态后,右上信息区会出现一个“进入”按钮,当用户浏览信息后确认是想要的搜索结果时,可以点击“进入”按钮,直接进入当前搜索结果。以房间为例,点击进入后,将会在左边列表中显示楼盘信息,右上信息栏中显示该房间信息,右下列表中显示所在楼盘的所有房间,若点击沁苑11栋201,则显示如图2.19所示。若用户未找到对应的搜索结果,则直接点击“【退出搜索】”,则恢复搜索前的状态不做改变。
    按照输入的搜索结果,不存在房间号为1的房间,因此未找到,但是存在楼栋号为1的房间,因此楼栋为1的房间在最前面显示。同时,由于未勾选“已售出”选项,搜索所有未售出的楼盘,系统会将一些未售出但是楼栋号不是1的房间显示在偏后的位置,供用户查看。

    2.5 统计模块由于可视化Windows程序的特殊性,本程序未在菜单中加入专门的统计栏,而是将统计融入在程序的显示中。包括统计平均价格,统计楼栋所有房间数,楼盘所有房间数、楼栋数,统计已售出、未售出的房间,目前所有的楼盘数,统计平均面积等。
    每次进行数据添加、更改、删除时,系统会自动将所有的相关数据全部更改,并在系统的界面上实时显示。由于楼栋编号为顺序,通过最后的楼盘编号即可了解所有盘数。且通过搜索功能可以达到更加实用和强大的统计功能,例如统计所有未售出的房间,统计所有价格在某一个价格段的房间等。
    2.6 帮助模块由于本系统未设置专门的参考文档,因此只在关于软件中提供版本信息、作者信息等信息。单击菜单中帮助的“关于软件”,即可得到相关信息,如图2.20所示。

    以上即为“楼盘管理系统”的主体功能模块,该功能模块较大的依赖于可视化界面,同时也充分发挥了可视化操作的优势,相较控制台带给用户更好的体验。同时,搜索模块可以通过调整权值分配的计算方法,使之更加的合理,得到的结果更符合用户的需要,此模块还有着很大的发展空间。

    3 数据结构设计3.1 整体数据结构本系统的设计中,内存总体数据结构为十字交叉三级链表,如图3.1所示。

    每一个楼盘、楼栋、房间都作为一个结构体,这些结构体在内存中形成一个三级链表。每个成员成员储存有关的信息,每个结构体的具体设计以及各成员的意义如下:
    //楼盘结构体//功能:储存楼盘相关信息,并可用于构造链表typedef struct _Community { int communityNum; //楼盘号 TCHAR name[100]; //楼盘名 TCHAR address[100]; //楼盘地址 TCHAR phone[30]; //联系电话 int numberOfBuildings; //所有楼栋数 int numberOfRooms; //所有房间数 float avgPrice; //平均价格 Person host; //联系人结构* struct _Community *nextCommunity = NULL; //指向下一个楼盘 struct _Building *buildings = NULL; //指向该楼盘第一个楼栋}Community;
    楼盘结构的每一个成员的具体含义如上述。其中,联系人结构将在后面指出,用于储存联系人的姓名、电话等信息。每个楼盘的唯一标识为楼盘名(name),楼盘名不允许重复。
    3.1.2 楼栋结构//楼栋结构体//功能:储存楼栋相关信息,并可用于构造链表typedef struct _Building { int buildingNum; //楼栋号 int communityNum; //所在楼盘号 int numberOfRooms; //所有房间数 int numberOfFloors; //楼层数 float avgPrice; //平均价格 TCHAR inCom[100]; //所在楼盘名称 Person host; //联系人结构 struct _Building *nextBuilding; //指向下一个楼栋 struct _Room *rooms; //指向该楼栋第一个房间}Building;
    楼栋结构的每一个成员的具体含义如上述。其中,联系人结构将在后面指出,用于储存联系人的姓名、电话等信息。一般而言,楼栋的联系人与楼盘的联系人相同,但是系统也提供单独修改楼栋联系人信息的方法。
    3.1.3 房间结构//房间结构体//功能:储存房间相关信息,并可用于构造链表typedef struct _Room { int roomNum; //房间号 int buildingNum; //所在楼栋号 int communityNum; //所在楼盘号 int floor; //所在楼层 float roomSize; //房间面积(平方米) float roomPrice; //房间价格(人民币元/平方米) long allPrice; //房间总价(人民币元) TCHAR roomType[100]; //户型:室,厅,厕,厨数量 TCHAR inCom[100]; //所在楼盘名 BOOL roomState; //售出状态:0代表未售出,1代表已售出 TCHAR note[1000]; //备注 Person host; //联系人结构 struct _Room *nextRoom; //指向链表中下一个房间}Room;
    房间结构的每一个成员的具体含义如上述。其中,联系人结构将在后面指出,用于储存联系人的姓名、电话等信息。一般而言,楼栋的联系人与楼盘、楼栋的联系人相同,但是系统也提供单独修改房间联系人信息的方法。
    需要说明的是,户型的储存方式为34个字符串代表34种户型,每种户型与每个字符串严格一一对应。这些户型被定义在静态区,户型的信息如下:
    static TCHAR *szComboBoxData[] = { TEXT("户型1:一室一厅一厨一厕"),TEXT("户型18:五室一厅一厨两厕"), TEXT("户型2:两室一厅一厨一厕"),TEXT("户型19:两室两厅两厨一厕"), TEXT("户型3:三室一厅一厨一厕"),TEXT("户型20:三室两厅两厨一厕"), TEXT("户型4:四室一厅一厨一厕"),TEXT("户型21:四室两厅两厨一厕"), TEXT("户型5:五室一厅一厨一厕"),TEXT("户型22:五室两厅两厨一厕"), TEXT("户型6:一室两厅一厨一厕"),TEXT("户型23:两室两厅一厨两厕"), TEXT("户型7:两室两厅一厨一厕"),TEXT("户型24:三室两厅一厨两厕"), TEXT("户型8:三室两厅一厨一厕"),TEXT("户型25:四室两厅一厨两厕"), TEXT("户型9:四室两厅一厨一厕"),TEXT("户型26:五室两厅一厨两厕"), TEXT("户型10:五室两厅一厨一厕"),TEXT("户型27:两室一厅两厨两厕"), TEXT("户型11:两室一厅两厨一厕"),TEXT("户型28:三室一厅两厨两厕"), TEXT("户型12:三室一厅两厨一厕"),TEXT("户型29:四室一厅两厨两厕"), TEXT("户型13:四室一厅两厨一厕"),TEXT("户型30:五室一厅两厨两厕"), TEXT("户型14:五室一厅两厨一厕"),TEXT("户型31:两室两厅两厨两厕"), TEXT("户型15:两室一厅一厨两厕"),TEXT("户型32:三室两厅两厨两厕"), TEXT("户型16:三室一厅一厨两厕"),TEXT("户型33:四室两厅两厨两厕"), TEXT("户型17:四室一厅一厨两厕"),TEXT("户型34:五室两厅两厨两厕"),};
    3.1.4 联系人结构//联系人结构体//功能:用于存储个人信息typedef struct _Person { TCHAR name[100]; //姓名 TCHAR phone[50]; //电话 TCHAR idNumber[50]; //证件ID号}Person;
    联系人结构储存一个人的相关信息,具体成员的含义见注释。
    3.2 辅助链表在搜索功能中,为了搜索的便捷。每找到一个有相关性的结构体,就将其接入一个新的链表,称为搜索链表。该链表为单向先进先出的链表,搜索链表有三类,分为楼盘搜索、楼栋搜索、房间搜索,对应三种不同的链表。将相关数据接入链表中后,将链表排序后输出,即可得到搜索结果。
    3.3 其他结构体3.3.1 引导文件结构体创建引导文件的目的是方便用户导入数据,同时储存相关的信,以供读入内存时使用。因此在引导文件中存储的是一个结构体,储存了其他数据文件的基本信息。引导文件结构如下:
    //*.led文件中的结构体//储存com,bui,room三个文件里面所包含的数据数typedef struct _LenData { int iCom; int iBui; int iRoom;}LenData;
    该文件中存储的为每一种结构体的数量。便于在读取文件重新构建链表的时候顺利的构建与原来相同的链表,结构见表3.2。
    3.3.2 搜索结构体在搜索设计中,系统将读取用户输入的所有数据并将其与每一个结构进行比对。因此,为了方便比对,特意将所有的输入数据读入同一个结构体,该结构具体内容如下:
    //SearchData搜索中使用的结构体,容纳搜索的所有数据typedef struct _SearchData { int mask; //确定搜索的对象 //值为SD_COM,SD_BUI,SD_ROOM中的一个 //Community TCHAR comName[100]; int comNum; TCHAR comPerson[100]; TCHAR comPhone[100]; //Building int buiNum; TCHAR buiPhone[100]; TCHAR buiPerson[100]; //Room int roomNum; int roomFloor; float roomSize; long allPrice; float roomLoPrice; float roomHiPrice; BOOL roomSold; TCHAR roomType[100];}SearchData;
    该结构体分为三个部分,楼盘、楼栋和房间,未输入的信息即为0或\0。第一个成员mask储存搜索的目标,其三个值在头文件“managerSys.h”头文件中定义。使用时,将每一个成员与对应结构比对即可。

    4 系统模块设计与实现4.1 文件模块4.1.1 文件格式4.1.1.1 引导文件引导文件只包含一个引导结构体,包含了所需要的相关信息。
    4.1.1.2 楼盘数据文件楼盘数据文件以楼盘结构为单位储存了所有楼盘的信息。该结构为许多楼盘无间隔相邻顺序储存,每一个单位大小为sizeof(Community)。
    4.1.1.3 楼栋数据文件每一个楼盘中,属于该楼盘的楼栋无间隔相邻顺序储存。不同楼盘的楼栋按照楼盘存储顺序储存,并且每两个楼盘的楼栋之间相隔一个分隔楼栋,该分隔楼栋的楼栋号为-1,其与数据均为空。
    4.1.1.4 房间数据文件每一个楼栋中,属于该楼栋的房间无间隔相邻顺序储存。不同楼栋的房间按照楼盘存储顺序储存,并且每两个楼栋的房间之间相隔一个分隔房间,该分隔房间的房间号为-1,其与数据均为空。
    4.1.2 文件读取文件读取使用的函数为ReadFile函数【1】,这些函数比fread更加功能全面。通过每次在文件中读取一个结构的数据到缓冲区,确定数据全部读取然后将缓冲区写入链表,之后调用SetFilePointer函数【2】移动文件指针到下一个结构,在调用下一个结构写入链表。若遇到文件中的分隔结构,则跳过该结构,将接下来读取的数据写入下一个楼盘(楼栋)。
    整个读取由一个函数来执行,该函数原型如下:
    //FileReadWnd//功能:读取文件//参数:窗口句柄hwnd,路径名//返回:若成功则返回TRUE,失败则返回FALSEBOOL FileReadWnd(HWND hwnd, PTSTR pstrLeadFileName);
    该函数的主要结构为:

    获取文件名;
    编辑数据文件名
    调用CreateFile函数【3】打开引导文件和数据文件,获取文件句柄;
    检查读取是否完整,并拷贝引导文件中的数据;
    将三个文件中的数据写入链表;
    检查数据是否全部读取;
    设置主窗口标题和回收指针、句柄;

    函数参数以及返回值见注释,函数实现代码见附录。
    4.1.3 文件写入文件写入的函数为WriteFile函数【4】,通过按照4.1.1所述的文件结构将链表中的数据写入链表,同时在适当的地方加入分隔结构,便于读取。每次写入文件后,调用SetFilePointer函数将文件指针后移一个结构体,写入新的数据(注意不可简单的将指针移到文件尾)。整个写入过程由一个函数来执行,该函数原型如下:
    /////////////////////////////////////////////////////////FileWriteWnd//功能:写入文件//参数:窗口句柄hwnd,引导文件路径//返回:若成功则返回TRUE,失败则返回FALSEBOOL FileWriteWnd(HWND hwnd, PTSTR pstrLeadFileName);
    该函数的主要结构为:

    获取文件名;
    编辑数据文件名
    调用CreateFile函数【3】打开引导文件和数据文件,获取文件句柄;
    编辑好文件中的分隔结构,并将其与链表中的数据一同按照4.1.1中的文件结构写入相应文件中;
    检查数据是否完全读取并制作引导结构,将其写入引导文件;
    设置主窗口标题和回收指针、句柄;

    函数参数以及返回值见注释,函数实现代码见附录。
    4.1.4 其它文件处理函数【5】其它的文件处理函数用于初始化以及完成一些附属功能,例如FileInitWnd函数、FileImportDlg函数、FileSaveDlg函数等,它们的函数原型如下:
    /////////////////////////////////////////////////////////FileInitWnd//功能:初始化弹出文件窗口的数据//参数:父窗口句柄hwnd//返回:无返回值void FileInitWnd(HWND hwnd);/////////////////////////////////////////////////////////FileImportDlg//功能:创建导入文件对话框//参数:父窗口句柄hwnd,文件名,路径名//返回:若成功则返回TRUE,失败则返回FALSEBOOL FileImportDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName);/////////////////////////////////////////////////////////FileSaveDlg//功能:创建保存文件对话框//参数:窗口句柄hwnd,文件名,路径名//返回:若成功则返回TRUE,失败则返回FALSEBOOL FileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName);
    这些函数的参数以及返回值见注释,函数实现代码见附录。
    4.1.5 主窗口过程中有关文件的消息响应主窗口过程中有关文件的消息主要有WM_COMMAND消息中的消息码为IDM_FILE_SAVE,IDM_FILE_SAVE_AS,IDM_FILE_CREATE,IDM_FILE_IMPORT,IDM_FILE_EXIT五种。不同的消息码对应菜单中的不同项目的ID。在WndProc主窗口过程中,对各个消息码有着分别的处理:
    4.1.5.1 保存(IDM_FILE_SAVE)调用FileWriteWnd函数将现有链表写入文件,若写入失败,则弹出警告。之后修改保存情况。具体操作见2.1.1文件模块功能。
    4.1.5.2 另存为(IDM_FILE_SAVE_AS)调用FileWriteWnd函数,弹出对话框,显示地址。将现有链表写入到一个备份的文件中,若写入失败,则弹出警告。之后修改保存情况具体操作见2.1.2文件模块功能。
    4.1.5.3 新建(IDM_FILE_CREATE)更改主窗口显示的文件名。具体操作见2.1.3文件模块功能。
    4.1.5.4 导入(IDM_FILE_IMPORT)若未保存,提示用户是否需要保存。调用FileImportDlg和FileReadWnd函数,弹出导入对话框,选择导入的文件(具体操作见2.1.4文件模块功能)。之后将所有数据导入链表,并调用InvalidateRect函数【6】无效化整个窗口,重绘相关信息,将信息区显示为第一个楼盘的数据。
    4.1.5.5 退出(IDM_FILE_EXIT)向主窗口发送WM_CLOSE消息。若未保存,则提示用户保存。若已经保存,向主窗口发送WM_DESTROY消息请求关闭。【7】
    4.2 显示模块在头文件“managerSys”显示过程中定义四种显示状态:
    #define PA_FIRSTEPCOM 500 //第一级,显示楼盘信息#define PA_SECSTEPBUI 501 //第二级,显示楼栋信息#define PA_FIRSTEPBUI 502 //第一级,显示楼栋信息#define PA_SECSTEPROOM 503 //第二级,显示房间信息
    4.2.1 显示第一级显示第一级为在左边ListBox【11】中显示楼盘,在右上信息区中显示楼盘或楼栋的具体信息,在右下角ListView【12】中显示相应楼盘下的所有楼栋基本信息。
    此时根据全局变量iPaintState的取值,判断显示的级别。若为显示楼盘信息,则在WM_PAINT消息处理中调用函数Draw1Step与DrawComInf;若显示为楼栋信息,则在WM_PAINT消息处理中调用函数Draw1Step与DrawBuiInf。
    单击左边的ListBox中的项目,则通过LB_SELCHANGE中获取选择项的文本(即为楼盘名),将楼盘名作为信息在整个链表内检索,获取该楼盘的具体信息以及其下的所有楼栋信息。使用TextOut函数在右上信息区中输出相关信息,通过向右下角发送LVS_SETITEMTEXT(或调用函数ListView_SetItemText)将楼栋信息发送到ListView中,从而显示楼盘信息(即为Draw1Step的工作方式)。
    单击右边的楼栋项目,将会将状态设置为PA_FIRSTEPBUI,然后无效化窗口并发送WM_PAINT消息。此时调用函数Draw1Step与DrawBuiInf,此时显示对应楼栋信息。
    双击右边的楼栋项目,将会将状态设置为PA_SECSTEPBUI,然后无效化窗口并发送WM_PAINT消息。此时调用函数Draw2Step与DrawBuiInf,在右边显示楼栋信息以及在列表中列出该楼栋下所有楼盘。
    4.2.2 显示第二级显示第一级为在左边ListBox【11】中显示楼盘,在右上信息区中显示楼栋或房间的具体信息,在右下角ListView【12】中显示相应楼盘下的所有楼栋基本信息。
    此时根据全局变量iPaintState的取值,判断显示的级别。若为显示楼盘信息,则在WM_PAINT消息处理中调用函数Draw1Step与DrawComInf;若显示为楼栋信息,则在WM_PAINT消息处理中调用函数Draw1Step与DrawBuiInf。
    单击左边的ListBox中的项目,则通过LB_SELCHANGE中获取选择项的文本(即为楼盘名),将楼盘名作为信息在整个链表内检索,获取该楼盘的具体信息以及其下的所有楼栋信息。使用TextOut函数在右上信息区中输出相关信息,通过向右下角发送LVS_SETITEMTEXT(或调用函数ListView_SetItemText)将楼栋信息发送到ListView中,从而显示楼盘信息(即为Draw1Step的工作方式)。
    单击右边的房间或楼栋项目,将会将状态设置为PA_SECSTEPBUI或PA_SECSTEPROOM,然后无效化窗口并发送WM_PAINT消息。此时调用函数Draw2Step与DrawBuiInf或DrawRoomInf,此时显示对应楼栋信息或对应房间信息。
    双击右边的列表中第一行楼栋项目,通过读取WM_NOTIFY中的消息获取选中项目,同时将会将状态设置为PA_SECSTEPBUI,然后无效化窗口并发送WM_PAINT消息。此时调用函数Draw1Step与DrawBuiInf,在右边显示楼栋信息以及在列表中列出所在楼盘下的所有楼栋。即实现返回上一级的目的。
    在这两种显示中使用的函数声明如下:
    /////////////////////////////////////////////////////////Draw1Step//功能:WM_PAINT消息中绘制第一级(包含Com与Bui),不显示数据//参数:设备环境hdc,显示数据的com指针//返回:无返回void Draw1Step(HDC hdc, Community *pChosenCom);/////////////////////////////////////////////////////////Draw2Step//功能:WM_PAINT消息中绘制第二级,不显示数据//参数:设备环境hdc,指向所选楼栋的指针//返回:无返回void Draw2Step(HDC hdc, Building *pBui);/////////////////////////////////////////////////////////DrawComInf//功能:绘制楼盘信息窗口//参数:编辑框句柄hwnd,设备环境hdc,Community结构//返回:成功返回TRUE,失败返回FALSEBOOL DrawComInf(HWND hwnd, HDC hdc, Community com);/////////////////////////////////////////////////////////DrawBuiInf//功能:绘制楼栋信息窗口//参数:编辑框句柄hwnd,设备环境hdc,Building结构//返回:成功返回TRUE,失败返回FALSEBOOL DrawBuiInf(HWND hwnd, HDC hdc, Building bui);/////////////////////////////////////////////////////////DrawRoomInf//功能:绘制楼栋信息窗口//参数:编辑框句柄hwnd,设备环境hdc,Room结构//返回:成功返回TRUE,失败返回FALSEBOOL DrawRoomInf(HWND hwnd, HDC hdc, Room room);/////////////////////////////////////////////////////////RenewData//功能:将数据区恢复为背景色//参数:设备环境hdc,Building结构//返回:无返回void RenewData(HDC hdc, RECT rectData);
    4.2.3 显示搜索结果显示搜索结果时,不同于以上的两种显示方式。当搜索点击确定时,整个系统的一个全局变量iSearch将会更改为搜索过程,对该变量取值范围在“managerSys.h”中做出了相关规定:
    #define SEARCHCOM 701#define NOSEARCH 702#define SEARCHBUI 703#define SEARCHROOM 704
    同时,定义处于搜索状态如下:
    #define SEARCHING (iSearch==SEARCHCOM||iSearch==SEARCHBUI||iSearch==SEARCHROOM)
    当处于搜索状态时,WM_PAINT消息中在左边ListBox显示为辅助链表(3.2)pComSearch(或pBuiSearch、pRoomSearch)中的数据,通过不停发送LB_ADDSTRING消息,添加项目,并在最后添加一条【退出搜索】。将左边上放的标题通过SetWindowText设置为“搜索结果”。同时响应其中的单击消息,只调用Draw*Inf函数显示对应信息。
    显示搜索结果未应用特殊的函数,基本通过调用之前的函数即可实现功能。
    4.3 编辑模块4.3.1更改数据更改数据分为两种情况:点击菜单中的更改、点击信息栏的“编辑”。
    在点击菜单中的“更改”时,将会直接发送一条BM_CLICK消息给编辑按钮,相当于制造了一次点击。
    在点击了信息栏中的“编辑”按钮时,保存状态转为False。首先判断当前信息区的状态,即被楼盘、楼栋或是房间占用。根据情况将会弹出相应的对话框,同时,读取信息区的楼栋号(或楼盘名、房间号),遍历链表检索该楼栋(或是楼盘、房间),之后将搜索到楼盘的相关信息通过SetWindowText函数【8】设置为对应信息编辑框的默认值。在用户对信息做出更改后,将检验是否与已在楼盘、楼栋、房间冲突,若不冲突,则将修改的信息录入链表,同时调用UpdateData函数,将链表的所有数据更新,并将其下的所有结构的inCom或buildingNum成员对应修改。无效化窗口,信息区规定显示编辑的信息更新版。
    UpdateData函数为自定义函数,其声明如下:
    /////////////////////////////////////////////////////////UpdataData//功能:更新整个链表的数据,包括房间数,均价等//参数:将要更新的链表的头指针的地址//返回:若完成所有更新则返回TRUE,否则返回FALSEBOOL UpdateData(Community **ppHead);
    4.3.2 添加数据添加数据分为三种情况,添加楼盘、楼栋和房间。
    以添加房间为例。点击添加房间时,WndProc收到WM_COMMAND消息(其wParam为IDM_EDIT_ADD_ROOM),于是会调用DialogBox函数【10】,创建一个对话框。在对话框窗口过程AddRoomDlgProc来获取此时所在的楼栋和楼盘信息,将默认的信息通过SetWindowText函数发送到对话框中。当用户添加完所有数据之后,通过向编辑框发送EM_GETLINE消息,对Combo Box进行GetWindowText函数获取文本,以及选择框发送BM_GETCHECK消息获取选择状态来获取对话框中的所有信息。利用_ttoi,_ttof等函数【9】将所有的信息转化为对应的数据类型,然后储存在一个新建的房间结构体中。判断这个房间的房间号是否与同一楼栋中的房间号冲突,若不冲突,将这个结构体接入链表,否则弹出警告报错。
    接入链表后,无效化整个客户区,并调用UpdateData函数后重绘整个客户区,信息区的为房间的信息。楼盘、楼栋的添加过程与此基本相似,具体流程如图4.1所示。
    参与添加数据的函数共有三个窗口过程,同时有三个辅助函数用于将数据写入链表。具体的函数声明如下:
    /////////////////////////////////////////////////////////“添加新楼盘”(AddCommunity)对话框窗口过程BOOL CALLBACK AddComDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);/////////////////////////////////////////////////////////“添加新楼栋”(AddBuilding)对话框窗口过程BOOL CALLBACK AddBuiDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);

    /////////////////////////////////////////////////////////“添加新房间”(AddRoom)对话框窗口过程BOOL CALLBACK AddRoomDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);/////////////////////////////////////////////////////////AddComToList//功能:向链表中添加一个community节点//参数:将要添加的Community结构体(添加对象链表的头指针.全局变量提供)//返回:返回更新后链表头指针BOOL AddComToList(Community newCom, Community **head);/////////////////////////////////////////////////////////AddBuiToList//功能:向链表中添加一个building节点//参数:将要添加的Building结构体,添加对象链表的头指针,所属楼盘号//返回:成功则返回TRUE,失败返回FALSEBOOL AddBuiToList(Building newBui, Community **head, int comNum);/////////////////////////////////////////////////////////AddRoomToList//功能:向链表中添加一个Room节点//参数:将要添加的Room结构体,添加对象链表的头指针,所属楼盘号,所属楼栋号//返回:成功则返回TRUE,失败返回FALSEBOOL AddRoomToList(Room newRoom, Community **head, int comNum, int buiNum);
    4.3.1 删除数据删除数据分为三种情况:删除楼盘、楼栋和房间。同时系统提供两种删除方式:准确删除与快速删除。下面以以添加房间为例。
    准确删除。点击添加房间时,WndProc收到WM_COMMAND消息(其wParam为IDM_EDIT_DEL_ROOM),于是会调用DialogBox函数【10】,创建一个对话框,要求用户输入对应的准确信息。其中楼盘允许在楼盘号与楼盘名中间进行选择。即在对话框窗口过程DelRoomDlgProc中处理复选框消息时,若用户选择第一个选项,则通过调用EnableWindow函数【10】将第一个窗口有效,第二个窗口无效。当用户添加完所有数据之后,通过判断复选框的选项和向编辑框发送EM_GETLINE消息来获取所有的数据。利用_ttoi,_ttof等函数【9】将所有的信息转化为对应的数据类型,然后遍历链表寻找知否有符合要求的房间。若找到,则直接从链表中删除该房间,若未找到,则弹出MessageBox提示该房间不存在。
    删除链表后,无效化整个客户区,并调用UpdateData函数后重绘整个客户区,信息区的为删除的房间所在的楼栋信息。楼盘、楼栋的添加过程与此基本相似,具体流程如图4.2所示。

    快速删除。快速删除主要体现在在浏览信息时,可以点击信息区右下角的“删除”按钮。此时读取目前所在的房间(或楼栋、楼盘)信息,之后遍历链表搜索该房间。搜索到该房间之后,弹出MessageBox询问用户是否确定删除该房间。若用户点击是,则调用删除函数将该房间从链表中删除。无效化整个窗口并发送WM_PAINT消息重绘窗口。若用户点击否,则不做删除,重绘窗口。
    参与删除数据的函数共有三个窗口过程,同时有三个辅助函数用于将数据从链表中删除。具体的函数声明如下:
    /////////////////////////////////////////////////////////“删除楼盘”(DeleteCommunity)对话框窗口过程BOOL CALLBACK DelComDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);/////////////////////////////////////////////////////////“删除楼盘”(DeleteBui)对话框窗口过程BOOL CALLBACK DelBuiDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);/////////////////////////////////////////////////////////“删除楼盘”(DeleteRoom)对话框窗口过程BOOL CALLBACK DelRoomDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);/////////////////////////////////////////////////////////DelComInList//功能:删除链表中的一个Community节点//参数:将要删除的Community编号,添加对象链表的头指针的地址//返回:返回更新后链表头指针BOOL DelComInList(int comNum, Community **head);/////////////////////////////////////////////////////////DelBuiInList//功能:删除链表中的一个Building节点//参数:将要删除的Building编号,添加对象链表的头指针的地址//返回:返回更新后链表头指针BOOL DelBuiInList(int comNum,int buiNum, Community **head);/////////////////////////////////////////////////////////DelRoomInList//功能:删除链表中的一个Room节点//参数:将要删除的Room编号,添加对象链表的头指针的地址//返回:返回更新后链表头指针BOOL DelRoomInList(int comNum, int buiNum, int roomNum, Community **head);
    4.4 查询模块查询模块为弹出对话框,之后读取用户输入的信息,通过相关搜索函数将每一项的相似度与对应结构进行比较。(详见2.2显示模块)具体的实现过程如图4.3所示。

    搜索结构所显示的排序方式以及原理在2.2显示模块中都有详细的介绍,搜索过程中显示的函数原型如下:
    /////////////////////////////////////////////////////////计算出每一个楼栋的相似度//参数:标准SearchData结构,对比的楼栋,该楼栋所在楼盘//返回:这个输入信息与该楼栋的相似度int GetBuiSim(SearchData data, Community com, Building bui);/////////////////////////////////////////////////////////计算出每一个房间的相似度//参数:标准SearchData结构,对比的房间,该房间所在楼栋、楼盘//返回:这个输入信息与该房间的相似度int GetRoomSim(SearchData data, Community com, Building bui, Room room);/////////////////////////////////////////////////////////“搜索功能”(Search)对话框窗口过程BOOL CALLBACK SearchDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);/////////////////////////////////////////////////////////对Com链表按照权重进行排序//参数:标准比较输入数据,排序的链表头指针//返回:返回为排完序的链表的头指针Community *RankCom(SearchData sData, Community *pComSearch);/////////////////////////////////////////////////////////对Bui链表按照权重进行排序//参数:标准比较输入数据,排序的链表头指针//返回:返回为排完序的链表的头指针Building *RankBui(SearchData sData, Building *pBuiSearch);/////////////////////////////////////////////////////////AddBuiToSearch//功能:创建一个只由bui组成的search//参数:将要添加的Building结构体,添加对象链表的头指针//返回:成功则返回TRUE,失败返回FALSEBOOL AddBuiToSearch(Building newCom, Building **head);/////////////////////////////////////////////////////////对Room链表按照权重进行排序//参数:标准比较输入数据,排序的链表头指针//返回:返回为排完序的链表的头指针Room *RankRoom(SearchData sData, Room *pBuiSearch);/////////////////////////////////////////////////////////计算出每一个楼盘的相似度//参数:标准SearchData结构,对比的楼盘//返回:这个输入信息与该楼盘的相似度int GetComSim(SearchData data, Community com);
    5.5 统计模块统计模块的主要体现在数据的更新与实现上,由于统计模块并无专门的菜单项,因此统计功能融入其它的模块中。
    统计中最重要的函数为更新数据,功能为遍历链表,将楼栋数、房间数、平均价格计算并写入对应的结构体。函数原型如下:
    /////////////////////////////////////////////////////////UpdataData//功能:更新整个链表的数据,包括房间数,均价等//参数:将要更新的链表的头指针的地址//返回:若完成所有更新则返回TRUE,否则返回FALSEBOOL UpdateData(Community **ppHead);
    5.6 帮助模块由于本软件界面较为简单,操作简洁,无需准备无帮助文档,帮助功能仅提供关于软件功能。即弹出对话框显示软件的基本信息,该对话框在资源中定义一些Static控件即可。
    1 评论 6 下载 2018-11-05 21:37:12 下载需要5点积分
  • 基于VC++的MFC类库实现的池塘夜降彩色雨程序

    1 题目1.1 问题描述设计一个程序,演示美丽的“池塘夜雨”景色:色彩缤纷的雨点飘飘洒洒地从天而降,滴滴入水有声,溅起圈圈微澜。
    1.2 基本要求
    雨点的空中出现位置、降落过程的可见程度、入水位置、颜色、最大水圈等等,都是随机确定的
    多个雨点按照各自的随机参数和存在状态,同时演示在屏幕上

    2 开发环境
    硬件:PC机
    软件:Microsoft Visual Studio 2010

    3 题目需求分析根据题目可知需要设计一个程序,程序运行后,有美丽的池塘夜晚景象,天空飘着彩色的雨,落在池塘时有涟漪产生。而雨点的空中出现位置、入水位置、颜色、最大水圈等等,都是随机确定的。画面中有按钮可以控制雨点数,雨点速度等参数,为了能在画出雨点下落的同时能响应窗口的控件的事件,则需要使用新的线程来画下落的雨点。下落的雨点数可以增减,则需要使用双向的链表来保存雨点的各种状态信息(坐标、大小、角度、涟漪半径等)。每次生成雨点,都在指定的范围内随机出相应的数据,然后每次画完一帧雨点,自增雨点的坐标值或涟漪半径。
    4 概要设计4.1 数据类型的定义//雨点类型定义typedef struct{ COLORREF color;//雨点颜色 int x,y;//初始坐标 int len;//雨点大小 float angle;//雨点角度 int speed;//落下速度 int thick;//雨点粗细 int radius;//涟漪半径}droplet;//雨点类型//雨的双向链表定义struct dropletchain{ droplet *data;//数据域 struct dropletchain *pre,*next;//指针域};
    4.2 主程序的流程
    4.3 各模块之间的调用关系
    5 详细设计5.1 主程序和其他模块的伪码算法// 线程函数; 强制转换wParam为当前窗口实例的指针->绘图方法static UINT onThread(LPVOID wParam)//初始化雨点;随机雨点各个参数void initDroplet(droplet *droplet)// 获取画布void doThread()// 画背景->读取链表->判断雨点是否到达底部并画雨点或涟漪->自增雨点的坐标或涟漪的半径->sleep延迟 while(1)// 退出按钮的实现afx_msg void OnBnClickedButton1()// 暂停按钮afx_msg void OnBnClickedButton2()// 雨点数控制按钮afx_msg void OnDeltaposSpin(NMHDR *pNMHDR, LRESULT *pResult)if 增加雨点数 在链表尾部添加雨点->把尾部指针指向新结点->初始化新的雨点else if 雨点数剩下一滴 弹出窗口警告 else 删除尾部指向的结点->把尾部指针指向前一个结点// 雨点速度滑动条;修改窗口成员变量延迟时间的值afx_msg void OnReleasedcaptureSlider(NMHDR *pNMHDR, LRESULT *pResult)
    6 调试分析6.1 调试过程遇到的问题及解决
    问题:雨点的涟漪使用画圆弧的方法画出来时会带有一根奇怪的线

    解决方法:通过画圆圈的方法画出来,但是却是实心的圆,然后还需要设置内画笔为NULL才可以画空心的圆
    问题: 雨点下落及产生涟漪时,经常会跑到画布之外的地方

    解决方法:在产生的涟漪自增其半径后,计算下次绘制涟漪时最大的范围是否会超过画布的范围,若超过了则重新“生成”雨点
    问题:静态线程内不能操作窗口

    解决方法:使用适配的方法,把窗口的实例指针传到线程中然后通过新的线程来执行原来实例中的绘图方法即可
    问题:初始雨点太少,雨点太短太粗不好看,颜色也太少,还有背景颜色不协调等

    解决方法:修改初始雨点数,雨点线条长度,在电脑的画图里调配颜色再找到比较合适的颜色,修改到最终差不多看着比较协调了

    6.2 经验和体会由于VS没有TC中的graphics.h这个图形库,上网查了下,可以使用C++的MFC完成图形的绘制及实现题目要求的下雨的景象,由于没接触过MFC,因而由此简单了解了其使用方法及一些简单的按钮实现功能。经过这个课程设计,大致了解Windows的消息处理机制,Visual Studio的Debug使用。
    7 用户使用说明运行程序,可以看到程序的界面如图所示:

    点击雨点数上边的按钮,可以增加雨点数

    点击雨点数下边的按钮,可以减少雨点数,当雨点数为1时,出现提示,不能继续减少


    雨点速度滑动条可以控制雨下落的速度,向右则变快,向左则变慢

    点击暂停按钮,则整个画面暂停,按钮名称变为“恢复”

    点击恢复按钮,则画面开始继续下雨,按钮名称变为“暂停”

    点击退出按钮,则退出程序,需重新运行程序才能开始下雨
    1 评论 13 下载 2018-11-05 20:57:18 下载需要10点积分
  • 基于C#实现的RPG角色扮演类小游戏

    1 需求分析1.1 游戏概述DragonQuest是一个角色扮演类游戏(RPG),该游戏实现的具体功能是设计两种类型的人物,分别为被玩家所控制的玩家人物(Hero)和由系统所控制的外部人物(Enemy),游戏中的主要情节就是Hero与 Enemy之间的战斗,双方互相发射子弹击打对方。
    在游戏的设计中要求游戏具有良好的扩展性,游戏界面友好,应方便用户,游戏画面要尽可能直观、美观。
    游戏角色参考图片:
    玩家人物—Hero

    敌人1—EnemyBoss

    敌人2—EnemyOne

    敌人3—EnemyTwo

    敌人4—EnemyThree

    游戏战斗场面

    1.2 需求描述本游戏名为“DragonQuest”游戏,基本可以实现以下功能:

    开始游戏
    退出(分保存进度设置和不保存进度设置两种)
    属性设置(开始的时候,对各属性值进行初始化操作)
    清除玩家信息,保存进度

    对人物,环境的要求如下:

    人物:游戏中分为两种角色,Hero和 Enemy,两者都有对应的生命值,在所有的Enemy之中,有一个EnemyBoss,他在Enemy之中是最厉害的角色,该游戏中,Hero和EnemyBoss各只有一个,但是其他的Enemy可以有很多个,双方在战斗的过程中,双方的生命值会减少,当EnemyBoss的生命值为0时,游戏胜利,当Hero的生命值为0时,战斗失败,游戏结束
    环境:由于游戏规模的限制,游戏中环境的设置比较单一,整个游戏只在一个环境中进行
    人物移动:Enemy人物的移动是随机的,每隔一段时间,移动到一个地方,Hero的移动由玩家控制
    人物遭遇战:在游戏过程中,Hero和 Enemy相互发射子弹,当子弹打到某个角色时,对应的角色的生命值就会降低,直到生命值为0,该角色死亡

    此游戏分为用户和管理员:
    用户的主要操作:

    未注册之前的准备<注册游戏,创建账户>
    注册之后:

    登陆自己的账号,填写密码等信息,读取游戏进度开始游戏退出游戏保存进度

    管理员的主要操作:

    管理注册游戏的玩家信息
    删除不保存的用户的信息,只保存相应的用户名

    1.3 功能需求本游戏的主要功能有:

    开始游戏
    退出(分保存进度设置和不保存进度设置两种)
    属性设置(开始的时候,对各属性值进行初始化操作)
    清除玩家信息,在各地各种环境下保存进度

    1.4 性能需求所有操作都应在30ms内得到响应。本游戏主要运行在Windows平台上,但以后有可能会扩展到其他平台,服务器数据库选用Mysql。
    1.5 运行需求游戏中界面以客户端程序的方式显示,界面能做到简洁,美观,大方,与用户交互友好 。若程序中有微小的错误从而导致游戏的死机,请将信息及时汇报给我们,以便于我们及时的进行修改并完善。
    用户忘记账号或者密码,可以通过游戏的说明书上的联系电话来联系管理员,根据注册的数据来判断账号的所属者,从而为用户提供服务。
    用户不能运行游戏,则可能是用户的电脑配置太低不适合游戏,可更换电脑的配置来满足游戏所运行环境下的条件。
    网络不通,排除故障后需要重新进入系统,系统不保存在用户进行游戏前的临时数据。
    在游戏过程中服务器死机,可在重启服务器后再统计一次即可。但不保存上次的临时数据。
    1.6 其他需求对该软件的灵活性的要求,即当需求发生某些变化时,该游戏应该能应对如下变化,如:

    操作方式上的变化
    运行环境的变化
    精度和有效时限的变化
    计划的变化或改进

    二、游戏中角色的层次框架
    三、DragonQuest的设计主要包含了以下几种设计模式
    单件模式
    工厂方法模式
    策略模式
    观察者模式
    外观模式
    代理模式

    四、游戏设计中的模式的详细说明4.1 单件模式4.1.1 设计说明游戏中由于角色,元素比较多,在DragonQuest游戏中设计了一个HitCheck类,该类负责控制游戏中所有元素(角色),包括对角色的增加,删除和控制其各种行为,该类在整个游戏中只有一个实例,这里就可以用到单件模式,如果该类可以被实例化多次,那么游戏就会相当混乱,整个游戏就会失去控制,所以该类只能有一个实例,并且该类提供了一个全局的访问点。
    该类利用一个私有静态变量来记录HitCheck类的唯一实例
    私有构造函数private HitCheck()确保该类在类外是无法实例化的,只能在类内进行实例化。利用静态方法GetInstance()实例化对象,并返回这个实例。
    4.1.2 类图
    4.1.3 单件模式的实现代码public class HitCheck{ private static volatile HitCheck instance;//记录该类唯一的实例 private HitCheck() { }//私有构造函数 public static HitCheck GetInstance()//实例化对象 { if (instance == null) { instance = new HitCheck(); } return instance; }}
    4.2 工厂方法模式4.2.1 设计说明游戏中涉及角色较多,每个角色都有自己的子弹,这样就可以用到工厂方法模式,这会使系统具有良好的扩展性和可维护性,达到一种松耦合的目的,以便将代码从具体类解耦,游戏中有两个抽象类Roles和Missiles分别作为工厂的接口和产品的接口,在Roles中有一个抽象工厂方法Fire(),实例化子弹的任务被移动到这个方法中,此方法就如同是一个“工厂”。Roles并不决定要实例化的类,而是由子类(Hero,EnemyOne,EnemyTwo…)来决定要实例化的类.抽象类Missiles的子类MissileHero,MissileOne,MissileTwo是由“工厂”(Hero,EnemyOne,EnemyTwo…)来实例化的,比如Hero是负责实例化MissileHero的,EnemyOne是负责实例化MissileOne的,EnemyTwo是负责实例化MissileTwo的。这样就可以让把实例化推迟到子类。
    这个设计模式中运用到的设计原则有:依赖抽象,不要依赖具体的类。
    4.2.2 类 图
    4.2.3 工厂模式的实现代码生产子弹的创建者类
    public abstract class Roles{ //属性 public abstract void Fire();//用来生产子弹,实例化子弹的任务被移到一个方法中,此方法就如同是一个工厂方法 //其他的方法}
    生产具体子弹的工厂
    public class Hero : Roles{ //英雄类中的Fire()产生MissileHero public override void Fire() { }}public class EnemyOne : Roles{ // EnemyOne类中的Fire()产生MissileOne public override void Fire() { }}public class EnemyTwo : Roles{ // EnemyTwo类中的Fire()产生MissileTwo public override void Fire() { }}
    子弹的抽象类
    public abstract class Missiles{ protected override void Move(){} protected void Draw(Graphics g){}}
    具体的子弹
    //Hero的子弹public class MissileHero : Missiles{}// EnemyOne的子弹public class MissileOne : Missiles{}// EnemyTwo的子弹public class MissileTwo : Missiles{}
    4.3 策略模式4.3.1 设计说明上面讨论了每个角色都有自己的子弹,但是考虑到每个角色产生子弹的方式又是不一样的,我们可以设计不同的子弹产生方式,比如,Hero在某些时候可以一次产生一个子弹,但是当敌人比较多的时候,可以一次产生两个子弹,或者更多,敌人也是一样的,也可以一次产生多个子弹,达到增强战斗力的效果,这里就可以采用策略模式来设计每个角色产生子弹的行为。设计了一个接口ShotBehavior来封装发射子弹的行为,然后可以定义不同的行为,接着,在Roles类中加入一个实例变量shotBehaviro,声明为接口类型,每个角色都会动态的设置这些变量以在运行时引用正确的行为类型,同一个角色可以采用不同的行为,实现不同的策略,并通过SetShotBehavior()来动态的改变发射子弹的行为。这样算法的变化就独立于使用算法的类了。这使得系统具有良好的扩展性和可维护性
    这个设计模式中运用到的设计原则有:

    封装变化
    依赖抽象,不要依赖具体类
    针对接口编程,不针对实现编程

    4.3.2 类图
    4.3.3 策略模式的实现代码 public abstract class Roles { protected ShotBehaviro shotBehavior;//行为变量被声明为行为”接口”类型 public abstract void Fire(); //动态设置不同的行为 public void SetShotBehavior(ShotBehaviro newShotBehavior) { shotBehavior= newShotBehavior; } } public class Hero : Roles { public Hero() { shotBehavior=new ShotThreeMissileHero(); } public override void Fire() { shotBehavior.Shot(); } } //这个接口用来封装发射子弹的行为 public interface ShotBehavior { public void Shot(); } public class ShotOneMissileHero:ShotBehavior { //一次发射一个子弹 public void Shot() { HitCheck.GetInstance().AddElement(new MissileHero()); } } public class ShotTwoMissileHero : ShotBehavior { //一次发射两个子弹 public void Shot() { HitCheck.GetInstance().AddElement(new MissileHero()); HitCheck.GetInstance().AddElement(new MissileHero()); } } public class ShotThreeMissileHero : ShotBehavior { //一次发射三个子弹 public void Shot() { HitCheck.GetInstance().AddElement(new MissileHero()); HitCheck.GetInstance().AddElement(new MissileHero()); HitCheck.GetInstance().AddElement(new MissileHero()); } }
    4.4 观察者模式4.4.1 设计说明游戏中由于HitCheck控制所有角色,所以游戏中的角色都要通过他来添加到游戏中,这样这些角色就成为了观察者了,然后由HitCheck去通知所有添加的观察者,这里就可以用到观察者模式,游戏中设计了一个所有类的父类Element,他有一个方法Draw(),所有的角色都实现了抽象类Element的Draw()方法,在游戏主程序中,当游戏状态改变时,都需要调用Draw()方法,以便更新自己最新的状态,所以,当游戏中的状态发生改变的时候,HitCheck类就会通知所有向他注册的观察者(调用观察者的Draw()方法),这样HitCheck不知道观察者的细节,只知道所有的观察者都实现了一个公共的接口(Draw),从而实现了观察者与可观察者之间的松耦合。
    这个模式中用到的设计原则有:为交互对象之间的松耦合设计而努力。
    4.4.2 类图
    4.4.3 观察者模式的实现代码public class HitCheck{ //记录观察者 private Hero myHero = null; private List<MissileHero> missileHero = new List<MissileHero>(); private List<Roles> enemy = new List<Roles>(); private List<Missiles> enemyMissile = new List<Missiles>(); private List<Element> bombs = new List<Element>(); //添加观察者 public void AddElement(Element el) { if (el is Hero) { myHero = (Hero)el; return; } if (el is MissileHero) { missileHero.Add((MissileHero)el); return; } //剩下的几种角色类型的操作与上面的一样,这里就省略不写了 } //删除观察者 public void RemoveElement(Element el) { if (el is MissileHero) { missileHero.Remove((MissileHero)el); return; } if (el is Roles) { enemy.Remove((Roles)el); return; } //剩下的几种角色类型的操作与上面的一样,这里就省略不写了 } //通知观察者,让所有观察者调用Draw()方法画自己 public void Draw(Graphics g) { //画自己(Hero) myHero.Draw(g); //画自己的子弹 for (int i = 0; i < missileHero.Count; i++) { missileHero[i].Draw(g); } //剩下的几种角色类型的操作与上面的一样,这里就省略不写了 } }
    4.5 外观模式4.5.1 设计说明由于游戏中使用了许多资源,在游戏结束的时候,要清理这些资源,最直接的方法就是针对每一种资源分别清理,即分别调用资源的Dispose()方法,在资源还不多的时候,可能还没有什么影响,但是如果系统资源多了,这样效率明显就降低了,如果把这些组件整合成一个统一的接口,就可以解决问题了,这里我们就可以用到了外观模式了,FrmMain_FormClosing()提供了一个简单的接口,负责清理一切资源,其中,每项任务都是委托子系统中相应的组件处理的,现在我们在游戏结束的时候,只需要使用简化的接口FrmMain_FormClosing()就可以了,他提供了一个统一的接口,用来访问子系统中的一群接口,让子系统更容易使用。
    这里运用到的设计原则有:最少知识原则,即只和你的密友谈话。
    4.5.2 类图
    外观模式的实现代码
    public partial class FrmMain{ //以下是我们用到的子系统组件 public static Bitmap backgroundImg; private Bitmap bufferImg = null; private Graphics gImg = null; Thread pt = null; //游戏结束,释放所有资源 private void Closing(object sender, FormClosingEventArgs e) { bufferImg.Dispose(); gImg.Dispose(); backgroundImg.Dispose(); }}
    4.6 代理模式4.6.1 设计说明游戏中,在设计BloodBar的时候,BloodBar是不能单独存在的,BloodBar是需要绑定一个角色存在的,他是角色的生命值的体现,在游戏中,单独对BloodBar的访问是没有意义的,游戏中也不能直接对BloodBar进行访问,对BloodBar的访问受到了控制,只能通过相应的角色去访问BloodBar,这就可以用到代理模式,游戏中的Hero就是BloodBar的代理(代表),他控制着外界对BloodBar的访问,当外界需要访问BloodBar时,被Hero拦截下来,由Hero去处理相应的请求,Hero对BloodBar提供了某些级别的保护,保证了外界不能直接去访问BloodBar,只有通过Hero才可以去访问Hero,通过Hero去访问BloodBar这个过程对外界来说是透明的,外界觉得是直接访问BloodBar的,这样,Hero对BloodBar就起到了一种代理的作用,保护了BloodBar。
    4.6.2 类图
    4.6.3 代理模式的实现代码public abstract class Element{ public abstract void Draw(Graphics g);}public class BloodBar : Element{ public override void Draw(System.Drawing.Graphics g) { g.DrawString(); g.DrawRectangle(); g.FillRectangle(); }}public class Hero : Element{ //Hero中持有BloodBar的引用,负责对它的访问控制,使得外界不能直接对BloodBar进行访问 public BloodBar bloodBar = null; public Hero() { bloodBar= new BloodBar();//实例化BloodBar } public override void Draw(System.Drawing.Graphics g) { //在该方法中实现对bloodBar的访问控制 bloodBar.NowLife = life;//设置其生命值 bloodBar.Draw(g); }}
    1 评论 52 下载 2018-11-05 20:48:57 下载需要5点积分
  • 基于EasyX实现的Flappy Bird小游戏

    一、设计目的
    掌握定义函数,并熟练使用各函数
    实现各函数模块的调用
    学会将静态库导入工程,熟练使用库函数
    掌握使用graphics.h的IMAG的数据类型
    学会调用API
    学会编写合适的算法来解决问题

    二、设计内容为了更好地掌握各数据类型、数据结构的使用以及C语言程序设计的思想,以C语言平日课堂知识为主,复刻了前几年在移动端很火的一款游戏Flappy bird。
    成品Flappy bird截图如下:
    游戏开始

    游戏画面

    游戏结束

    三、概要设计3.1 功能模块图
    3.2 各个模块详细的功能描述Custom Function list 自定义函数
    void print();void begin();//载入music、背景、First stonevoid printstone();void bird();//控制鸟的下降和上升void judgement();void scoleprint();void endorretry();
    使用到的头文件和lib
    #include <graphics.h>#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <time.h>#include <windows.h>#include "mmsystem.h"#include WINMM.lib (VC6.0自带的静态库)
    四、详细设计首先,需要安装EasyX图形库,将.exe呈现出更好的图形界面,然后,利用graphics.h绘制图像。
    熟悉graphics头文件中的各种库函数,比如
    initgraph(); // 界面初始化circle(); // 画圆RGB(); // 颜色设置IMAGE // 定义IMAGE对象closegraphics(); // 关闭绘图界面等等
    还需要寻找一些库函数,识别键盘的敲击,比如while(!kbhit())等等。熟悉相关库函数后,开始本次flappy bird程序编写。
    实现思路如下所示:

    背景图片的显示
    加入小鸟图片
    小鸟自由下落,按键后上升
    加入静态的障碍物
    障碍物向左移动
    判断小鸟和障碍物的碰撞
    障碍物移动出左边界后,在右边重新出现
    加入记分模块
    加入开始界面、结束界面
    加入背景音乐

    分阶段编写实现上述10个模块。
    首先,由于我需要设置图形界面,所以调用了VC6.0里头对窗口句柄属性操作的函数,实现对窗口句柄属性的修改,这里由于游戏简单,仅修改了窗口名字,下面贴代码:
    // 获取窗口句柄HWND hwnd = GetHWnd();// 设置窗口标题文字SetWindowText(hwnd, "大峰子的Flappy bird!");
    而后便是游戏窗口的设置,这里为了尽最大限度地复刻移动端,给玩家带来熟悉的感觉,我初始化成了350X600,大概是6寸的手机屏幕大小。这一步的实现是:
    initgraph(350,600);
    之后,需明确游戏的两个对象,鸟,管道;
    由于小鸟的属性本质是取其需打印位置的左上角坐标(X’, Y’),然后通过库函数
    loadimage();putimage();
    将准备好的图片素材输出到该位置上,这样小鸟就呈现在了屏幕上,所以我们需要定义两个全局变量bird_x、bird_y去实现存储小鸟坐标的功能。
    之前提到,本游戏主要是基于C语言graphics.h中各类绘图库函数实现的,所以要定义IMAGE对象,代码说话:
    IMAGE background, bird1[4], bird2[4], scole1[10], scole2[10], stone_up1, stone_up2, stone_down1, stone_down2, stone_up3, stone_up4, stone_down3, stone_down4;
    以便于后面的loadimage和putimage这一系列操作。
    随后,便是各个功能模块的技术实现了,我简述一下我的技术实现:
    背景图片的显示。这个比较简单,定左上角为(0,0)点,只要使用函数putimage()就能实现该模块
    加入小鸟图片。首先我们观察游戏会发现,该游戏中小鸟只会上下移动,并不会左右移动,造成小鸟向前飞的错觉是管道相对于小鸟的相对位移造成的,因此,我们只需要putimage到(150,300)即屏幕中央偏左的位置即可。另外,这里有一个小技术实现,就是三光栅操作,使得位图能透明显示。其原理是XOR,即异步运算,掩码图XOR精灵图=能透明显示到背景图上的位图。
    举个例子:


    黑XOR黑=原颜色。通过XOR运算将两张图像先后重叠打印,就能够实现图像的显示而不造成图像闪烁现象。
    加入静态的障碍物管道。这个原理与2是一致的。不再过度阐述。
    开始时播放背景音乐。这里需要调用媒体播放API,双线程进行,不然就会造成“播放.wav时控制台黑屏”的现象。这里用到的是头文件windows.h下的库函数Playsound,下面贴代码:
    PlaySound("000.wav", NULL, SND_FILENAME | SND_ASYNC|SND_LOOP);
    通过这段代码,实现多线程、循环播放。此外实现该功能需要添加WINMM.lib到project当中。
    加入封面、结束界面。封面的加入较为简单,制作一个350X600的图片,在开始时putimage,并利用getch函数实现停顿直至键盘输入。结束界面的“GAME OVER”图像,显示方法如上述描述的一样,不再过多阐述。
    小鸟的自动下落,键盘输入空格or鼠标左键时上升。首先,自动下落可以通过循环解决,每一次循环都进行一次按键检测 if(kbhit()),若按下空格键or鼠标左键,bird_y减小,小鸟图像打印时将上移,造成一种小鸟向上飞跃的感觉,若没有按按键,则bird_y+=3,缓慢下降。
    障碍物向左移动。这个操作是在自定义函数printstone中实现的。关键点在于游戏一开始时柱子的初始化、柱子的随机长度、及柱子移动到屏幕左边框后右侧柱子重新出现…这三种情况的技术实现。
    柱子的随机长度怎么设置呢?需要用rand函数,其位于stdlib.h中,用rand()%310-550,将得到的数值赋给上方的柱子坐标stone_y,保持x不变,y-750,就得到了下柱子的位置坐标,再putimage()即可。
    为了让每一次游戏时管道间的间距位置都不一致,我使用了srand随机种子,由于随机种子函数值决定了rand()得到的数字序列,所以可以利用时间的多样性实现随机种子的多样性,下面贴代码:
    srand( (unsigned)time( NULL ) );
    这样每次rand();得到的数字都是不定的,达到伪随机的效果。
    如何实现柱子的左移呢?在printstone中添加stone_x— 这一行,这样每次while循环就能实现柱子的左移。
    如何才能在一开始游戏时只出现一个柱子呢?需把stone_x2赋一个极小值,让putimage();到350*600的屏幕之外即可。
    同理,每次循环检测柱子坐标变量stone_x的值是否等于0,等于0的话,将stone_x重新赋值为350即可。
    碰撞判断模块。我自定义了一个judgement();进行判断,如果鸟和管道的素材重叠,就判断游戏失败了,执行endorretry();。由于我的bird图像素材是34X24,所以区间就是stone_y+-24,同时要考虑管道的素材是140*600,首先考虑碰撞上界,上界即是与上管道重叠,因此有以下代码实现:
    if((stone_x1>10 && stone_x1<20)||(stone_x1>174&&stone_x1<184))if((bird_y>(stone_y1+576)&&bird_y<(stone_y1+600))||((bird_y>(stone_y1+726))&&bird_y<(stone_y1+750)))
    同时,掉出下界也需要判断,下界分为与下管道重叠,与窗口下边缘重叠,所以有了以下的代码实现:
    else if(stone_x1>=20 && stone_x1<=174)if(!(bird_y>(stone_y1+600)&&bird_y<(stone_y1+726)))if(bird_y>576) // 判断结果为ture后,即进入endorretry();或者main while(1)主循环
    计分模块。当stone_x==150时,scole++,即柱子过屏幕一半的位置时,默认小鸟通过了柱子。当碰撞后,初始化,即执行endorretry();,scole=0,计分归零。
    暂停模块。比较简单,键盘检测鼠标右键、Esc键,即在bird函数中检测键盘输入是否等于27(ASCII码对应Esc键),或者是否等于’ ’(对应空格),然后再使用getch();函数停顿即可。
    游戏失败后的初始化模块。当 judgement();中判断成功并进入endorretry();,将打印Game Over图像并初始化。技术实现上,需要消除图像闪烁问题,这里需要用到BeginBatchDraw();和EndBatchDraw();批量绘图函数来消除Sleep();函数造成的闪烁问题。
    功能函数的调用关系图
    各功能函数的数据流程图
    五、测试数据及运行结果


    六、调试情况,设计技巧及体会6.1 调试改进像素小鸟翅膀的扇动

    改进办法:当bird_y上升/下降时,利用IMAGE数组控制输出不同类型的图案。
    像素小鸟位移感严重,跳跃不顺畅
    改进办法:按键检测到空格键or鼠标左键时,将bird_y-=80调整至bird_y-=40,减小相对位移的长度。
    柱子移动偏慢
    改进办法:多设置一个难度模块,通过改变柱子移动速度达到难度的改变,例如定义全局变量n,将stone_x—修改为stone_x=stone_x-n,然后通过scanf(“%d”,&n);去控制每次循环时柱子向左移动的位移即可。
    缺乏最高分模块,记录玩家最高分
    改进办法:后续加入该模块。
    6.2 体会通过这次C语言课程设计,让我很好地掌握了C语言数据类型的使用,学会了用结构化、模块化的思想去编写程序,增强程序的健壮性,可读性,同时增强了对于添加并引用lib的熟练度,让程序功能更好地达到目的。同时增强了个人对计算机、程序编写的自信心,有利于未来的职业发展,衷心地感谢任课老师的指导与栽培。
    1 评论 20 下载 2018-11-05 18:53:55 下载需要8点积分
  • 基于J2EE技术和MVC框架的Android手机安全卫士APP设计与实现

    1 目标伴随智能手机的不断普及,移动互联网的快速发展,伴随着3G时代的到来,智能手机的广泛应用,手机安全问题被越发关注。系统的主要功能在于防止外来的骚扰和便于内部的管理,就外来而言我们实现了对黑名单号码的电话和短信屏蔽,而对内而言,用户通过安全卫士软件可以便捷地对手机进行监控和管理,如一键关闭后台,流量监控等,最终实现还用户一个清净安全的手机使用体验。
    2 总体功能概述
    定义主界面的图标和图标下相关文字,并可以自动联网进行检查更新,也就是说可以完成与服务器的交互,并不单一只是本地化单机软件
    可导入手机自带联系人信息,并可以将联系人设置黑名单或白名单处理,黑名单下的联系人来电可自动挂断
    黑名单下的联系人的短信拦截,拦截后短信不再显示在收件箱里,转而显示在“手机卫士”相关功能下
    程序锁功能,程序锁上锁的软件只可通过输入正确的密匙才可打开运行,否则无法打开,保护手机拥有者的个人隐私
    后台程序清理和管理功能,清理后台运行的不必要的进程,以节省内存
    流量管理模块,在用户设置了流量套餐后,对用户手机流量进行实时监控,并在相应时间做出流量预警,以提醒使用者

    3 整体软件构架设计
    软件对象:安全卫士主要是对面用户,开发人员,数据库三者的一个全面的系统,其中包括,用户使用系统进行日常的手机保护和使用,而开发人员进行系统的更新和维护,数据库进行黑名单数据存储和通讯录、电话号码归属地等相关信息的存储
    系统功能设计:安全卫士包含了号码归属地查询,流量监控,应用程序管理,防骚扰,黑名单管理等功能,其中应用程序管理就有分为程序锁,一键关闭后台,程序分享等子功能。同时开发人员还承担了对软件进行维护更新的指责

    4 技术体系设计我们将使用Eclipse完成代码的编写,利用J2EE技术架构完成Java部分的结构搭建。
    Java 编程语言是个简单、面向对象、分布式、解释性、健壮、安全与系统无关、可移植、高性能、多线程和动态的语言。Java是功能完善的通用程序设计语言,可以用来开发可靠的、要求严格的应用程序。
    MVC(Model View Controller):整体项目采用MVC框架进行设计和开发,一种软件设计典范,用一种业务逻辑和数据显式分离的方法组织代码,将业务逻辑被聚集到一个部件里面,在界面和用户围绕数据的交互能被改进和个性化定制的同时而不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。
    SQLite数据库: SQLite是一个非常流行的嵌入式数据库,它的SQL界面非常简洁,内存占用少,速度快。对于Android,SQLite已经“融入”到Android运行时,因此所有Android应用程序都可以创建SQLite数据库。由于SQLite使用SQL界面,对于有基于其他SQL数据库使用经验的用户而言,它的使用非常简单直接。
    5 数据结构设计数据库中主要存储黑名单数据,通讯录信息,应用程序状态信息,号码归属地这四项信息,详情见后面的数据详细设计。
    5.1 软件系统构架图
    5.2 构件图


    5.3 部署图
    5.4 流程图总流程图

    黑名单流程图

    检查更新流程图

    软件管理流程图

    手机防盗流程图

    6 详细设计6.1 主界面用户界面

    时序图

    类图

    用户界面

    6.2 检查更新用户界面

    时序图

    类图

    6.3 手机防盗用户界面

    时序图

    类图

    6.4 流量管理用户界面

    时序图

    类图

    6.5 应用程序缓存管理用户界面

    类图

    6.6 程序管理用户界面

    时序图

    类图

    6.7 程序锁用户界面

    类图

    6.8 进程管理用户界面

    类图

    6.9 电话归属地用户界面

    时序图

    类图

    6.10 通讯管理用户界面

    时序图

    类图

    7 系统数据结构设计7.1 逻辑结构设计要点7.2 用户信息表(user)用户(用户编号,用户账号,密码,头像,性别,地址,电话,Email,注册时间)



    序号
    字段含义
    类型
    长度
    默认值
    允许空
    主键
    说明




    1
    用户编号
    int
    11
    1


    自动递增


    2
    用户账号
    varcher
    32






    3
    密码
    char
    18






    4
    头像
    varchar
    32






    5
    性别
    varchar
    2
    1





    6
    地址
    varchar
    255






    7
    电话
    varchar
    20






    8
    Email
    varchar
    50






    9
    注册时间
    datatim
    32






    7.3 来电归属地表(from)电话归属地(电话号码,来电次数,来电归属)



    序号
    字段含义
    类型
    长度
    默认值
    允许空
    主键
    说明




    1
    电话号码
    int
    20






    2
    来电次数
    Int
    100






    3
    来电归属
    char
    40






    7.4 程序管理表(program)程序(程序名,目前状态,描述,具体信息)



    序号
    字段含义
    类型
    长度
    默认值
    允许空
    主键
    说明




    1
    程序名
    varcher
    11
    1





    2
    目前状态
    varcher
    32






    3
    描述
    varcher
    18






    4
    具体信息
    varchar
    32






    7.5 流量管理表(rate)流量(套餐含有,实际使用,日期,日均使用,实际与设定差值)



    序号
    字段含义
    类型
    长度
    默认值
    允许空
    主键
    说明




    1
    套餐含有
    int
    100
    0





    2
    实际使用
    Int
    100






    3
    日期
    Datetime
    40






    4
    日均使用
    Int
    100






    5
    差值
    Int
    100
    1





    7.6 用户黑名单表(usr_blist)用户黑名单(编号,加入时间,加入的号码)



    序号
    字段含义
    类型
    长度
    默认值
    允许空
    主键
    说明




    1
    编号
    int
    11
    1


    自动递增


    2
    加入时间
    varcher
    32






    3
    加入号码
    Int
    18






    7.7 产品评论表(goods_comment)评论表(编号,用户账号,商品编号,星级,评论时间,状态,评论内容)



    序号
    字段含义
    类型
    长度
    默认值
    允许空
    主键
    说明




    1
    编号
    int
    11
    1


    自动递增


    2
    用户账号
    varcher
    32






    3
    产品编号
    char
    18






    4
    星级
    varchar
    32






    5
    评论时间
    varchar
    40






    6
    状态
    varchar
    255






    7
    评论内容
    varchar
    20






    码归属地的ER图

    黑名单服务的ER图

    7.8 数据库的逻辑结构设计逻辑结构设计的任务
    数据库逻辑设计的任务是将概念模型转换成特定的DBMS所支持的数据模型的过程。从E-R图所表示的概念模型可以转换成任何一种具体的DBMS所支持的数据模型,这里只介绍E-R图如何向关系模型进行转换,一般的逻辑结构设计分为一下三步,如图所示。

    逻辑结构设计的模式
    概念设计中得到的E-R图由实体、属性和联系组成的,而关系数据库逻辑设计的结果是一组关系模式的集合。所以将E-R图转换成关系模型实际上就是将实体、属性和联系转换成关系模式。转换要遵循以下原则。
    一个实体转换为一个关系模式,实体的属性就是关系的属性,实体的键就是关系的键。
    一个联系转换成一个关系模式,与该联系相连的各实体的键以及联系的属性均转换为该 关系的属性。该关系的键有三种情况:

    如果联系为1:1,则每个实体的键都是关系的候选键
    如果联系为1:m,则n端实体的键是关系的键
    如来联系为n:m,则各实体键的组合是关系的键

    7.9 数据结构与程序的关系数据结构为关系型数据库,所以在程序中可以用标准的SQL语句与数据结构进行交互,交互过程中采用通用的数据反问接口。为了保持良好的程序架构,对数据库访问采用DAO设计模式实现,提高维护性和扩张性。
    1 评论 6 下载 2018-11-05 18:44:09 下载需要20点积分
显示 720 到 735 ,共 15 条
eject