结对项目--自动生成小学四则运算题目
这个作业属于哪个课程 | [https://edu.cnblogs.com/campus/gdgy/Networkengineering1834] |
---|---|
这个作业要求在哪里 | [https://edu.cnblogs.com/campus/gdgy/Networkengineering1834/homework/11148] |
这个作业的目标 | 队友互相协作生成设计文档,实现代码编写和代码复审,最终实现一个可以自动生成小学四则运算题目 |
结对成员:
- 郑旭朋(3118005301)
- 卢进兴(3118005286)
一.github仓库
https://github.com/JJDD-ljx/Pair-Project
二.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 10 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 440 | 1080 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 180 |
· Design Spec | · 生成设计文档 | 20 | 10 |
· Design Review | · 设计复审 | 10 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
· Design | · 具体设计 | 10 | 10 |
· Coding | · 具体编码 | 180 | 560 |
· Code Review | · 代码复审 | 30 | 180 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | 110 | 110 |
· Test Report | · 测试报告 | 60 | 60 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
Total | · 合计 | 560 | 1200 |
三.设计与实现的过程
大体思路
-
键盘录入题目数值的范围range和生成题目的数量questionNum
-
用for循环来控制题目数量for(i=0;i<questionNum;i++)每次循环产生一条题目
-
题目运算符+-/的个数随机生成(1-3个),用字符数组来装+-×÷
char[] operator = {'+','-','×','÷'};
int j(1/2/3) = r.nextInt(4);
这样就随机产生运算符了,如j1随机得0时,operator[j1]含义是第一个运算符为+ ,当j3随机得3时,operator[j3]含义就是第三个运算符为÷ -
每条题目的数值最多4个,随机4个分子和4个分母出来,然后通过函数Fraction(分子,分母)得到分数num1/2/3/4
-
由于每次循环的运算符个数不同,开始分类讨论
- 当运算符个数为1个时
- 用字符串来表示式子 str="num1+operator[j1]+num2=" 然后输出题目 println("题目i:"+str)
- 使用函数Calculator(str)得出题目的答案answer {由于+-×÷是字符,不是运算符不能直接计算,所以要新建函数Calculator来读取字符串并计算出结果}
- 保存题目和答案到txt文件 - 当运算符个数为2个时,同上,只有str="num1+operator[j1]+num2+operator[j2]+num3" 这里不同
- 当运算符个数为3个时,同上,只有str="num1+operator[j1]+num2+operator[j2]+num3+operator[j3]+num4" 这里不同
- 当运算符个数为1个时
-
-
结束并返回for循环开始下一个题目生成
详细代码思路
- ①先创建一个分数类型Fraction:Fraction a = new Fraction(分子,分母)
新建分数如Fraction a = new Fraction(x,y),输入(x,y)=(3,4)将得到 a = 3/4
如果输入(5,1)将得到整数 a = 5,这样分数类型也包含整数了
如果输入假分数(8,5)将得到带分数 a = 1'3/5
/*下面的代码是简略版,只提供思路*/
public class Fraction {
public int molecule; //分子
public int denominator; //分母
//约分处理
public void reduction(){
int x=gcd(molecule,denominator); //最大公因数
molecule /=x; //分子除公因数得最简分子
denominator/=x; //分母除公因数得最简分母
}
//返回分数形式
@Override
public String toString() {
if(isFraction()){ //是分数就返回真分数形式
if(molecule >denominator){ //带分数
return (molecule /denominator)+"’"+ molecule %denominator+"/"+denominator;
}
return molecule +"/"+denominator; //真分数
}
else return ""+ molecule /denominator; //整数 }
//求最大公因数
private static int gcd(int a,int b) {
return (b==0)?a:gcd(b,a%b);
}
- ②创建计算器类Calculator
计算器类可以识别字符串并转化成数值和运算符,然后计算结果
如 String str = "3/10 × 5 + 6 ÷ 1'3/4 =";
answer = calculator(str);//计算字符串答案=12,不能直接answer = str得出答案,因为str的+-×÷是字符不是运算符不能直接计算
/*下面的代码是简略版,只提供思路*/
public class Calculator {
final public static Calculator calculator = new Calculator();
private Stack<Fraction> fractionStack = null;//数字栈,用于存储表达式中的数值
private Stack<Character> operationStack = null;//符号栈,用于存储运算符和括号和带分数号
//解析并计算四则运算表达式,返回计算结果
public Fraction calculate(String numStr) {
fractionStack = new Stack<Fraction>();// 初始化栈
operationStack = new Stack<Character>();
StringBuffer nowFractionNum = new StringBuffer();// 用于缓存数字,因为数字可能是多位的
for (int i = 0; i < numStr.length(); i++) {// 从表达式的第一个字符开始处理
char nowChar = numStr.charAt(i); // 获取一个字符
if (isNumber(nowChar)) { // 若当前字符是数字
nowFractionNum.append(nowChar); // 加入到数字缓存中
} else { // 非数字的情况
String checkFractionNum = nowFractionNum.toString(); // 将数字缓存转为字符串
if (!checkFractionNum.isEmpty()) {
int num = Integer.parseInt(checkFractionNum); // 将数字字符串转为长整型数
fractionStack.push(new Fraction(num)); // 将数字压栈
nowFractionNum = new StringBuffer(); // 重置数字缓存
}
// 取出栈尾运算符进行相应运算,并把结果压栈用于下一次运算
switch (operationStack.pop()) {
case '’': fractionStack.push(Fraction.with(a , b));//处理带分数
break;
case '+': fractionStack.push(Fraction.add(a , b));//处理普通运算符
break;
case '-': fractionStack.push(Fraction.sub(a , b));
break;
case '×': fractionStack.push(Fraction.mul(a , b));
break;
case '/':
case '÷': fractionStack.push(Fraction.div(a , b));
break;
default:
break;
}
if (nowChar != '=') {
operationStack.push(nowChar); // 符号入栈
} } }
return fractionStack.pop(); // 返回计算结果 }
- ③创建题目和答案txt文件
下面代码是题目txt文件,答案文件代码是类似的
QuestionWrite qw = new QuestionWrite();
qw.Write(question);//这样就直接存入txt了
AnswerWrite aw = new AnswerWrite();
aw.Write(answer);
public class QuestionWrite {
static String all="";
static int cnt=1;
public static void save(){
try{
File file = new File("Exercises.txt");
if(!file.exists()){
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(all);
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void Write(String question){
all+=(cnt+". "+question+"\n");
cnt++;
}
}
- ④main函数
/*下面的代码是简略版,只提供思路*/
System.out.println("请输入题目中数值的范围");
int range = scanner.nextInt();
System.out.println("请输入你想生成的题目的数量");
int questionNum = scanner.nextInt();
//用for循环来出题目
for(int i = 0;i<questionNum;i++){
Random r = new Random();
/* 运算符 */
int operatorNum = r.nextInt(3) + 1; //随机生成运算符个数,每次1~3个
char[] operator = {'+','-','×','÷'}; //用字符来表示运算符+-*/
//用operator[j]来随机产生+-×÷
int j1 = r.nextInt(4);//如果j1是1,那第一个运算符operator[j1]是-
int j2 = r.nextInt(4);
int j3 = r.nextInt(4);
/* 数值 */
//至多4个数值,建立4个分数的分子分母(整数可以看成分母为1的分数)
int molecule1 = r.nextInt(range); //第1个分子
int molecule2 = r.nextInt(range);
int molecule3 = r.nextInt(range);
int molecule4 = r.nextInt(range);
int denominator1 = r.nextInt(range)+1; //第1个分母,+1是为了防止为0
int denominator2 = r.nextInt(range)+1;
int denominator3 = r.nextInt(range)+1;
int denominator4 = r.nextInt(range)+1;
//由分子分母生成分数(真分数,带分数,整数)
Fraction num1 = new Fraction(molecule1,denominator1);
Fraction num2 = new Fraction(molecule2,denominator2);
Fraction num3 = new Fraction(molecule3,denominator3);
Fraction num4 = new Fraction(molecule4,denominator4);
/*根据运算符个数的不同开始分类讨论*/
if(operatorNum == 1){ //当运算符数目是1个的时候
//使用字符串输出题目
String question = num1 + " " + operator[j1]+ " " + num2 + " = ";
//除号后面不能是0
if(operator[j1] == '÷' && num2.molecule == 0) {
i--;
continue;
}
//使用计算器算出题目答案
Fraction answer=Calculator.calculator.calculate(question);
//出现负数就重新产生题目
if(answer.molecule < 0 || answer.denominator < 0) {
i--;
continue;
}
//输出题目
System.out.println("题目" + (i+1) + ": " + question);
//题目与答案存入目录文件里
QuestionWrite qw = new QuestionWrite();
qw.Write(question);
AnswerWrite aw = new AnswerWrite();
aw.Write(answer);
}
//运算符为2时,同上,只有str这里不同
if(operatorNum == 2) {
String question = num1 + " " + operator[j1] + " "+ num2 + " " + operator[j2] + " " + num3 + " = ";
}
//运算符为3时,同上,只有str这里不同
if(operatorNum == 2) {
String question = num1 + " " + operator[j1] + " " + num2 + " " + operator[j2] + " " + num3 + " " + operator[j3] + " " + num4 + " = ";
}
3.测试运行
- 输出10个题目
- 题目txt展示
- 答案txt展示
- 输出10000个题目,数值范围100