首页 > 其他 > 详细

结对项目-自动生成小学四则运算题目的命令行程序

时间:2020-04-01 22:58:57      阅读:101      评论:0      收藏:0      [点我收藏+]

一. github

github 地址:https://github.com/DongDGT/ArithmeticGenerator

项目成员:吴宗东,3118005112;林涛,3118005100

二 .psp

 

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

60

 

· Estimate

· 估计这个任务需要多少时间

 20

 

Development

开发

 1570

 

· Analysis

· 需求分析 (包括学习新技术)

 20

 

· Design Spec

· 生成设计文档

 30

 

· Design Review

· 设计复审 (和同事审核设计文档)

 10

 

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 10

 

· Design

· 具体设计

 180

 

· Coding

· 具体编码

 1200

 

· Code Review

· 代码复审

 20

 

· Test

· 测试(自我测试,修改代码,提交修改)

 100

 

Reporting

报告

 120

 

· Test Report

· 测试报告

 60

 

· Size Measurement

· 计算工作量

 10

 

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 30

 

合计

 

1730

 

三.效能分析

技术分享图片

 

 

 可以看出文件的打开和关闭占用了非常多的资源,设置生成10000道题只生成6000多道题目用了2分钟多而且还暂停了,所以对此做了一些改进

改进之后

技术分享图片

 

 

 技术分享图片

 

 

 改进之后生成10000道题目只花了0.63秒

尝试一下生成10万道题目

技术分享图片

 

 

 技术分享图片

 

 

 

四.代码设计过程

1.使用语言:C语言

2.解题思路:

  (1):对每个算式进行拆分,将各个操作数和操作符独立开来。各个操作数和操作符按照特定的顺序排列,再加上答案,组成算式。

  (2):需求分析使用message参数获取。

  (3):括号随机插入算式中,算式在输出的时候再转化为字符串。

  (4):对于判重,没有做到题目中将的那样,只好将之简化,不允许生成答案一样的题目,这样就避免了生成题目重复的问题。

3.项目文件结构ArithmeticGenerrator

├── .vscode            
├── Answers .txt     // 存放答案文件
├── Exercises.txt                // 存放题目文件
├── Debug 
├──  Release
├── main.cpp

├──main.h

4.函数之间的关系

技术分享图片

 

 

 

五.代码说明

消息处理

 

 1 //消息处理,topnum为题目的数量,numrange为数值的范围
 2 bool MessageProcess(int *topnum ,int *numrange ,int messageCount ,char *message[]){
 3     *topnum = 10;  //设题目数量的默认值为10
 4     if(messageCount == 5 && strcmp(message[1], "-r")==0 && strcmp(message[3],"-n") == 0){
 5         if(StrToInt(numrange ,message[2]) == false|| (StrToInt(topnum, message[4]) == false)) return false;
 6     }
 7     else if(messageCount == 5 && strcmp(message[1], "-n")==0 && strcmp(message[2],"-r") == 0){
 8         if(StrToInt(topnum ,message[2]) == false|| (StrToInt(numrange, message[4]) == false)) return false;
 9     }
10     else if(messageCount == 3&&strcmp(message[1], "-r")==0 ){
11         if(StrToInt(numrange ,message[2]) == false) return false;
12     }
13     else    return false;
14     return true;
15 }

 

算式生成

 1 //随机算式生成,输出生成的算式,算式由数个算数单元组成
 2 int RandomArithmetic(arithmeticAtom* arithmetic,int length,int range) {
 3     int countRandom;
 4     countRandom = RandomNum(3)+1;
 5     //
 6 
 7     int i = 0,n=0;
 8     while (i < countRandom+1) {
 9 
10         //生成分数或整数
11         //1按整数生成
12         if (RandomNum(2)) {
13             arithmetic[n].arithmeticData.num = RandomNum(range+1);
14             arithmetic[n].type = dataType::NUM;
15             n++;
16         }
17         /****************************************************************/
18         //0为按分数生成
19         else {
20             arithmetic[n].arithmeticData.fraction.denominator = RandomNum(range)+1;
21             arithmetic[n].arithmeticData.fraction.molecule = RandomNum(arithmetic[n].arithmeticData.fraction.denominator);
22             //若随机的分子为0,转化为整数
23             if (arithmetic[n].arithmeticData.fraction.molecule == 0){
24                 arithmetic[n].arithmeticData.num = 0;
25                 arithmetic[n].type = dataType::NUM;
26             }
27             else {
28                 arithmetic[n].type = dataType::FRACTION;
29                 SimplifyFraction(&arithmetic[n]);
30             }
31             n++;
32         }
33         /**************************************************************/
34         //生成运算符
35         if (i + 1 < countRandom+1) {
36             arithmetic[n].arithmeticData.oper = RandomOper();
37             arithmetic[n++].type = dataType::OPER;
38         }
39         i++;
40     }
41 
42     //判断算式是否结束
43     arithmetic[n].arithmeticData.oper = \0;
44     arithmetic[n].type = dataType::OPER;
45     //插入括号
46     BracketsRandom(countRandom, arithmetic, length,&n);
47 
48     return n;
49 }
 1 void AtomToString(char* string,arithmeticAtom* atom,int atomLength) {
 2     int a = 0, b = 0, c = 0;
 3     int i = 0,j = 0;
 4     /*i:atom[i] ,j:strin 12+4 atom[0].data.num=12->"12"g[j]*/
 5     /*arithmeticData*/
 6     /* denominator:分母*/
 7     /*molecule:分子*/
 8     while(i < atomLength){
 9         if(atom[i].type == NUM){//atom[i]整数
10             a = atom[i].arithmeticData.num;
11             AddString(a, string, &j);//从string[j]把整数a传入
12         }
13         else if(atom[i].type == FRACTION){
14             a = atom[i].arithmeticData.fraction.molecule;
15             b = atom[i].arithmeticData.fraction.denominator;
16             if (a > b) {
17                 c = (a / b);
18                 a -= b * c;
19                 AddString(c, string, &j);
20                 string[j++] = \‘;
21             }
22             AddString(a, string, &j);
23             string[j++] = |;
24             AddString(b, string, &j);
25         }
26         else if(atom[i].type == OPER){
27             string[j++] = atom[i].arithmeticData.oper;
28         }
29         else{
30             printf("TO-STRING-ERROR");
31         }
32         string[j++] =  ;
33         i++;
34     }
35     string[j++] = \0;
36 }

判断算式是否满足题目条件

//计算算式答案及该算式是否可用
bool Calculation(arithmetic *arith) {
    bool isRight = true;
    std::stack<arithmeticAtom> numStack, operStack;
    arithmeticAtom answer ,a,b;
    answer.type = NUM;
    answer.arithmeticData.num = 0;
     for (int i = 0; i < arith->length&&isRight; i++) {
        if (arith->a[i].type != dataType::OPER) {
            numStack.push(arith->a[i]);
        }
        else if (arith->a[i].arithmeticData.oper == (|| operStack.empty()) {
            operStack.push(arith->a[i]);
        }
        else if(arith->a[i].arithmeticData.oper == )){
            while (operStack.top().arithmeticData.oper != ( && isRight) {
                b = numStack.top();
                numStack.pop();
                a = numStack.top();
                numStack.pop();
                switch (operStack.top().arithmeticData.oper)
                {
                case +:
                    isRight = Addition(&answer, a, b);
                    break;
                case -:
                    isRight = Subtraction(&answer, a, b);
                    break;
                case *:
                    isRight = Multiplication(&answer, a, b);
                    break;
                case /:
                    isRight = Division(&answer, a, b);
                    break;
                default:
                    break;
                };
                numStack.push(answer);
                operStack.pop();
            }
            operStack.pop();
        }
        else if((arith->a[i].arithmeticData.oper==*|| arith->a[i].arithmeticData.oper== /)&&
            (operStack.top().arithmeticData.oper == + || operStack.top().arithmeticData.oper == -)){
            operStack.push(arith->a[i]);
        }
        else {
            while (!operStack.empty() &&
                (((arith->a[i].arithmeticData.oper == + || arith->a[i].arithmeticData.oper == -) &&
                    operStack.top().arithmeticData.oper != () ||
                ((arith->a[i].arithmeticData.oper == * || arith->a[i].arithmeticData.oper == /) &&
                    (operStack.top().arithmeticData.oper == / || operStack.top().arithmeticData.oper == /))
                    &&isRight)) {
                b = numStack.top();
                numStack.pop();
                a = numStack.top();
                numStack.pop();
                switch (operStack.top().arithmeticData.oper)
                {
                case +:
                    isRight = Addition(&answer, a, b);
                    break;
                case -:
                    isRight = Subtraction(&answer, a, b);
                    break;
                case *:
                    isRight = Multiplication(&answer, a, b);
                    break;
                case /:
                    isRight = Division(&answer, a, b);
                    break;
                default:
                    break;
                };
                numStack.push(answer);
                operStack.pop();
            }
            operStack.push(arith->a[i]);
        }
    }

    while (!operStack.empty()&&isRight) {
        b = numStack.top();
        numStack.pop();
        a = numStack.top();
        numStack.pop();
        switch (operStack.top().arithmeticData.oper)
        {
        case +:
            isRight = Addition(&answer, a, b);
            break;
        case -:
            isRight = Subtraction(&answer, a, b);
            break;
        case *:
            isRight = Multiplication(&answer, a, b);
            break;
        case /:
            isRight = Division(&answer, a, b);
            break;
        default:
            break;
        };
        numStack.push(answer);
        operStack.pop();
    }
    arith->answer = answer;
    
    return isRight;
}

判断答案是否重复

//判断是否重复****
bool IsNotRepeat(arithmetic arith, arithmeticAtom* repeat,int nownum) {
    int t = nownum - 1;
    while(t >= 0){
        if(arith.answer.type == repeat[t].type){
                //如果当前题目答案的类型与之前的相同
            if(arith.answer.type == NUM){
                        //如果都为整数
                if(arith.answer.arithmeticData.num == repeat[t].arithmeticData.num){
                    return false;
                }
            }
            else if(arith.answer.type == FRACTION){
                         //如果都为分数
                if(arith.answer.arithmeticData.fraction.molecule == repeat[t].arithmeticData.fraction.molecule &&
                arith.answer.arithmeticData.fraction.denominator == repeat[t].arithmeticData.fraction.denominator)
                    return false;
            }
        }
        t--;
    }
        //如果答案不重复,则将这个答案插入到答案数组后面
    repeat[nownum].type = arith.answer.type;
    if(repeat[nownum].type == NUM){
        repeat[nownum].arithmeticData.num = arith.answer.arithmeticData.num;
    }
    else if(repeat[nownum].type == FRACTION){
        repeat[nownum].arithmeticData.fraction.molecule = arith.answer.arithmeticData.fraction.molecule;
        repeat[nownum].arithmeticData.fraction.denominator = arith.answer.arithmeticData.fraction.denominator;
    }
    return true;
}
                                                       

 

文本输出

 

 1 //文件输出Exercises.txt Answers.txt
 2 void fileCreate(int i, arithmetic arith, FILE* q, FILE* an) {
 3     char string[QUESTIONLENGTH],count[QUESTIONCOUNT],answer[ANSWERLENGTH];
 4     int j=0,k=1;
 5     if (q == NULL || an == NULL)
 6         return;
 7     i++;
 8     //形成当前题号
 9     AddString(i, count, &j);
10     count[j] = \0;
11     
12     //输出题目
13     AtomToString(string, arith.a, arith.length);
14     fputs(count, q);
15     fputs(" . ", q);
16     fputs(string, q);
17     fputs("= ", q);
18     fputc(\n, q);
19 
20     //输出答案
21     AtomToString(answer, &(arith.answer), k);
22     fputs(count, an);
23     fputs(" . ", an);
24     fputs(answer, an);
25     fputc(\n, an);
26 }

 

主函数

int main(int messageCount ,char *message[]){
    srand(time(NULL));
    int topnum,numrange;
    arithmetic a;
    arithmeticAtom* repeat;
    //消息处理
    if (!MessageProcess(&topnum, &numrange, messageCount, message)) {
        for (int i = 0; i < messageCount+1; i++) {
            printf("%s\n", message[i]);
        }
        return 0;
    }
    //开辟重复判重数组
    repeat = (arithmeticAtom*)malloc(sizeof(arithmeticAtom) * topnum);
    FILE* q, *an;
    fopen_s(&q, QUESTION, "a");
    fopen_s(&an, ANSWER, "a");
    for (int i = 0; i < topnum; ) {
        a.length=RandomArithmetic(a.a, ALENGTH, numrange);//随机生成一个算式
        if (Calculation(&a) && IsNotRepeat(a,repeat,i)) {//当该算式可用且不重复
            fileCreate(i, a, q, an);//输出算式及答案
            i++;
        }
        else;
    }
    free(repeat);
    fclose(q);
    fclose(an);
    return 0;
}

数据结构

 1 enum dataType {
 2     NUM,OPER,FRACTION
 3 };
 4 struct arithmeticAtom {
 5     dataType type;//单元类型
 6     union {
 7         int num;//整数
 8         char oper;//运算符或括号
 9         struct {
10             int denominator;//分母
11             int molecule;//分子
12         }fraction;//分数
13     }arithmeticData;
14 };
15 struct arithmetic {//算式
16     arithmeticAtom a[ALENGTH];//算式主体
17     int length;//算式长度
18     arithmeticAtom answer;//算式答案
19 };

六 . 功能测试

生成10000道题目,数值范围为0~99

技术分享图片

 

。。。

 

技术分享图片

 

 经过反复检查,生成的题目和答案都没有问题。

七 .psp

 

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

60

 20

· Estimate

· 估计这个任务需要多少时间

 20

 15

Development

开发

 1570

 1600

· Analysis

· 需求分析 (包括学习新技术)

 20

 20

· Design Spec

· 生成设计文档

 30

 30

· Design Review

· 设计复审 (和同事审核设计文档)

 10

 20

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 10

 10

· Design

· 具体设计

 180

 20

· Coding

· 具体编码

 1200

 1000

· Code Review

· 代码复审

 20

0

· Test

· 测试(自我测试,修改代码,提交修改)

 100

 500

Reporting

报告

 100

 80

· Test Report

· 测试报告

 60

 50

· Size Measurement

· 计算工作量

 10

 10

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 30

 20

合计

 

1730

 1700

 

 

 

八、项目小结

本次项目为我们俩个人的首次结对项目,有很多东西都不熟悉,而且两个人熟悉的语言不相同,产生了很多的麻烦。

首先确定大家都会的语言(c语言)为本次项目的语言,然后确定了VScode为本次项目使用的IDE工具,然后再去找了VScode有

什么结对编程使用的插件,找到了live share,使用live share作为结对编程工具。

个人感想:

吴宗东:这次结对项目让我第一次有团队协作的感觉,队友的提醒和想法极大的加快了项目的完工,期待着下一次的团队项目。

林涛:本次有大佬带着非常舒服,因为我只学了c语言的皮毛,所以有很多东西都不知道,再加上live share没有找到有给加入者的错误提示,

写了很多BUG,都有大佬迅速改正。这次结对编程真的学到了很多。

 

结对项目-自动生成小学四则运算题目的命令行程序

原文:https://www.cnblogs.com/qiuyezhezhi/p/12616532.html

(1)
(1)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!