结对编程项目—四则运算 第二周 整体总结

20175214林郅聪 结对编程项目—四则运算 第二周 整体总结

一、需求分析

1.题目要求:
  • 实现一个命令行程序,要求:

    • 自动生成小学四则运算题目(加、减、乘、除)

      • 支持整数
      • 支持多运算符(比如生成包含100个运算符的题目)
      • 支持真分数
    • 统计正确率

2.扩展需求
  • 可以实现多语言,包括简体中文,繁体中文和英文
  • 生成题目去重
  • 输入题目到文件,从文件中读取题目并判断对错
3.深度需求

本次结对项目要求完成小学生的四则运算,除了题目中要求的内容外,还可以包含以下方面

  • 进行难度更高的运算,比如嵌套运算或其他运算符例如求方幂、求整、取余等
  • 由于是通过程序完成,在给出测试的正确率的情况下可以判断正确率是否达到合格标准,若未达到则继续进行直到达到标准为止
  • 让学生自由选择题目难度,根据不同难度给出相应评价

二、设计思路

在开始本周任务前,我对我们的程序进行了简要的分析,和上周相比有如下的改变

  • 增加了真分数的运算,并控制分数的格式(在后面会有说明)
  • 给出了多语言的支持:简体中文、繁体中文、英文
  • 生成了题目去重的功能:在原来的基础上进行了适当的修改,因为当生成算式较短时比较容易重复,但这一部分的代码还存在一些问题,目前只能判断两道题目是否完全相同,不能排除1 + 22 + 1 这种重复的情况
UML类图

1592121-20190414221732369-771713103.png

三、变动的代码

  • 首先是分数的形式,选择将分号“/”也当做随即字符和加减乘除一起随机产生,而在中缀转后缀运算式将分号的优先级设置为仅低于有括号,这样可以区别分号“/”和除号“÷”
public int compareValue(char chi) {    
    int number = 0;    
    switch (chi) {        
        case '(':            
            number = 1;            
            break;        
        case '+':        
        case '-':            
            number = 2;            
            break;        
        case '*':        
        case '÷':            
            number = 3;            
            break;        
        case '/':            
            number = 4;            
            break;        
        case ')':            
            number = 5;            
            break;        
        default:            
            number = 0;            
            break;    
        }    
    return number;
}
  • 如何产生真分数?分数的产生很容易,那如何控制产生真分数呢?和其他小组的同学讨论研究后发现他们的方式都不适合我们,因为在产生算式用到的方法不同,分数的生成方式也存在差异,因此他们声称分数的方法并不适合我们。在和结对伙伴讨论后,我们决定先产生分子,根据分子的范围控制分母的大小
else if (rand == 0 && flag2 % 2 == 0 || flag5 % 3 == 0 && flag2 % 2 == 0    {                                        //插入数字                
    if(flag6==1)                     //当产生了分号时 
        n = num.GetNumber(a-n)+n;    //控制分号后面的数比分号前面的数大但不会超过给出的最大值
    else n = num.GetNumber(a);    
        q += n;    
        flag2++;    
        flag5 = 0;    
        countTotal++;
  • 接下来是真分数的产生和运算部分,关于这一部分,在编写之前花了很长时间思考,因为分数在运算时涉及到了压栈的问题,而在运算时如果将分子分母和分号分开压栈那么就失去了本来的意义,如果将分数控制为字符串的形式进行压栈操作,那么之前的代码需要全部重写,最后在翻看教材的时候发现的书上第四章Example4_23中给出了一个有理数Rational类,可以通过该类进行分数的运算,而这种方法也正适合我们之前写的程序。在对书上的例子进行少许修改后,应用到我们的程序中
Rational div(Rational r)  { //除法运算    
    int a=r.getNumerator();    
    int b=r.getDenominator();   
    int newNumerator=numerator*b;    
    int newDenominator=denominator*a;    
    Rational result=new Rational();   
    if(a==0) {        
        System.out.println("该算式无解");        
        result.setNumerator(0);    
    }    
    else {        
        result.setNumerator(newNumerator);        
        result.setDenominator(newDenominator);    
    }    
    return result;
}
  • 简要说明:这一部分的程序与书上基本相同,但由于书上是控制输入,因此不需要排除分母为0的情况,而我们的程序中数字时随机产生的,可能会在运算的过程中产生了计算出的结果是0作为了分母,因此需要控制这种情况

  • 多语言选择:在完成这一部分内容时,我们选择了用抽象类的方法,将每一种提示作为一个抽象方法,三种语言作为子类重写其中的方法

package CalculateSystem;
public abstract class Language {    
    public abstract String getQuestionNumber();    
    public abstract String getMaxNumber();    
    public abstract String getMaxOperator();    
    public abstract String getInputAnswer();    
    public abstract String getRight();    
    public abstract String getWrong();    
    public abstract String getRate();    
    public abstract String getContinue();   
    public abstract String getThanks();
}

下面是子类English中重写的方法

public class English extends Language {    
    public String getQuestionNumber() {        
        return "Enter the number of questions you want to do:";    
    }    
    public String getMaxNumber() {        
        return "Please enter the maximum number you want to operate:";   
    }    
    public String getMaxOperator() {        
        return "Please enter the length of the expression you want to operate:";    
    }    
    public String getInputAnswer() {        
        return "Enter your answer :(floating point)";    
    }    
    public String getRight() {        
        return "Congratulations! Your answer is right";    
    }    
    public String getWrong() {        
        return "Wrong answer! The correct answer is";    
    }    
    public String getRate() {        
        return "Test over! Your accuracy is";    
    }    
    public String getContinue() {        
        return "Do you want to continue? Please enter 1 to continue and 0 to exit";    
    }    
    public String getThanks() {        
        return "Test over, thanks for using!";    
    }
}
  • 题目去重:这一部分的代码的功能 并不全面,只限于判断两道题目是否完全相同,并不能判断其中是否含有没有意义的重复
GetQuestion q = new GetQuestion();
String question1 = q.get(maxnum,maxop);
if(question1.equals(question2)) {                     //判断时候和前一题是否相等,相等则不计入次数,重新产生等式    
    i--;        continue;
}
System.out.println(question1);
question2 = question1;                                 //不相同则把该题目赋值给question2用于和下一题进行比较

四、遇到的问题

  • 开始时我和伙伴在考虑如何生成真分数的同时,也在考虑如何保证过程中也都控制真分数,后来发现没有必要纠结这个问题,只需要控制在生成时生成简单的真分数,例如13/15 即可,因为在运算过程中给存在括号优先级的问题,例如 (15*3+8)/16 并不需要在运算过程中控制都是真分数
  • 在进行压栈和弹栈运算时,将弹出的数转化为有理数时,发现第一个弹出的数总是会被第二个数覆盖,在探讨测试后发现是因为定义了一个变量num,他的作用是,当栈中的数不是运算符的时候,要将其放回。这个变量定义在了if-else 语句外,因此只有最开始初始化了变量,在运算过程中一直使用后面的数覆盖前面的数,因此弹出的两个数会一样,更该方法是将变量的初始化放在else语句中,每次判断时,都要初始化,这样不会对之前的产生影响。
while (token.hasMoreTokens()) {    
    temp = token.nextToken();    
    if (Isop(temp) == 1)//遇到操作符,弹出栈顶的两个数进行运算    {        
        op2 = (Rational) stack.pop();        
        op1 = (Rational) stack.pop();//弹出最上面两个操作数        
        result = cal(temp.charAt(0), op1, op2);//根据运算符进行运算        
        stack.push(result);//将计算结果压栈    
    } 
    else {        
        Rational num = new Rational();        //每次重新初始化
        num.setNumerator(Integer.parseInt(temp));        
        stack.push(num);//操作数入栈    
    }
}
  • 产生分数时会产生 5/7/8 的形式,事实上这种分数产生的意义不大,我们希望避免这种情况,几经尝试后选择在产生问题的类中再加flag变量进行控制

五、运行过程截图

1592121-20190414221908608-734148924.png
1592121-20190414221914799-1106899921.png
1592121-20190414221921018-1678370936.png
1592121-20190414221924048-1051216349.png

六、代码托管

https://gitee.com/fzlzc/java2019/tree/master/src/CalculateSystem

七、对结对伙伴的评价

我觉得我的小伙伴非常棒,这周他主要负责添加真分数功能和语言包,这部分基本由他独立完成,我只负责对接,最后拼接虽然有些磕磕绊绊,有许多没有发现的bug错误,但是一一纠正检验,一起讨论学习的氛围让我觉得十分酣畅,而且成果还是比较让我们满意的,基本完成了预期,希望以后可以继续这样快乐合作,快乐编程。

### 八、预估时间与实际时间

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划
•Estimate• 估计这个任务需要多少时间570815
Development开发
• Analysis• 需求分析 (包括学习新技术)3040
• Design Spec• 生成设计文档3030
• Design Review• 设计复审 (和同事审核设计文档)2040
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)2060
• Design• 具体设计2025
• Coding• 具体编码360500
• Code Review• 代码复审2020
• Test• 测试(自我测试,修改代码,提交修改)3050
Reporting报告
• Test Report• 测试报告2020
• Size Measurement• 计算工作量1010
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划1020
合计570815

转载于:https://www.cnblogs.com/fzlzc/p/10707481.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ChatGPT结对编程是一种将两个程序员合作编写代码的技术。这种技术可以提高编写代码的效率和质量,同时也可以提高两位程序员的技能水平。以下是ChatGPT结对编程的步骤: 1. 首先,找到一个合适的编程伙伴。最好是一个有一定编程经验的人,但如果你是新手,也可以与另一个新手合作。 2. 确定你们编写的代码项目。你们可以选择一个共同感兴趣的项目或者一个有挑战性的项目。确保你们都对项目有一定的理解。 3. 确定你们的角色。一个人可以担任主要代码编写者,另一个人可以担任代码审核者。这样可以确保代码的质量。 4. 确定编程环境。你们可以使用一个共同的编程环境,如Visual Studio Code或者Atom。也可以使用在线编程环境,如CodePen或JSFiddle。 5. 开始编写代码。一个人负责编写代码,另一个人负责审核代码。在编写代码的过程中,你们可以随时通过聊天工具进行交流和讨论。 6. 定期进行代码审核。定期进行代码审核可以确保代码的质量。你们可以定期的分享代码,并相互审核对方的代码。 7. 完成项目并进行总结。完成项目后,你们可以总结你们的经验和教训,并提出改进建议。这将有助于你们以后更好的编写代码。 总之,ChatGPT结对编程是一种非常有用的技术,可以提高编写代码的效率和质量。通过合作编写代码,你们可以相互学习,相互支持,以及增强你们的编程技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值