小学生题目生成器

这次写了一个小学生作业生成器,感觉自己才是个小学生

需求分析

[√] 控制生成题目的个数。
[√] 控制题目中数值(自然数、真分数和真分数分母)的范围。
[√] 生成的题目中如果存在形如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

小结
那个判重算法真的不太懂。。
要把小学生逼疯就要先把自己逼疯。
不过做你的一万道题去吧:)


项目地址>>
posted @ 2017-09-19 15:18  Symumi  阅读(787)  评论(3编辑  收藏  举报