2017年软件工程团体项目

小组成员:(组长:刘炜;组员:黄智、何保委、刘少帅、吕智勇)

源代码链接:https://github.com/superwales/Random_test

项目功能点:(10个基本功能+1个附件功能)

1,拥有多个默认标签,用户可以进行交叉选择。例如:操作符标签为:“连乘”、“连加”,数据标签为:“整数”、“真分数”等;

2,各个标签的交叉选择具有冲突检测功能,提示用户或者自动修正;

3,用户可以自定义添加或者删除标签;

4,用户可以自定义题目长度,操作符类型及个数(或比例),数据类型及取值范围等信息来自定义出题;

5,建立用户的自定义题库,可以查询、统计、删除、清空;

6,更改错题本为收藏夹,用户可以自由选择题目收藏;

7,可以判断用户错题的错误类型;

8,显示错题的解题步骤;

9,练习模式添加解题提示功能;

10,能够用折线图、柱状图、饼图等可视化方式显示用户做题记录。

附件功能:程序界面支持多种语言。

在确定了功能需求后,我们首先进行了分工,秉持每人都能得到锻炼的原则,组内按照功能点进行了分工:

功能点1、2、3、4、5、附加功能:刘炜

功能点7、10:黄智

功能点9:何保委

功能点6:刘少帅

功能点8:吕智勇

本次项目在刘炜、刘少帅的第二次作业基础上修改展开。

part1:刘炜

功能1:拥有多个默认标签,用户可以交叉选择

首先是设计的工作。一道四则运算的题,题目里面会包含运算符、操作数、有无括号等元素。那么考虑从这三个方面设计标签。运算符的不同体现在类型上,因为数量和顺序是随机生成的。运算符总共有“+”,“-”,“×”,“÷”四种,可以设计一道题拥有一种类型的运算符,有四种情况;两种类型的运算符,情况有6种情况......操作数的不同体现在类型(整数、真分数)和运算范围上,因此可以设计类型标签,让用户手动输入运算范围;括号影响了运算顺序,考虑到小学运算的复杂性,将括号数量的上限设定为1。

将此功能添加到原程序的随机练习模式中,界面如图:

     

功能2:各个标签的交叉选择具有冲突检测功能,提示用户或自动修正

为了避免用户在交叉选择中选择自相矛盾的标签,所有的类型标签都设置为单选。但是在题目工厂中,当指定一个操作符并要求包含括号时,会提示用户。

功能3:用户可以自定义标签。

这个功能后来转变成程序自动记忆用户的设置。出题需要选择的标签比较多,如果用户每一次使用都要进行选择,无疑会使使用相当繁琐。因此记忆用户的选择,在下次登录时自动恢复成上次的设置是很有必要的。截图不能展示这个功能,简单介绍一下设计原理。在用户注册的时候,将生成一个设置文件,里面是默认的设置。在用户退出界面的时候,当前选择会修改进入设置文件中。下次登录时,读取设置文件中的设置就行了。

功能4,:用户可以自定义题目长度,操作符类型及个数,数据类型及取值范围等信息来自定义出题。

首先是界面设计:

当点击开始出题时,首先会根据上面的操作符的类型及数量得到一个操作符列表,出题时从这些列表中随机挑操作符就好了。如果有括号的话,将操作符随机分成两部分,一部分在括号内,另一部分在括号外,然后随机选择位置插入括号就好了。

核心代码:

def getdiyoperators(list):
    operators = random.choice(list)
    list.remove(operators)
    if operators == '×':
        length = 2
    elif operators == '÷':
        length = 2
    else:
        length = 1
    return operators, length,list

def getdiyquestion(list,numstr,ran,brastr):
    if brastr=="":
        question = ''
        questionstack = []
        ans = 0
        length_ques = 0

        for i in range(1, len(list) + 1):
            (op, va, de) = getlabeloperands(numstr, ran)
            operands = op
            value = va
            (operators, length, list1) = getdiyoperators(list)
            list = list1
            question = question + operands + operators
            questionstack.append(value)
            questionstack.append(operators)
            length_ques = length_ques + length + de
        (op, va, de) = getlabeloperands(numstr, ran)
        operands = op
        value = va
        question = question + operands
        questionstack.append(value)
        length_ques = length_ques + de
        # print question
        # print questionstack
        condition = 0
        while len(questionstack) > 1:
            for i in range(0, len(questionstack)):
                if questionstack[i] == '×':
                    questionstack[i - 1] = questionstack[i - 1] * questionstack[i + 1]
                    del questionstack[i]
                    del questionstack[i]
                    break
                elif questionstack[i] == '÷':
                    questionstack[i - 1] = questionstack[i - 1] / questionstack[i + 1]
                    del questionstack[i]
                    del questionstack[i]
                    break
                else:
                    condition = 1
            if condition == 1:
                if len(questionstack) > 1:
                    questionstack[0] = calculate(questionstack[0], questionstack[2], questionstack[1])
                    del questionstack[1]
                    del questionstack[1]
                    # print question
                    # print questionstack
        else:
            ans = questionstack[0]
    elif brastr=="":
        n1=random.randint(1,len(list)-1)
        n2=len(list)-n1
        n3=random.randint(1,n2)
        list_in=[]
        for i in range(1,n1+1):
            kop=random.choice(list)
            list_in.append(kop)
            list.remove(kop)

        question = ''
        questionstack = []
        ans = 0
        length_ques = 0

        for i in range(1, n2 + 1):
            if i==n3:
                (op,va,de)=getdiyquestionbylist(list_in,numstr,ran)
                operands = op
                value = va
                (operators, length, list1) = getdiyoperators(list)
                list = list1
                question = question + '('+operands+')' + operators
                questionstack.append(value)
                questionstack.append(operators)
                length_ques = length_ques + length + de
            else:
                (op, va, de) = getlabeloperands(numstr, ran)
                operands = op
                value = va
                (operators, length, list1) = getdiyoperators(list)
                list = list1
                question = question + operands + operators
                questionstack.append(value)
                questionstack.append(operators)
                length_ques = length_ques + length + de
        (op, va, de) = getlabeloperands(numstr, ran)
        operands = op
        value = va
        question = question + operands
        questionstack.append(value)
        length_ques = length_ques + de
        # print question
        # print questionstack
        condition = 0
        while len(questionstack) > 1:
            for i in range(0, len(questionstack)):
                if questionstack[i] == '×':
                    questionstack[i - 1] = questionstack[i - 1] * questionstack[i + 1]
                    del questionstack[i]
                    del questionstack[i]
                    break
                elif questionstack[i] == '÷':
                    questionstack[i - 1] = questionstack[i - 1] / questionstack[i + 1]
                    del questionstack[i]
                    del questionstack[i]
                    break
                else:
                    condition = 1
            if condition == 1:
                if len(questionstack) > 1:
                    questionstack[0] = calculate(questionstack[0], questionstack[2], questionstack[1])
                    del questionstack[1]
                    del questionstack[1]
                    # print question
                    # print questionstack
        else:
            ans = questionstack[0]
    return question, ans, length_ques

功能5:建立用户的自定义题库。

界面就是功能4中的题目工厂,选择添加就能将所选题目添加到收藏夹。

附加功能:

支持多语言,显然不能把所有的语言的都写死在程序中,这样不仅麻烦,而且没有任何的可扩展性。参考了其他同学的作业后,发展出了一个思路:把所有的文本写在一个文本文件中,文本文件按照语言类型命名。在登录界面可以添加一个输入框和一个语言设置按钮,当点击按钮时,程序会找到以输入框的文字命名的文件,读取其中的内容,如果读取错误,就调用简体中文包。

比如:chinese文件:

english文件:

 当不做选择时,界面是简体中文:

 当设置为英语时:

 当前的程序没有做在登录界面添加输入和按钮,是通过改变全局变量实现的,用户不可控制。

 part2:黄智

Github链接:https://github.com/hz5612777/Calculator_task3

1 分配任务

  在这次5人团队任务中,我的任务是可以判断用户的错题类型,并且使软件实现能够用折线图、柱状图、饼状图等可视化方式显示用户做题记录。

2 解题思路

我的任务在有用户做题数据的情况下,画出三种类型的图不难,难点在于用户错题类型的分类。用户的错题到底属于哪种类型,单单从答案是很难获得的。我想从用户对该题的答题时间进行判断。

我们团队根据每题的操作数和运算符设定了一个难度系数,在完成正确的答题后得到每题的做题时间,我将这些难度系数和做题时间作为训练集,采用线性回归的方法训练出模型参数,当系统再次获得一个难度系数的时候,则根据这个难度系数得到相应的预测时间,当用户做错题时,如果用户的做题时间在基于预测时间设定的时间范围以内,则判定为用户会做本题但是做错了,如果在时间范围以外,则认为用户不会计算本题。

用于训练的线性回归模型可以表示为:

根据训练集得到的参数值,然后输入难度系数可以得到每题的预测时间。

3 设计实现

根据线性回归模型,利用训练集拟合出来的曲线如图所示:

利用matplotlib包,可以完成柱状图、折线图和饼状图的画图,我设计了三个QT的graphicsview控件,当用户单击显示做题记录的按钮,三个控件分别显示三种作图信息。

  由于当用户做题记录只有一天的时候无法绘制折线图,所以这是提示无法绘制折线图,单击图中的退出按钮完成该界面的退出。

 part3:何保委

功能:练习模式添加解题提示功能(逐步显示)


思路:
求解计算结果用后缀表达式,显示解题过程用中缀表达式。


方法:
①将字符串格式的运算表达式用函数middle_to_after由中缀表达式转换成后缀表达式,存储在列表 expression
具体转换方法是遇到数字,直接输出;遇到左括号,直接忽略;遇到符号,将符号压入栈,遇到右括号则弹出栈中的符号。
②将字符串格式的运算表达式用函数用split函数分解成列表形式存储 存储在列表 expression1
③调用求解函数expression_to_value 将后缀表达式expression和中缀表达式expression1作为实参传递
④利用函数expression_to_value求解出每一步后缀表达式的结果,
同时将计算结果赋值给中缀表达式,删除中缀表达式中已经参与运算的数字和字符,用字符串格式打印
在每一步计算结果后遍历中缀表达式,若括号内有且只有一个数字,则删除()。
⑤重复上述步骤①到④,直到求解出结果。

 part4:刘少帅

一)功能目的

更改错题本为收藏夹,用户可以自由选择题目收藏。

(二)解决思路

原来的“错题本”功能是如果某道题目做错,则该题自动添加到错题本中,比较被动。本功能是在错题本功能基础上添加“收藏夹”功能,用户可以根据自己需要将觉得有收藏价值的题目(不论这道题是做错还是做对)主动添加到收藏夹中。

(三)实现方法

1.增加“添加”按钮,并设置好其在界面中的位置;

2.定义“Add”函数,目的是调用该函数时,会将某道题添加到“收藏夹”中;

3.将“添加”按钮与“Add”函数绑定。当点击“添加”按钮时,“Add”函数被调用,某道题会添加到“收藏夹”中。

(四)测试情况

1.测试内容

区分四种情况进行测试:

情况一:题目回答正确,不点击“添加”按钮;

情况二:题目回答错误,不点击“添加”按钮;

情况三:题目回答正确,点击“添加”按钮;

情况四:题目回答错误,点击“添加”按钮。

2.测试结果

在情况一、二下,收藏夹中没有收藏相应的题目;在情况三、四下,收藏夹中收藏了相应的题目。

经测试,能够稳定实现“用户自由选择题目收藏”的功能。

项目小结:

本次团体作业可谓是相当敏捷。总结这学期的软件工程课,最大的收获倒不是掌握了软件设计的某些流程方法,反而是了解了一种新的编程语言——python。这是一个有趣的事情,我认为也恰恰反映了软件工程的必要性。很多的东西,比如代码复审、回归测试等,都是编程的新手容易不重视的,然而这学期编程的经验告诉我,最开始不注重代码规范、单元测试等问题,到后面可能得用更多的时间和精力去填自己挖下的坑。团体项目的最后时间,我陷入了一种状态,感觉这个程序,总有可以修改的地方,总有需要改进的地方,总有不尽如人意的地方。现在回头检查,发现确实很多地方做的不好,但是这种感觉很奇妙。

原文地址:https://www.cnblogs.com/seven-v13/p/8400599.html