【软件工程基础结队项目】四则运算题目生成

本文介绍了一个能自动生成小学四则运算题目的命令行软件,支持整数和真分数运算,乘方运算,以及Windows/Mac/Linux图形界面。软件包含倒计时和历史记录功能,用户可在20秒内答题,记录成绩。作者负责分数题目部分,队友负责整数部分和界面。关键代码包括随机生成真分数、运算符重载、出题和逆波兰表达式求值。
摘要由CSDN通过智能技术生成

Github 项目地址

Github: acromema/CPGenerator

任务

写一个能自动生成小学四则运算题目的命令行软件,满足以下要求:

  • 一次可以出一千道题目,并且没有重复的,把题目写入一个文件中。
  • 当有多余一个运算符的时候,对表达式求值。
  • 除整数以外,还要支持真分数的四则运算。
  • 让程序能接受用户输入答案,并判定对错。最后给出总 对/错 数量。
  • 支持乘方运算。
  • 把程序变成一个 Windows/Mac/Linux电脑图形界面程序。
  • 增加“倒计时”功能,每个题目必须在20s内完成,如果完不成,则得0分并进入下一题。
  • 增加“历史记录”功能,把用户做题的成绩记录下来并可以展现历史记录。

时间预估

PSP 2.1Personal Software Process Stages预估耗时(min)实际耗时(min)
Planning计划60
Estimate估计这个任务需要多少时间60
Development开发2400
Analysis需求分析(包括学习新技术)360
Design Spec生成设计文档120
Design Review设计复审(和同事审核审计文档)60
Coding Standard代码规范(为目前的开发制定合适的规范)60
Design具体设计360
Coding具体编码600
Code Review代码复审480
Test测试(自我测试,修改代码,提交修改)360
Reporting报告420
Test Report测试报告120
Size Measurement计算工作量120
Postmortem & Process Improvement Plan事后总结,并提出过程改进计划180
合计2880

需求分析

模块划分

程序要同时支持整数和真分数的四则运算,由于分数无法直接运算,因此单独进行处理。

  • 整数题目
    包含第一阶段的整数题目生成以及第二阶段的乘方运算。
  • 分数题目
    包括第一阶段分数的四则运算和题目的生成。

分工为:我完成分数题目部分,队友完成整数部分和界面部分。

队友传送门-> 闪bo

设计实现

定义class PF真分数类,包含:

  • int mother 分母
  • int son 分子
  • PF() 随机生成分母分子值的构造函数
  • PF(int _mother, int _son) 指定分母分子值的构造函数
  • Display() 显示函数(将分数显示在命令行中方便调试)
  • ConvertString() 真分数转字符串的转换函数(方便存储到字符串中)
  • GetRandomSeed() 随机数种子函数(用于随机生成分母分子值)
  • MaxComDivisor(int x, int y) 最大公因子函数(用于约分化简)
  • operator +-*/(PF p1, PF p2) 重载四种运算符(用于分数分四则运算)

定义class Problem题目类,包含:

  • string op1 op2 op3 3个运算符
  • PF p1 p2 p3 p4 4个运算数
  • Problem() 生成一道题目的构造函数
  • NextProblem() 生成下一道题目的函数
  • CalValue() 表达式求值函数(计算当前题目答案)
  • ConvertString() 真分数转字符串的转换函数(方便存储到字符串中)
  • GetRandomSeed() 随机数种子函数(用于随机生成分母分子值)
  • MaxComDivisor(int x, int y) 最大公因子函数(用于约分化简)
  • operator +-*/(PF p1, PF p2) 重载四种运算符(用于分数分四则运算)

关键代码

1.随机生成真分数(构造函数)

 public PF()
        {
        	Random rand = new Random(GetRandomSeed());
        	mother = rand.Next(3,10);
            son = rand.Next(1,2);
            int maxDivisor = MaxComDivisor(Math.Abs(mother), Math.Abs(son));
            mother /= maxDivisor;
            son /= maxDivisor;
        }

2.重载四个运算符

public static PF operator+ (PF p1,PF p2)  
        {  
           int mother = p1.mother * p2.mother;
           int son1 = p1.son * p2.mother;
           int son2 = p2.son * p1.mother;
           int son = son1 + son2;
           PF sum = new PF(mother, son);
           return sum;
        }

        public static PF operator- (PF p1,PF p2)  
        {  
           int mother = p1.mother * p2.mother;
           int son1 = p1.son * p2.mother;
           int son2 = p2.son * p1.mother;
           int son = son1 - son2;
           PF result = new PF(mother, son);
           return result;
        }

        public static PF operator* (PF p1,PF p2)  
        {  
           int mother = p1.mother * p2.mother;
           int son = p1.son * p2.son;
           PF result = new PF(mother, son);
           return result;
        }

        public static PF operator/ (PF p1,PF p2)  
        {  
           int mother = p1.mother * p2.son;
           int son = p1.son * p2.mother;
           PF result = new PF(mother, son);
           return result;
        }

3.出题

public Problem()
        {
            string[] op = new string[]{"+", "-", "*", "/", "-", "+"};
            Random rand = new Random(GetRandomSeed());
            op1 = op[rand.Next(6)];
            op2 = op[rand.Next(6)];
            op3 = op[rand.Next(6)];
            p1 = new PF();
            int baseMother = rand.Next(2,5)*p1.mother;
            p2 = new PF(baseMother,rand.Next(1,baseMother));
            baseMother = rand.Next(2,5)*p1.mother;
            p3 = new PF(baseMother,rand.Next(1,baseMother));
            baseMother = rand.Next(2,5)*p1.mother;
            p4 = new PF(baseMother,rand.Next(1,baseMother));
            problem = p1.ConvertString() + " " + op1 + " " + p2.ConvertString() + " " + op2 + " " + p3.ConvertString() + " " + op3 + " " + p4.ConvertString();
        }

4.转化为逆波兰表达式并求值

public PF CalValue()
        {
            string[] symbols = {"1", op1, "2", op2, "3", op3, "4"};
            Stack<string> operaStack = new Stack<string>();
            Queue<string> valueQueue = new Queue<string>();
            Stack<PF> numStack = new Stack<PF>();
            for (int i = 0; i < symbols.Length; i++)
            {
                if (IsInt(symbols[i]))
                {
                    valueQueue.Enqueue(symbols[i]);
                }
                else if (IsOperator(symbols[i]))
                {
                    while (operaStack.Count != 0 && GetOpLevel(operaStack.Peek())>=GetOpLevel(symbols[i]))
                    {
                        valueQueue.Enqueue(operaStack.Pop());
                    }
                    operaStack.Push(symbols[i]);
                }
            }            
            while (operaStack.Count != 0)
            {
                valueQueue.Enqueue(operaStack.Pop());
            }
            while(valueQueue.Count != 0)
            {
                if(IsInt(valueQueue.Peek()))
                {
                    switch (valueQueue.Peek())
                    {
                        case "1":
                            numStack.Push(p1);
                            break;
                        case "2":
                            numStack.Push(p2);
                            break;
                        case "3":
                            numStack.Push(p3);
                            break;
                        case "4":
                            numStack.Push(p4);
                            break;
                        default:
                            break;
                    }  
                    valueQueue.Dequeue();
                    // numStack.Peek().Display();
                    // Console.WriteLine(" ");
                }
                else
                {
                    string operation = valueQueue.Dequeue();
                    numStack.Push(GetResult(operation, numStack.Pop(), numStack.Pop()));
                }   
            }
            PF result = numStack.Pop();
            return result;
        }

时间统计

PSP 2.1Personal Software Process Stages预估耗时(min)实际耗时(min)
Planning计划6060
Estimate估计这个任务需要多少时间6060
Development开发24002130
Analysis需求分析(包括学习新技术)360300
Design Spec生成设计文档120120
Design Review设计复审(和同事审核审计文档)6060
Coding Standard代码规范(为目前的开发制定合适的规范)6030
Design具体设计360300
Coding具体编码600720
Code Review代码复审480360
Test测试(自我测试,修改代码,提交修改)360240
Reporting报告420270
Test Report测试报告12090
Size Measurement计算工作量12090
Postmortem & Process Improvement Plan事后总结,并提出过程改进计划180120
合计28802460
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值