这篇文章是我的结对编程搭档刘正豪——豪神的个人项目代码的总结评价。
豪神使用Java语言实现中小学数学卷子自动生成程序的预期功能,代码结构清晰,其中的某些函数不乏亮点。
账户类型 | 用户名 | 密码 |
---|---|---|
小学 | 张三1 | 123 |
小学 | 张三2 | 123 |
小学 | 张三3 | 123 |
初中 | 李四1 | 123 |
初中 | 李四2 | 123 |
初中 | 李四3 | 123 |
高中 | 王五1 | 123 |
高中 | 王五2 | 123 |
高中 | 王五3 | 123 |
小学 | 初中 | 高中 | |
---|---|---|---|
难度要求 | +,-,*./ | 平方、开方 | sin,cos,tan |
备注 | 只能有+,-,*./和() | 题目中至少有一个平方或开根号的运算符 | 题目中至少有一个sin,cos或tan的运算符 |
由于代码全部复制过来太多,只说几个关键的。
public class User { private String id; private String psw; private String type; private boolean convert; @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } User user = (User) o; return id.equals(user.id) && psw.equals(user.psw); } @Override public int hashCode() { return Objects.hash(id, psw); } }
成员属性有4个,convert用于判断后续的是否重新登录的判断。
equals()函数用于登录时的判断
hashCode()函数用于后续查重
剩余的代码都写在了Login里面,由于代码量较大,只展示其中几个关键的函数:
private void paper(int cnt,User u) throws IOException { Random r = new Random(); String[] specialSigns = {"?","√","sin","cos","tan"}; HashSet<String> hisQ = historyPaper(u); String path = "F:\\4\\Auto_Math\\out\\production\\Mathpaper\\" + u.getId() + "/"; Calendar date = Calendar.getInstance(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); String time = formatter.format(date.getTime()); path = path + time + ".txt"; //生成题目 FileWriter fw = new FileWriter(path,true); for(int i = 0;i < cnt;i++){ String question; //生成单个题目 question = singleQuestion(u, r, specialSigns); //查询是否与历史题目重复 if(hisQ.contains(question)){ i--; continue; } question = "第" + (i + 1) + "题: " + question + "="; fw.write(question+"\r\n"); } fw.close(); }
本次的关键是生成题目,先生成路径后生成题目,生成单个题目之后进行查重,最后输出到文件里,思路清晰,代码简洁。
private String singleQuestion(User u, Random r, String[] specialSigns) { String[] signs = {"+","-","×","÷"}; String question = null; String[] opQ = null; String type= u.getType(); switch (type){ case "小学" -> { int opNum = r.nextInt(4) + 2; opQ = new String[opNum]; for(int i = 0;i < opNum;i++){ opQ[i] = String.valueOf(r.nextInt(100) + 1); } //括号 addBracket(r, opQ, opNum); } case "初中" -> { int opNum = r.nextInt(5) + 1; opQ = new String[opNum]; for(int i = 0;i < opNum;i++){ opQ[i] = String.valueOf(r.nextInt(100) + 1); } //特殊符号数 int sopNum = r.nextInt(opNum) + 1; while((sopNum--) != 0){ int rPos = r.nextInt(opNum); if(!opQ[rPos].contains("?") && !opQ[rPos].contains("√")){ opQ[rPos]= r.nextBoolean()? opQ[rPos]+"?": "√"+opQ[rPos]; } } addBracket(r, opQ, opNum); } case "高中" -> { int opNum = r.nextInt(5) + 1; opQ = new String[opNum]; for(int i = 0;i < opNum;i++){ opQ[i] = String.valueOf(r.nextInt(100) + 1); } //特殊符号数 int sopNum = r.nextInt(opNum) + 1; boolean[] speOpFlag = new boolean[opNum]; //确保至少有一个三角函数 int tri = 0; while((sopNum--) != 0){ int rPos = r.nextInt(opNum); if(tri == 0 && !opQ[rPos].contains("sin") && !opQ[rPos].contains("cos") && !opQ[rPos].contains("tan")){ opQ[rPos] = specialSigns[r.nextInt(3)+2] + opQ[rPos]; tri++; speOpFlag[rPos] = true; } if(!speOpFlag[rPos]){ int rOp = r.nextInt(5); opQ[rPos] = rOp < 1 ? opQ[rPos] + specialSigns[rOp] : specialSigns[rOp] + opQ[rPos]; speOpFlag[rPos] = true; } } addBracket(r, opQ, opNum); } default -> System.out.println("error"); } assert opQ != null; for(int i = 0;i < opQ.length ;i++){ int opType = r.nextInt(4); question = (question == null?"":question) + (i!=0?signs[opType]:"") + opQ[i]; } return question; }
这是生成单个题目的函数,分为三类来进行。逻辑基本是差不多的,先通过随机数生成几个操作数,之后再利用循环判断添加操作符。
private void addBracket(Random r, String[] opQ, int opNum) { boolean bracket = r.nextBoolean() && opNum > 2; if(bracket){ int range = r.nextInt(opNum - 2) + 1; int left = r.nextInt(opNum - range); opQ[left] = "(" + opQ[left]; opQ[left+range] = opQ[left+range] + ")"; } }
括号是在算式最后添加的,通过随机数来确定位置。
private HashSet<String> historyPaper(User u) throws IOException { HashSet<String> hisQuestions = new HashSet<>(); String path = "F:\\4\\Auto_Math\\out\\production\\Mathpaper" + "\\" + u.getId(); File folder = new File(path); if(!folder.exists()){ folder.mkdir(); } File[] fList = folder.listFiles(); assert fList != null; for(File f : fList){ if (f.isFile() && f.getName().endsWith(".txt")){ BufferedReader br = new BufferedReader(new FileReader(f)); String s; while((s = br.readLine()) != null){ hisQuestions.add(s); } br.close(); } } return hisQuestions; }
对于题目查重,豪神采用了哈希表,将同一用户名文件夹下的题目导入哈希表中,挨个查询,这样做大大节省了查询的复杂度,好评!
Java还是非常好用的,要今后多学习Java的使用,很多都封装好了可以直接拿来用,不需要我再写了。多看看其他人的代码一方面可以让我学到更多的编程思路,学习其他人的切入点,另一方面通过检查他人代码的缺陷,我也能反省自身,不再犯类似的错误。