队友使用Java语言进行编程,并分为三个文件
文件名 | 主要功能 |
---|---|
User.java | 定义user类和用户登录log_in函数 |
Formula.java | createSingleFormula方法生成一个合法算式 |
Main.java | 主函数执行和辅助判断函数 |
User类的设计用户名,用户类型
public class User { private String userName; private String userType; public String getUserName() { return userName; } public String getUserType() { return userType; } public void setUserType(String userType) { this.userType=userType; } }
其中userType用于多个地方,可以确定生成试卷的类型/切换试卷类型/题目难度设置
顶层类设计了登录方法log_in(),其中进行了while判断,并且可以复用该方法
/** * * @Title: LogIn() * @Description: 用户登录,输入账户和密码, 错误时重新登录 * @return void */ public void LogIn() { String inputNameString; String inputPasswordString; Boolean loginSuccessBoolean = false; String path = "users.txt"; System.out.println("-----欢迎来到中小学数学卷子自动生成系统-----"); while (!loginSuccessBoolean) { System.out.println("请输入正确的用户名、密码(中间用空格隔开)"); Scanner scanner = new Scanner(System.in); String[] login_info = scanner.nextLine().split(" "); if (login_info.length != 2) continue; inputNameString = login_info[0]; inputPasswordString = login_info[1]; try (FileReader reader = new FileReader(path); BufferedReader br = new BufferedReader(reader)) { String txt_line; while ((txt_line = br.readLine()) != null) { String[] txt_info = txt_line.split(" "); if (inputNameString.equals(txt_info[0]) && inputPasswordString.equals(txt_info[1])) { System.out.println("当前选择为" + txt_info[2] + "出题"); userName = txt_info[0]; userType = txt_info[2]; loginSuccessBoolean = true; } } } catch (Exception e) { e.printStackTrace(); } } String testType = userType; System.out.println("\n"+"准备生成" + testType + "数学题目,请输入生成题目数量(10-30)(输入-1将退出当前用户,重新登录)"); System.out.println("\n"+"如需模式切换,请输入\"切换为小学\",\"切换为初中\",\"切换为高中\""); }
队友生成合法算式的思路如下:
首先将x个操作数和操作符依次加入List
// 首先将操作数和操作符依次加入res列表 for (int i = 1; i <= oprandNum; i++) { res.add(Integer.toString(rand.nextInt(100) + 1)); if (i != oprandNum) { Integer dice = rand.nextInt(4); res.add(fourOption[dice]); } else res.add("="); }
然后列出2-5个操作数范围内,所有括号可能出现的位置
private Integer[][] bracketPosition = {{0, 2}, {2, 4}, {4, 6}, {0, 4}, {2, 6}, {0, 6}, {2, 8}, {4, 8}, {6, 8}};
在已知操作数个数的情况下,括号可能出现的位置种类是确定的
此时随机选择一组括号加入表达式,并判断括号的合法性,如有交叉,不合法
for (List<Integer> opt : bracketOption) { if (opt.get(1) >= bracketDice[0] && opt.get(1) < bracketDice[1] && opt.get(0) < bracketDice[0]) legal = false; else if (opt.get(1) > bracketDice[1] && opt.get(0) <= bracketDice[1] && opt.get(0) > bracketDice[0]) legal = false; else if (opt.get(1).equals(bracketDice[1]) && opt.get(0).equals(bracketDice[0])) { legal = false; } }
// 判断是否符合初中要求 if (paperType.equals("初中")) { Boolean middleLimit = false; for (int i = 0; i < res.size(); i++) { if (i % 2 == 0 && rand.nextInt(2) == 1) { if (rand.nextInt() % 2 == 0) res.set(i, middleOption[0] + res.get(i)); else res.set(i, res.get(i) + middleOption[1]); middleLimit = true; } } if (!middleLimit) res.set(res.size() - 2, res.get(res.size() - 2) + middleOption[1]); } // 判断是否符合初中要求 if (paperType.equals("高中")) { Boolean highLimit = false; for (int i = 0; i < res.size(); i++) { if (i % 2 == 0 && rand.nextInt(2) == 1) { Integer tri_dice = rand.nextInt(3); res.set(i, highOption[tri_dice] + "(" + res.get(i) + ")"); highLimit = true; } } if (!highLimit) res.set(res.size() - 2, highOption[rand.nextInt(3)] + "(" + res.get(res.size() - 2) + ")"); }
首先要得到该用户文件夹下所有生成的文件,并且储存到Hash
/** * @param * @return HashSet<String> * @Title: getUsedProblem() * @Description: 得到当前用户文件夹下所有题目 */ public static HashSet<String> getUsedProblem(User loginTest) { String path = loginTest.getUserName(); // 获取路径下所有file对象 File file = new File(path); // 遍历path下的文件和目录,放在fs数组中 File[] fs = file.listFiles(); HashSet<String> UsedProblem = new HashSet<String>(); // 将所有算式添加到HashSet<string> for (File f : fs) { if (!f.isDirectory()) { try { BufferedReader br = new BufferedReader(new FileReader(f)); String line; while ((line = br.readLine()) != null) { UsedProblem.add(line); } br.close(); } catch (Exception e) { e.printStackTrace(); } } } return UsedProblem; }
然后主函数的判断中:每生成一个式子,都要和当前文件与之前文件的式子查重
String nowques = formula.createSingleFormula(loginTest); HashSet<String> used = getUsedProblem(loginTest); HashSet<String> now_paper = new HashSet<String>(); while (used.contains(nowques) || now_paper.contains(nowques)) nowques = formula.createSingleFormula(loginTest);
java的内置console类并不能像c++的cmd里直接清屏,需要一些特殊的方法,队友利用了java的机器人来清屏,很有趣。
/** * @return void * @throws AWTException * @Title: clear() * @Description: java机器人类,实现清屏 */ public static void clear() throws AWTException { Robot r = new Robot(); r.mousePress(InputEvent.BUTTON3_MASK); r.mouseRelease(InputEvent.BUTTON3_MASK); r.keyPress(KeyEvent.VK_CONTROL); r.keyPress(KeyEvent.VK_R); r.keyRelease(KeyEvent.VK_R); r.keyRelease(KeyEvent.VK_CONTROL); r.delay(100); }
整体流程还算完整,对于错误输出有一定限制,可以达到脸滚键盘随意输入测试后,程序可以给出引导语而不会崩溃。
用户的需求成功满足;
多个括号嵌套生成并且合法
纠错功能避免溢出,允许用户的非法输入。
程序较为分散,阅读起来函数调用有一点难懂。
if语句太多,代码的复用性不强。