这次写了一个小学生作业生成器,感觉自己才是个小学生。
需求分析
[√] 控制生成题目的个数。
[√] 控制题目中数值(自然数、真分数和真分数分母)的范围。
[√] 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数。
[√] 每道题目中出现的运算符个数不超过3个。
[x] 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。
[√] 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件。
[√] 程序应能支持一万道题目的生成。
[x] 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,并会输出所有题目中重复的题目。
功能设计
生成表达式
计算结果
分数转换
判断对错
生成文件
设计实现
根据功能整个项目由5个类构成:
CreateExpression
负责生成表达式,其中是根据随机数生成算符个数,根据算符个数生成算数个数,根据随机数生成分数或整数,以及通过随机数生成括号及括号位置。
CalculateExpression
负责计算表达式,通过调用js的eval
方法实现直接计算。
resultToFraction
负责将结果转化为分数,通过遍历数值范围平方找到结果,并返回。
JudgeAnswer
负责判断对错,将计算结果与输入结果传入judge
方法判断并显示。
Study
是程序的主方法,其中有文件的读写,对表达式和结果的判断,控制范围输入和题目个数输入。
代码说明
1.生成表达式
public class CreateExpression {
static final char[] operator = { '+', '-', '*', '/' };
public static String createExpression(int range) {
int num = new Random().nextInt(2) + 1;//算符个数
String[] number = new String[num + 1];
char[] op = new char[num];
String expression = "";
int length = number.length;
for (int i = 0; i < num; i++) {
op[i] = operator[(int) (Math.random() * 4)];//生成算符
}
for (int i = 0; i < num + 1; i++) {//生成算数
if (Math.random() > 0.5)//通过随机数生成
number[i] = (int) (Math.random() * range) + "";//整数
else
number[i] = (int) (Math.random() * range) + "/"
+ (int) ((Math.random() * range) + 1) + "";//分数
}
int flag = (int) (Math.random() * 4);//括号生成
switch (flag) {
case 0:
case 1:
for (int i = 0; i < length; i++) {
expression += number[i];
if (i <= length - 2)
if (op[i] != '/'
|| number[i + 1].indexOf("/") != -1
|| (op[i] == '/' && Integer.parseInt(number[i + 1]) != 0))//判断除数非0
expression += op[i];
else {
expression = "";
return null;
}
}
break;
case 2:
if (length > 2) {
for (int i = 0; i < length; i++) {
if (i == 0)
expression += "(";
expression += number[i];
if (i == 1)
expression += ")";
if (i <= length - 2)
if (op[i] != '/'
|| number[i + 1].indexOf("/") != -1
|| (op[i] == '/' && Integer
.parseInt(number[i + 1]) != 0))
expression += op[i];
else {
expression = "";
return null;
}
}
break;
} else {
for (int i = 0; i < length; i++) {
expression += number[i];
if (i <= length - 2)
if (op[i] != '/'
|| number[i + 1].indexOf("/") != -1
|| (op[i] == '/' && Integer
.parseInt(number[i + 1]) != 0))
expression += op[i];
else {
expression = "";
return null;
}
}
break;
}
case 3:
case 4:
if (length > 2) {
for (int i = 0; i < length; i++) {
if (i == 1)
expression += "(";
expression += number[i];
if (i <= length - 2)
if (op[i] != '/'
|| number[i + 1].indexOf("/") != -1
|| (op[i] == '/' && Integer
.parseInt(number[i + 1]) != 0))
expression += op[i];
else {
expression = "";
return null;
}
if (i == 2)
expression += ")";
}
break;
} else {
for (int i = 0; i < length; i++) {
expression += number[i];
if (i <= length - 2)
if (op[i] != '/'
|| number[i + 1].indexOf("/") != -1
|| (op[i] == '/' && Integer
.parseInt(number[i + 1]) != 0))
expression += op[i];
else {
expression = "";
return null;
}
}
}
}
return expression;
}
2.计算表达式
public Object calculate(String expression) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");//调用js引擎
Object result = null;
try {
result = engine.eval(expression);//调用eval方法
if (Double.parseDouble(String.valueOf(result)) < 0) {
return null;
}
} catch (ScriptException e) {
e.printStackTrace();
}
return result;
}
3.分数转换
public String convert(String res, int range) {
String result = null;
String[] array = new String[2];
array = res.split("\\.");
float x, y;
int ext = 0;
Integer b1;
int a = Integer.parseInt(array[0]);// 获取整数部分
String str_b = String.valueOf(array[1]);// 获取小数部分且判断0个数
for (int i = 0; i < str_b.length() && str_b.charAt(i) == '0'; i++) {
ext = i + 1;
}
int b = Integer.parseInt(str_b);
if (b == 0) {
result = a + "";
} else {
b1 = b;
x = (float) (b / (Math.pow(10, b1.toString().length() + ext)));//将小数点后转化成float型
for (int i = 1; i <= range * range; i++) {//遍历
for (int j = i; j <= range * range; j++) {
y = (float) i / (float) j;
if (y == x)
if (a == 0) {
result = i + "/" + j + "";
return result;
} else {
result = a + "'" + i + "/" + j + "";
return result;
}
else
continue;
}
}
}
return result;
}
4.判断结果
public void judge(String[] s1, String[] s2) {
int correctnum = 0;
int length = s1.length;
int[] correct = new int[length];
int[] wrong = new int[length];
for (int i = 0; i < length; i++) {
if (s1[i].equals(s2[i])) {
correct[correctnum] = i + 1;//记录正确结果题目号
correctnum++;//记录正确结果个数
} else {
wrong[i - correctnum] = i + 1;//错误结果题目号
}
}
//打印结果
System.out.print("Correct:" + correctnum);
for (int i = 0; i < correctnum; i++) {
if (i == 0)
System.out.print("( ");
if (i < correctnum - 1)
System.out.print(correct[i] + " , ");
else
System.out.print(correct[i] + " )");
}
System.out.print("Wrong:" + (length - correctnum));
for (int i = 0; i < length - correctnum; i++) {
if (i == 0)
System.out.print("( ");
if (i < length - correctnum - 1)
System.out.print(wrong[i] + " , ");
else
System.out.println(wrong[i] + " )");
}
}
5.主方法
public static void start() throws IOException {
Scanner sc = new Scanner(System.in);
int loopnum = 0, range;
System.out.println("输入题目文件名称");
File questionFile = new File(sc.next());
while (questionFile.exists()) {
System.out.println("文件已存在,请重新输入");
questionFile = new File(sc.next());
}
FileWriter q_writer = new FileWriter(questionFile, true);
System.out.println("输入文件答案名称");
File answerFile = new File(sc.next());
while (answerFile.exists()) {
System.out.println("文件已存在,请重新输入");
answerFile = new File(sc.next());
}
FileWriter a_writer = new FileWriter(answerFile, true);
System.out.println("输入题目个数");
loopnum = sc.nextInt();
System.out.println("输入数值范围");
range = sc.nextInt();
String[] i_anwser = new String[loopnum];
String[] q_anwser = new String[loopnum];
//开始生成
for (int i = 0; i < loopnum; i++) {
CreateExpression cte = new CreateExpression();
String expression = cte.createExpression(range);
Object result = null;
//判断表达式是否可用
if (expression != null && !expression.equals(null)) {
CalculateExpression cce = new CalculateExpression();
result = cce.calculate(expression);
//判断结果是否可用
if (result == null || result.toString().equals("Infinity") || result.toString().equals("NaN")) {
i--;
continue;
} else {
resultToFraction rtf = new resultToFraction();
String n_result = rtf.convert(String.valueOf(Float.parseFloat(result.toString())), range);//将结果转化成有限小数
System.out.println(expression);
q_writer.write(i + "." + expression);
a_writer.write(i + "." + n_result);
q_anwser[i] = n_result;
}
} else {
i--;
}
}
System.out.println("输入答案");
for (int i = 0; i < loopnum; i++) {
i_anwser[i] = sc.next();
}
JudgeAnswer jda = new JudgeAnswer();
jda.judge(q_anwser, i_anwser);
}
测试运行
1.控制台
2.生成文件
PSP
PSP2.1 | Personal Software Process Stages | Time Senior Student | Time |
---|---|---|---|
Planning | 计划 | 20 | 20 |
Estimate | 估计这个任务需要多少时间 | 5 | 5 |
Development | 开发 | 500 | 700 |
Analysis | 需求分析 (包括学习新技术) | 30 | 10 |
Design Spec | 生成设计文档 | 5 | 1 |
Design Review | 设计复审 | 2 | 1 |
Coding Standard | 代码规范 | 1 | 1 |
Design | 具体设计 | 20 | 30 |
Coding | 具体编码 | 400 | 470 |
Code Review | 代码复审 | 10 | 8 |
Test | 测试(自我测试,修改代码,提交修改) | 60 | 150 |
Reporting | 报告 | 20 | 60 |
测试报告 | 12 | 45 | |
计算工作量 | 3 | 5 | |
并提出过程改进计划 | 8 | 10 |
小结
那个判重算法真的不太懂。。
要把小学生逼疯就要先把自己逼疯。
不过做你的一万道题去吧:)