zoukankan      html  css  js  c++  java
  • 结对作业

    题目:实现一个自动生成小学四则运算题目的命令行程序


    项目GitHub地址:https://github.com/LittleTaro/Calculator

    结对人:舒雯钰(3218005129)、方子茵(3218005127)

    PSP2.1

    Personal Software Process Stages

    预估耗时(分钟)

    实际耗时(分钟)

    Planning

    计划

     30

     45

    · Estimate

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

     30

     35

    Development

    开发

     1670

     2020

    · Analysis

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

    240

     520

    · Design Spec

    · 生成设计文档

     150

     135

    · Design Review

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

     60

     50

    · Coding Standard

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

     20

     40

    · Design

    · 具体设计

     180

     240

    · Coding

    · 具体编码

     600

     600

    · Code Review

    · 代码复审

     180

     135

    · Test

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

     240

     300

    Reporting

    报告

     120

     240

    · Test Report

    · 测试报告

     60

     40

    · Size Measurement

    · 计算工作量

     30

     45

    · Postmortem & Process Improvement Plan

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

     30

     65

    合计

     

     1820

     2305



    项目要求


    使用 -n 参数控制生成题目的个数,例如:Myapp.exe -n 10  将生成10个题目。
    使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如:Myapp.exe -r 10将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。
    生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。
    生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。
    每道题目中出现的运算符个数不超过3个。
    程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。
    生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:四则运算题目1
          2. 四则运算题目2
          3. ……
          其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。
    在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
    答案1
    答案2
    ……
           特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
    程序应能支持一万道题目的生成。
    程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下: 
      Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt
      统计结果输出到文件Grade.txt,格式如下:
        Correct: 5 (1, 3, 5, 7, 9)
             Wrong: 5 (2, 4, 6, 8, 10)



    效能分析


    代码设计

     


    关键代码

      1 #include "Calculator.h"
      2 //#include<stdio.h>
      3 //#include<stdlib.h>
      4 //#include<string>
      5 //#include<time.h>
      6 //#include <iostream>
      7 //using namespace std;
      8 time_t g_unused = (srand(time(NULL)), 0);     // Generate a seed for 'rand' in whole program.
      9 
     10 const char* operators[4] = { " + ", " - ", " * ", " / " };
     11 
     12 int random(int a, int b) // 生成[a,b]间的随机整数
     13 {
     14     //srand((unsigned)time(NULL));
     15     return (rand() % (b - a + 1) + a);
     16 }
     17 
     18 char a[100] = "";
     19 char* op = a;     // 存放转换成由数字转换而来的字符串
     20 char b[100] = "";
     21 char* pro = b;  // 存放题目
     22 char c[100] = "";
     23 char* dem = c;//  存放转换成字符串的分母
     24 char d[100] = "";
     25 char* tmp = d;;// 存放转换成字符串的带分数整数部分
     26 
     27 
     28 char* GeneratePro()
     29 {
     30     int num = 0;          // 运算符个数,1~3个
     31     int index = 0;        // 指示运算符的下标
     32     num = random(1, 3);   // 随机生成运算符个数,1到3个
     33     int count = 0;
     34     int left_c = 0;      // 未匹配的左括号个数
     35     int tag = 0;         // 在操作数右边插入“)”指示该操作数左边是否插入左括号
     36     memset(pro, 0, sizeof(pro));  // 每调用一次,都要初始化内存空间
     37     //memset(tmp, 0, sizeof(tmp));  // 每调用一次,都要初始化内存空间
     38     int way = 0;    // 括号插入方式
     39     while (count < num)
     40     {
     41         // 先在此处判断是否插入“(”
     42         if (count == 0 && num > 1 && random(0, 1))
     43         {
     44             strcat_s(pro, strlen(pro) + 2, "(");    // 插入左括号
     45             left_c++;    // 未匹配的左括号个数加1
     46             tag = 1;
     47         }
     48         else if (count == 1 && num > 1 && random(0, 1) && !left_c)
     49         {
     50             strcat_s(pro, strlen(pro) + 2, "(");    // 插入左括号
     51             left_c++;    // 未匹配的左括号个数加1
     52             tag = 1;
     53         }
     54         else if (count == 2 && num > 2 && random(0, 1) && !left_c)
     55         {
     56             strcat_s(pro, strlen(pro) + 2, "(");    // 插入左括号
     57             left_c++;    // 未匹配的左括号个数加1
     58             tag = 1;
     59         }
     60         // 随机生成一个运算数(整数或分数),并将其转变为字符串形式
     61         op = GenerateOperand();//operand = GenerateOperand();
     62         strcat_s(pro, strlen(pro) + strlen(op) + 1, op);    // 将操作符移到指向题目的指针
     63         // 在此处判断是否插入“)”
     64         if (tag != 1 && ((count == num - 1) || random(0, 1)) && left_c)
     65         {
     66             strcat_s(pro, strlen(pro) + 2, ")");    // 插入右括号
     67             left_c--;    // 未匹配的左括号个数减1
     68         }
     69         else if (tag == 1)
     70         {
     71             tag = 0;     // 该数左边已插入"(",不可在右边插入")",但要取消标志以便下一次匹配
     72         }
     73 
     74         // 若第一循环到此处:pro是一个运算数字符串,下面再随机生成运算符并拼接
     75         // 随机生成运算符下标
     76         //srand((unsigned)time(NULL));
     77         index = rand() % 4;       // 生成运算符索引下标
     78         strcat_s(pro, strlen(pro) + 4, operators[index]);   // 拼接运算数与运算符
     79         count++;
     80     }
     81     // 此时还要再生成一个运算数并拼接
     82     op = GenerateOperand();
     83     strcat_s(pro, strlen(pro) + strlen(op) + 1, op);
     84     // 判断最后一个操作数后面是否插入“)”
     85     if (left_c)
     86     {
     87         strcat_s(pro, strlen(pro) + 2, ")");    // 插入右括号
     88         left_c--;    // 未匹配的左括号个数减1
     89     }
     90 
     91     return pro;                   // 返回生成的题目
     92 }
     93 
     94 char* GenerateOperand()    // 随机生成操作数
     95 {
     96     extern int range;      // 引用main.cpp中的全局变量range,操作数范围
     97     memset(op, 0, sizeof(op));
     98     int operand = 0;          // 随机生成的整型运算数
     99     int inteP = 0;            // 带分数的整数部分
    100     int demominator = 0;      // 分母部分
    101     int numerator = 0;        // 分子部分
    102     // 随机生成一个数,决定要生成整数(1),真分数(2),还是带分数(3)
    103     int type = 0;     // 即将生成的数据类型
    104     //type = 1;
    105     type = random(1, 3);
    106     if (type == 1)
    107     {
    108         // 将生成整数
    109         //srand((unsigned)time(NULL));
    110         operand = rand() % range;
    111         _itoa_s(operand, op, 100, 10); //把整数部分转换成字符串
    112     }
    113     else
    114     {
    115         // 先生成不为0的且在范围内的分母
    116         demominator = random(2, range - 1);
    117         // 生成小于分母且非0的分子
    118         numerator = random(1, demominator - 1);
    119         _itoa_s(numerator, op, 100, 10);    // 先把分子部分转换成字符串放入op
    120         strcat_s(op, strlen(op) + 2, "/");       // 拼接分子串和"/"
    121         _itoa_s(demominator, dem, 100, 10);    // 
    122         strcat_s(op, strlen(op) + strlen(dem) + 1, dem);       // 拼接上分母
    123         // 到此op是一个表示真分数的字符串
    124         // 下面判断是否要生成分数的整数部分
    125         if (type == 3)   // 将要生成带分数的整数部分
    126         {
    127             // 注意这个整数不能为0
    128             inteP = random(1, range);        // 生成范围内且非0的整数部分
    129             memset(d, 0, sizeof(d));
    130             strcat_s(tmp, strlen(tmp) + strlen(op) + 1, op);       // 将分数内容移交给tmp,以便op去接收整数部分
    131             //tmp = op;          // tmp寄存真分数部分
    132             _itoa_s(inteP, op, 100, 10);       // 将其转换成字符串放入op
    133             strcat_s(op, strlen(op) + 2, "'");       // 拼接"'"
    134             strcat_s(op, strlen(op) + strlen(tmp) + 1, tmp);       // 拼接上真分数部分
    135         }
    136     }
    137     return op;    // 返回生成的操作数
    138 }

    计算逆波兰表达式

    #include "Calculator.h"
    //#include<stdio.h>
    //#include<stdlib.h>
    //#include<string>
    //#include<time.h>
    //#include <iostream>
    //using namespace std;
    time_t g_unused = (srand(time(NULL)), 0);     // Generate a seed for 'rand' in whole program.
    
    const char* operators[4] = { " + ", " - ", " * ", " / " };
    
    int random(int a, int b) // 生成[a,b]间的随机整数
    {
        //srand((unsigned)time(NULL));
        return (rand() % (b - a + 1) + a);
    }
    
    char a[100] = "";
    char* op = a;     // 存放转换成由数字转换而来的字符串
    char b[100] = "";
    char* pro = b;  // 存放题目
    char c[100] = "";
    char* dem = c;//  存放转换成字符串的分母
    char d[100] = "";
    char* tmp = d;;// 存放转换成字符串的带分数整数部分
    
    
    char* GeneratePro()
    {
        int num = 0;          // 运算符个数,1~3个
        int index = 0;        // 指示运算符的下标
        num = random(1, 3);   // 随机生成运算符个数,1到3个
        int count = 0;
        int left_c = 0;      // 未匹配的左括号个数
        int tag = 0;         // 在操作数右边插入“)”指示该操作数左边是否插入左括号
        memset(pro, 0, sizeof(pro));  // 每调用一次,都要初始化内存空间
        //memset(tmp, 0, sizeof(tmp));  // 每调用一次,都要初始化内存空间
        int way = 0;    // 括号插入方式
        while (count < num)
        {
            // 先在此处判断是否插入“(”
            if (count == 0 && num > 1 && random(0, 1))
            {
                strcat_s(pro, strlen(pro) + 2, "(");    // 插入左括号
                left_c++;    // 未匹配的左括号个数加1
                tag = 1;
            }
            else if (count == 1 && num > 1 && random(0, 1) && !left_c)
            {
                strcat_s(pro, strlen(pro) + 2, "(");    // 插入左括号
                left_c++;    // 未匹配的左括号个数加1
                tag = 1;
            }
            else if (count == 2 && num > 2 && random(0, 1) && !left_c)
            {
                strcat_s(pro, strlen(pro) + 2, "(");    // 插入左括号
                left_c++;    // 未匹配的左括号个数加1
                tag = 1;
            }
            // 随机生成一个运算数(整数或分数),并将其转变为字符串形式
            op = GenerateOperand();//operand = GenerateOperand();
            strcat_s(pro, strlen(pro) + strlen(op) + 1, op);    // 将操作符移到指向题目的指针
            // 在此处判断是否插入“)”
            if (tag != 1 && ((count == num - 1) || random(0, 1)) && left_c)
            {
                strcat_s(pro, strlen(pro) + 2, ")");    // 插入右括号
                left_c--;    // 未匹配的左括号个数减1
            }
            else if (tag == 1)
            {
                tag = 0;     // 该数左边已插入"(",不可在右边插入")",但要取消标志以便下一次匹配
            }
    
            // 若第一循环到此处:pro是一个运算数字符串,下面再随机生成运算符并拼接
            // 随机生成运算符下标
            //srand((unsigned)time(NULL));
            index = rand() % 4;       // 生成运算符索引下标
            strcat_s(pro, strlen(pro) + 4, operators[index]);   // 拼接运算数与运算符
            count++;
        }
        // 此时还要再生成一个运算数并拼接
        op = GenerateOperand();
        strcat_s(pro, strlen(pro) + strlen(op) + 1, op);
        // 判断最后一个操作数后面是否插入“)”
        if (left_c)
        {
            strcat_s(pro, strlen(pro) + 2, ")");    // 插入右括号
            left_c--;    // 未匹配的左括号个数减1
        }
    
        return pro;                   // 返回生成的题目
    }
    
    char* GenerateOperand()    // 随机生成操作数
    {
        extern int range;      // 引用main.cpp中的全局变量range,操作数范围
        memset(op, 0, sizeof(op));
        int operand = 0;          // 随机生成的整型运算数
        int inteP = 0;            // 带分数的整数部分
        int demominator = 0;      // 分母部分
        int numerator = 0;        // 分子部分
        // 随机生成一个数,决定要生成整数(1),真分数(2),还是带分数(3)
        int type = 0;     // 即将生成的数据类型
        //type = 1;
        type = random(1, 3);
        if (type == 1)
        {
            // 将生成整数
            //srand((unsigned)time(NULL));
            operand = rand() % range;
            _itoa_s(operand, op, 100, 10); //把整数部分转换成字符串
        }
        else
        {
            // 先生成不为0的且在范围内的分母
            demominator = random(2, range - 1);
            // 生成小于分母且非0的分子
            numerator = random(1, demominator - 1);
            _itoa_s(numerator, op, 100, 10);    // 先把分子部分转换成字符串放入op
            strcat_s(op, strlen(op) + 2, "/");       // 拼接分子串和"/"
            _itoa_s(demominator, dem, 100, 10);    // 
            strcat_s(op, strlen(op) + strlen(dem) + 1, dem);       // 拼接上分母
            // 到此op是一个表示真分数的字符串
            // 下面判断是否要生成分数的整数部分
            if (type == 3)   // 将要生成带分数的整数部分
            {
                // 注意这个整数不能为0
                inteP = random(1, range);        // 生成范围内且非0的整数部分
                memset(d, 0, sizeof(d));
                strcat_s(tmp, strlen(tmp) + strlen(op) + 1, op);       // 将分数内容移交给tmp,以便op去接收整数部分
                //tmp = op;          // tmp寄存真分数部分
                _itoa_s(inteP, op, 100, 10);       // 将其转换成字符串放入op
                strcat_s(op, strlen(op) + 2, "'");       // 拼接"'"
                strcat_s(op, strlen(op) + strlen(tmp) + 1, tmp);       // 拼接上真分数部分
            }
        }
        return op;    // 返回生成的操作数

    }

    测试运行


    项目小结

    方子茵:

     只实现了一小部分功能,因为沟通较少,不能充分了解对方的想法。没有详细计划好再编程。但是也从中意识自己能力有很大欠缺
     结对项目双方要有充分交流,明确分工,了解彼此的想法,项目才能统一起来
     结对感受:队友打码积极,但是和我一样比较拖拉,我们两个都不主动,结对项目要注重交流沟通

    舒雯钰:

    虽然很早就和队友沟通了想法和思路,但是比较晚开始具体编码,没有规划好时间,而且不知道电脑哪的配置出了问题,尝试了很多解决方法vscode还是不能编译,我要对我的队友说抱歉QAQ。

    结对感受:队友非常积极地沟通、安排进度,而且会主动说出具体的想法来对接,她负责的部分完成的很好。

  • 相关阅读:
    大数据之路_1
    Echart图表设置项
    AsyncSocket
    book_.Net与设计模式
    book_精通正则表达式
    操作系统基本功能
    操作系统基础
    网络系统结构与设计的基本原则
    3.1EDA和数据描述: 探索性数据分析
    宽带城域网
  • 原文地址:https://www.cnblogs.com/kriswy666/p/12617261.html
Copyright © 2011-2022 走看看