HNU_结对编程队友ljq代码分析

结对编程队友代码分析

一、整体思路

队友使用Java语言进行编程,并分为三个文件

文件名 主要功能
User.java 定义user类和用户登录log_in函数
Formula.java createSingleFormula方法生成一个合法算式
Main.java 主函数执行和辅助判断函数

二、重要的代码实现

1.顶层类设计

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"+"如需模式切换,请输入\"切换为小学\",\"切换为初中\",\"切换为高中\"");
    }

2.生成合法算式

队友生成合法算式的思路如下:

首先将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;
    }
}

3.满足初高中题目要求

// 判断是否符合初中要求
        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) + ")");
        }

4.多文件去重和单文件去重

首先要得到该用户文件夹下所有生成的文件,并且储存到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);

5.Java的工具清屏类

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);
    }

三.程序运行实际情况

整体流程还算完整,对于错误输出有一定限制,可以达到脸滚键盘随意输入测试后,程序可以给出引导语而不会崩溃。

四.优缺点

1.优点

用户的需求成功满足;

多个括号嵌套生成并且合法

纠错功能避免溢出,允许用户的非法输入。

2.缺点

程序较为分散,阅读起来函数调用有一点难懂。

if语句太多,代码的复用性不强。

posted @ 2022-09-14 00:48  Leftovers  阅读(305)  评论(0编辑  收藏  举报