标签:file ati director imp 成员 随机 保存 文件的 括号
一 . 项目介绍
项目成员:黄梓垲 蔡海杰
项目仓库:github
二. PSP表格
三. 项目功能
由界面输入参数,实现了题目的生成以及去重,问题与答案的文件保存,用户输入答案文件与标准答案的校对以及结果文件生成
运行示例(Answerfile.txt为用户提交文件):
四. 项目分析与代码设计
1. 由于题目设计真分数运算,所以采用分数作为基本的运算单位。使用ExpressionResult类保存每条表达式以及它的运算结果
public class Fraction {
//分子
private Integer numerator;
//分母
private Integer denominator;
//取最大公因数化简
public Fraction(Integer n, Integer d) {
Integer GCD = Calculator.GCD(n, d);
this.numerator = n /= GCD;
this.denominator = d /= GCD;
}
//重写toString方法,以真分数形式表示
@Override
public String toString() {
if (this.numerator > this.denominator && this.denominator != 1 && this.getNumerator() > 0 && this.getDenominator() > 0) {
int num = numerator / denominator;
return num + "‘" + numerator % denominator + "/" + denominator;
} else if (denominator == 1) {
return numerator.toString();
} else return numerator + "/" + denominator;
}
}
public class ExpressionResult {
private String expression;
private String result;
@Override
public String toString() {
return expression+"="+result;
}
}
2. 很多人采用二叉树生成表达式或者中缀转后缀表达式的思路,我则是直接进行表达式的生成与计算,在生成表达式时采用HashSet无法重复的特性来存放表达式达到去重的目的
//表达式的生成,采用HashSet存放表达式,直接去重,可以免去后续检测是否重复
public static HashSet generateExpression(Integer r, Integer n) {
HashSet expressionResultHashSet = new HashSet();
for (int i = 0; i ) {
//生成第一个操作符和操作数,在后面计算中使用firstNum存放计算的结果
char firstOps = GeneratorUtil.getOperator();
Fraction firstNum = GeneratorUtil.getFraction(n);
char secondOps = firstOps;
Fraction secondNum = firstNum;
ExpressionResult expressionResult = new ExpressionResult();
StringBuilder expression = new StringBuilder().append(firstNum);
//生成后续两个操作符并进行表达式的拼接
for (int j = 0; j ) {
//获取第二个操作数
secondNum = GeneratorUtil.getFraction(n);
switch (secondOps) {
//加法则直接进行拼接,不需要额外操作
case ‘+‘:
//将当前运算符保存,后面在优先级比较中会使用到(下同)
firstOps = secondOps;
expression.append(secondOps).append(secondNum);
//保存运算的中间结果(下同)
firstNum = Calculator.ADD(firstNum, secondNum);
//获取下一个操作符(下同)
secondOps = GeneratorUtil.getOperator();
break;
case ‘-‘:
firstOps = secondOps;
//由于不能产生负数,所以在减法时要进行比较,如果前数小于后数则将表达式倒置拼接
if (Calculator.CMP(firstNum, secondNum)) {
firstNum = Calculator.SUB(firstNum, secondNum);
expression.append(secondOps).append(secondNum);
} else {
expression = new StringBuilder().append(secondNum).append(secondOps).append(expression);
firstNum = Calculator.SUB(secondNum, firstNum);
}
secondOps = GeneratorUtil.getOperator();
break;
case ‘ב:
//乘法优先级大,在这里判断前面是否有优先级较小的加减操作,有的话将表达式带上括号再拼接乘法运算
if (firstOps == ‘+‘ || firstOps == ‘-‘) {
expression = new StringBuilder().append("(").append(expression).append(")").append(secondOps).append(secondNum);
} else {
expression.append(secondOps).append(secondNum);
}
//保存运算结果
firstNum = Calculator.MUL(firstNum, secondNum);
firstOps = secondOps;
secondOps = GeneratorUtil.getOperator();
break;
case ‘÷‘:
//除法优先级大,在这里判断前面是否有优先级较小的加减操作,有的话将表达式带上括号再拼接乘法运算
if (firstOps == ‘+‘ || firstOps == ‘-‘) {
expression = new StringBuilder().append("(").append(expression).append(")").append(secondOps).append(secondNum);
firstNum = Calculator.DIV(secondNum, firstNum);
} else {
expression.append(secondOps).append(secondNum);
firstNum = Calculator.DIV(firstNum, secondNum);
}
firstOps = secondOps;
secondOps = GeneratorUtil.getOperator();
break;
}
}
//将表达式和结果保存,放进HashSet
expressionResult.setExpression(expression.toString());
expressionResult.setResult(firstNum.toString());
expressionResultHashSet.add(expressionResult);
}
return expressionResultHashSet;
}
3. 随机数和操作符的获取
public class GeneratorUtil {
private static final char OPERATORS[] = {‘+‘, ‘-‘, ‘ב, ‘÷‘};
private static final Random R = new Random();
public static Fraction getFraction(int maximum) {
//调整随机数为整数或者分数
boolean isFraction = R.nextBoolean();
return isFraction ? new Fraction(R.nextInt(maximum) + 1, R.nextInt(maximum) + 1) : new Fraction(R.nextInt(maximum) + 1, 1);
}
public static char getOperator() {
return OPERATORS[R.nextInt(4)];
}
}
4. 分数的运算操作
public class Calculator {
/**
* 化简
*/
public static Integer simplify(Integer numerator, Integer denominator) {
if (denominator == 0) return numerator;
return numerator % denominator == 0 ? denominator : simplify(denominator, numerator % denominator);
}
//相加
public static Fraction ADD(Fraction first, Fraction second) {
return new Fraction(first.getNumerator() * second.getDenominator() + first.getDenominator() * second.getNumerator(),
first.getDenominator() * second.getDenominator());
}
//相减
public static Fraction SUB(Fraction first, Fraction second) {
return new Fraction(first.getNumerator() * second.getDenominator() - first.getDenominator() * second.getNumerator(), first.getDenominator() * second.getDenominator());
}
//相乘
public static Fraction MUL(Fraction first, Fraction second) {
return new Fraction(first.getNumerator() * second.getNumerator(), first.getDenominator() * second.getDenominator());
}
//相除
public static Fraction DIV(Fraction first, Fraction second) {
return MUL(first, Countdown(second));
}
//取倒
public static Fraction Countdown(Fraction fraction) {
return new Fraction(fraction.getDenominator(), fraction.getNumerator());
}
//比较大小
public static boolean CMP(Fraction first, Fraction second) {
Fraction result = DIV(first, second);
return result.getNumerator() > result.getDenominator() && result.getNumerator() > 0 ? true : false;
}
//获取最大公因数并约去(辗转相除法)
public static int GCD(int a, int b) {
if (b == 0) return a;
return a % b == 0 ? b : GCD(b, a % b);
}
}
5. 题目、答案文件和答案比对结果文件的生成
public static void generateFile(HashSet expressionResultHashSet) throws IOException {
File questionFile = new File("Exercises.txt");
File answerFile = new File("Answers.txt");
if (!questionFile.exists()) {
questionFile.createNewFile();
}
if (!answerFile.createNewFile()) {
answerFile.createNewFile();
}
try (BufferedWriter abw = new BufferedWriter(new FileWriter(answerFile));
BufferedWriter qbw = new BufferedWriter(new FileWriter(questionFile))) {
int count = 1;
for (ExpressionResult e : expressionResultHashSet) {
try {
qbw.write(count + "." + e.getExpression());
qbw.newLine();
abw.write(count + "." + e.getResult());
abw.newLine();
//将表达式放入队列,在监听线程中拼接到界面中去
GuiForOperator.queue.add(count + "." + e.getExpression() + "=" + e.getResult());
count++;
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
public static void CompareAnswers(File answerFile) throws IOException {
List correctList = new ArrayList();
List wrongList = new ArrayList();
try (BufferedReader qrAnswer = new BufferedReader(new FileReader(answerFile));
BufferedReader qrExercise = new BufferedReader(new FileReader("Answers.txt"))) {
String eStr = null;
String aStr = null;
while ((eStr = qrExercise.readLine()) != null && (aStr = qrAnswer.readLine()) != null) {
String orderNum = eStr.substring(0, eStr.indexOf("."));
String standardAnswer = aStr.substring(2, aStr.length());
String submitAnswer = eStr.substring(2, eStr.length());
if (standardAnswer.equals(submitAnswer)) {
correctList.add(orderNum);
} else {
wrongList.add(orderNum);
}
}
}
File gradeFile = new File("Grade.txt");
if (!gradeFile.exists()) {
gradeFile.createNewFile();
}
try (BufferedWriter bw = new BufferedWriter(new FileWriter(gradeFile))) {
StringBuilder correctStr = new StringBuilder().append("Correct: ").append(correctList.size()).append(" (");
StringBuilder wrongStr = new StringBuilder().append("Wrong: ").append(wrongList.size()).append(" (");
correctList.forEach((e) -> {
correctStr.append(e + ",");
});
wrongList.forEach((e) -> {
wrongStr.append(e + ",");
});
bw.write(correctStr.toString().substring(0, correctStr.lastIndexOf(",")) + ")");
bw.newLine();
if (wrongList.size() != 0) {
bw.write(wrongStr.toString().substring(0, wrongStr.lastIndexOf(",")) + ")");
} else {
bw.write(wrongStr.append(")").toString());
}
//将比对结果放入队列,在监听线程中拼接到界面中去
GuiForOperator.queue.add(correctStr.toString().substring(0, correctStr.lastIndexOf(",")) + ")");
GuiForOperator.queue.add(wrongStr.toString().substring(0, wrongStr.lastIndexOf(",")) + ")");
}
}
6. 界面:包括传入参数、文件以及结果显示
public class GuiForOperator extends JFrame {
// 使用队列存放表达式,起线程监听,有则取出并显示
public static BlockingQueue queue = new LinkedBlockingQueue();
private JPanel contentPane;
private JTextField textField;
private JTextField textField_1;
public JTextArea textArea;
public JScrollPane scrollPane;
/**
* Create the frame.
*/
public GuiForOperator() {
setTitle("\u56DB\u5219\u8FD0\u7B97");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 706, 495);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel label = new JLabel("\u9898\u76EE\u6570\u91CF\uFF1A");
label.setBounds(55, 43, 76, 18);
contentPane.add(label);
textField = new JTextField();
textField.setBounds(163, 35, 282, 35);
contentPane.add(textField);
textField.setColumns(10);
JLabel label_1 = new JLabel("\u6700\u5927\u968F\u673A\u6570\uFF1A");
label_1.setBounds(55, 91, 125, 18);
contentPane.add(label_1);
textField_1 = new JTextField();
textField_1.setBounds(163, 83, 282, 35);
contentPane.add(textField_1);
textField_1.setColumns(10);
scrollPane = new JScrollPane(textArea);
textArea = new JTextArea();
textArea.setEditable(false);
textArea.setBounds(55, 167, 591, 255);
textArea.setLineWrap(true);
scrollPane.setBounds(55, 167, 591, 255);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
contentPane.add(scrollPane);
scrollPane.setViewportView(textArea);
JButton button = new JButton("\u786E\u5B9A");
button.addActionListener(e -> {
String r = textField.getText();
String n = textField_1.getText();
textArea.setText("");
try {
//传入参数生成表达式写入文件
HashSet expressionResults = Generator.generateExpression(Integer.valueOf(r), Integer.valueOf(n));
Generator.generateFile(expressionResults);
} catch (IOException e1) {
e1.printStackTrace();
}
});
button.setBounds(533, 87, 113, 27);
contentPane.add(button);
JButton btnNewButton = new JButton("选择文件");
btnNewButton.addActionListener(arg0 -> {
JFileChooser jfc = new JFileChooser();
jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
jfc.showDialog(new JLabel(), "选择");
File file = jfc.getSelectedFile();//得到文件
if (file.isDirectory()) {
System.out.println("文件夹:" + file.getAbsolutePath());
} else if (file.isFile()) {
System.out.println("文件:" + file.getAbsolutePath());
}
try {
//传入比对文件
Generator.CompareAnswers(file);
} catch (IOException e) {
e.printStackTrace();
}
});
btnNewButton.setBounds(533, 39, 113, 27);
contentPane.add(btnNewButton);
}
7. 程序入口
public class AppEntry {
public static void main(String[] args) {
//新建窗口并显示
GuiForOperator frame = new GuiForOperator();
frame.setVisible(true);
//启动线程监听队列取出表达式进行显示
new Thread(() -> {
while (true) {
try {
String expression = GuiForOperator.queue.take();
if (expression != null) {
frame.textArea.append(expression + "\r\n");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
五. 运行耗时
生成一万道题目,数值在一万以内;生成十万道题目,数值在十万以内;生成一百万道题目,数值在一百万以内;
基于Java实现的四则运算程序
标签:file ati director imp 成员 随机 保存 文件的 括号
原文地址:https://www.cnblogs.com/hzkkk/p/9727038.html