一、需求分析
1.基本需求
- 随机生成n道题目
- 支持整数、分数,支持多运算符
- 能判断正误,错误时给出正确答案
- 能计算出正确率
2.扩展需求
- 处理生成题目并输出到文件
- 完成题目后从文件读入并判题
- 支持多语言:
简体中文
、繁体中文
、English
二、设计思路
由于上周已经把大的框架设计好了、也实现了整数运算。故本周的主要任务为真分数的添加、输出题目到文件、从文件读取题目并判题、多语言的实现、Junit测试。
1.真分数的添加
- 在生成题目时添加一种情况:随机插入真分数
- 设计
RandomFenshu
类返回形式正确的真分数 - 设计
getRational
类用于后缀转结果计算时使用 - 修改
ZhongzhuiToHouzhui
、getResult
类,使其适配分数的计算
2.输出题目到文件
- 添加主类
ShuChuTimu
将随机生成的题目输出到文件
3.从文件读取题目并判题
- 修改主类
sizeyunsuan
使其能从文件中读题、判题、并将结果输出到另一个文件
4.多语言的实现
- 添加抽象类
Language
实现多语言
5.Junit测试
- 参考单元测试完成。
6.类图
三、修改完善代码的过程
1.题目输出到文件阶段
- 因为上周刚学到文件这一块,掌握还不是很熟练,尝试了很多次都失败后,上网查阅,使用
PrintStream
成功将题目写入文件,但出现了如下的问题:
- 仔细阅读了程序,发现我的i是从0开始的,而字符串数组是从1开始的,又上网查阅了资料,换行符应表示为
2.从文件读题并判题阶段
- 考虑使用
FileInputStream
输入流指向最开始生成题目的文件,然后用InputStreamReader
将字节流转为字符流,再用BufferReader
添加辅助功能。 - 使用
StringTokenizer
将公式以“:”和“=”分割,从而计算出结果。
3.添加真分数阶段
- 随机生成公式中添加:用字符串的形式,添加不可约的真分数
真分数的计算 - 中缀转后缀:因真分数的字符串长度为3,故不能再用
字符串名.split(" ")
的方法,故考虑使用StringTokenizer
将公式以空格分割开。
-
后缀出结果:同样使用
StringTokenizer
将公式以空格分开,带真分数的计算考虑将所有的数都化为分数进行计算,即计算时将出栈的两元素都转化为getRational
型,再进行计算,最后返回字符串型结果。 -
遇到的问题:没有考虑分母为1的情况,后来修改程序得以解决。
4.多语言实现阶段
- 考虑使用
Language
抽象类,用几种语言继承该抽象类实现多态 - 添加
ChooseLanguage
类,进行语言的选择与识别 - 在读题、判题过程中考虑直接识别文件中的语言进行语言确定,但进行语言对比调用
equals
时发现比较产生异常,因此将字符串转为字符数组,进行比较,解决了问题~
5.Junit测试阶段
- 刚开始这里选错了,一直显示错误
- 后来修正了错误后,测试成功
四、核心代码解释
- 生成随机数代码:
import java.util.*;
import java.lang.*;
public class getRandom {
String s;
String str[]=new String[100];
char a,b; //a:插入的数字,b:插入的符号
int x; //x:插入符号的个数
char flag1,flag3; //flag1:左括号,flag3:右括号
int flag2=0,flag4=0; //flag2:插入左括号的个数,flag4:控制不连续插入左右括号
public void storeRandom(int n) {
for(int i=1;i<=n;i++) { //存储随机生成的的每个公式
s="";
x=(int)(Math.random()*6)+3;
Random r3=new RandomFuhao();
flag1=r3.getRandom();
for(int j=1;j<=x;j++) { //依次插入数字、公式
Random r1=new RandomNum();
a=r1.getRandom();
s=s+(int)a+" ";
if(flag2>0&&flag4==0) {
Random r6=new RandomFuhao();
flag3=r6.getRandom();
if(flag3=='#') {
s=s+')'+" ";
flag2--;
}
}
flag4=0;
Random r2=new RandomChar();
b=r2.getRandom();
s=s+b+" ";
Random r4=new RandomFuhao();
flag1=r4.getRandom();
if(flag1=='#'&&j<x-1) {
s=s+'('+" ";
flag2++;
flag4=1;
}
}
RandomFuhao r7=new RandomFuhao();
if (r7.getRandom()=='#') { //控制随机插入分数
Random r5 = new RandomNum();
s = s + (int) r5.getRandom() + " ";
}
else {
RandomFenshu f=new RandomFenshu();
s=s+f.getFenshu()+" ";
}
while(flag2!=0) {
s=s+")"+" ";
flag2--;
}
str[i]=s;
}
}
public String[] retRandom() {
return str;
} //返回随机生成的公式
}
- 输出题目到文件:
import javax.imageio.IIOException;
import java.io.*;
import java.util.*;
public class ShuchuTimu {
public static void main(String[] args) throws FileNotFoundException{
getRandom g=new getRandom();
String string[];
ChooseLanguage c=new ChooseLanguage();
Language l;
l=c.choose();
System.out.println(l.getGeshu());
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
g.storeRandom(n);
string=g.retRandom();
PrintStream ps = new PrintStream("Exercises.txt");
for (int i=0;i<n;i++){
String s = l.getTimi() + (i+1) + ":" + string[i+1] + "
";
System.out.println(s);
ps.append(s);
}
ps.close();
ps.flush();
}
}
- 后缀出结果
import java.util.*;
import java.lang.*;
public class getResult {
public String getResult(String s){
Stack<String> stack=new Stack<String>(); //新建栈
String a,b;
StringTokenizer t=new StringTokenizer(s);
while (t.hasMoreTokens()){ //依次遍历元素,计算结果
String c=t.nextToken();
if (c.equals("+") || c.equals("-") || c.equals("*") || c.equals("÷")){ //遇到符号,弹出栈顶两个元素,并计算结果
a=stack.pop();
b=stack.pop();
getRational g1=rational(a);
getRational g2=rational(b);
stack.push(jisuan(g2,g1,c)); //将计算后的结果重新压入栈中
}
else { //遇到数字,直接入栈
stack.push(c);
}
}
String p=stack.pop();
StringTokenizer t2=new StringTokenizer(p,"/");
String token1=t2.nextToken();
String token2=t2.nextToken();
if (token2.equals("1"))
return token1;
else
return p;
}
public getRational rational(String a){
int i1,i2;
StringTokenizer t1=new StringTokenizer(a,"/");
String s1=t1.nextToken();
String s2;
if (t1.hasMoreTokens()){
s2=t1.nextToken();
i1=Integer.parseInt(s1);
i2=Integer.parseInt(s2);
getRational g1=new getRational(i1,i2);
return g1;
}
else {
i1=Integer.parseInt(s1);
i2=1;
getRational g2=new getRational(i1,i2);
return g2;
}
}
public String jisuan(getRational r1,getRational r2,String c){ //计算结果
getRational g=new getRational(0,1);
if (c.equals("+"))
g=r1.add(r2);
else if (c.equals("-"))
g=r1.sub(r2);
else if (c.equals("*"))
g=r1.muti(r2);
else
g=r1.div(r2);
return g.getNumerator()+"/"+g.getDenominator();
}
}
- 从文件读题、判题
import java.io.*;
import java.util.*;
public class sizeyunsuan {
public static void main(String args[]) throws IOException{
ZhongzhuiToHouzhui z=new ZhongzhuiToHouzhui();
getResult r=new getResult();
FileInputStream fis = new FileInputStream("Exercises.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader in = new BufferedReader(isr);
Language l;
ChooseLanguage recognizeLanguage=new ChooseLanguage();
String s1,s2,s3,s4;
String str,str1,str2;
String s;
String result=null;
int count=0,n=0;
PrintStream ps=new PrintStream("Result.txt");
while ((str=in.readLine())!=null){
StringTokenizer t1=new StringTokenizer(str,":");
s1=t1.nextToken();
l=recognizeLanguage.recognize(s1,n+1);
s2=t1.nextToken();
StringTokenizer t2=new StringTokenizer(s2,"=");
s3=t2.nextToken();
s4=t2.nextToken();
s=z.result(s3);
result=r.getResult(s);
if (s4.equals(result)){
str1=l.right();
count++;
}
else
str1=l.wrong()+result;
n++;
str2=str+"
"+str1+"
";
ps.append(str2);
}
FileInputStream fis0 = new FileInputStream("Result.txt");
InputStreamReader isr0 = new InputStreamReader(fis0);
BufferedReader in0 = new BufferedReader(isr0);
str=in0.readLine();
StringTokenizer t3=new StringTokenizer(str,":");
s1=t3.nextToken();
l=recognizeLanguage.recognize(s1,1);
str2=l.wancheng1()+n+l.wancheng2()+((double)count/n)*100+"%";
ps.append(str2);
System.out.println(str2);
}
}
五、运行结果
六、码云托管地址
七、对结对的小伙伴进行评价
- 我的小伙伴在这周的任务中继续担任“领航员”的角色,我主要负责一些想法的构建和一些零散的工作,对方负责完成项目的主干,打磨主体部分。我的小伙伴态度认真,学习积极,严谨细致且颇具耐心,在此次任务中给予我很大的帮助,也是我学习的榜样。
八、总结
- 在本次结对编程中,我学到了很多,也受到了小伙伴很大的鼓励。在完成此次项目的过程中,也出现了很多问题,很多知识掌握的不牢靠,当一些概念问题上升到应用层时难以将其完美地实现,无法与想法完美契合,想要做好仍需不断扩充我们的知识量,以及积极主动地敲代码,加速对知识的熟悉程度与运用能力。
九、预估与实际
Planning | 计划 | 预估耗时(分钟) | 实际耗时 |
---|---|---|---|
Estimate | 预估这个任务需要多长时间 | 1110 | 1580 |
Development | 开发 | ||
Analysis | 需求分析(包括学习新技术) | 40 | 90 |
Design Spec | 生成设计文档 | 30 | 30 |
Design Review | 设计复审 | 60 | 60 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 40 | 40 |
Design | 具体设计 | 70 | 70 |
Coding | 具体编码 | 700 | 1100 |
Code Review | 代码复审 | 60 | 60 |
Test | 测试(自我测试、修改代码、提交修改) | 40 | 60 |
Reporting | 报告 | ||
Test Report | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem&Process Improvement Plan | 事后总结并提出改进计划 | 40 | 40 |
合计 | 1110 | 1580 |