Proyecto emparejado (con interfaz gráfica de usuario) Implementación de Java [Chai Zheng-Chen Qiting]

1. Introducción

  • Este proyecto es un programa que puede generar automáticamente cuatro preguntas y respuestas aritméticas para estudiantes de primaria y puede corregir las preguntas y los archivos de respuestas.
  • Dirección de GitHub: https://github.com/softwareCQT/cz_cqt/tree/master/src/com/czAcqt
  • Nota: La versión de consola del programa se puede ejecutar directamente haciendo clic en el archivo .exe; el programa de interfaz gráfica de usuario debe ejecutar el paquete jar (out / artifacts / arithmetic_jar / arithmetic.jar) a través de la línea de comandos para ejecutarse.
  • Par de proyectos: Chai Zheng, Chen Qi Ting (clase obrera suave)

2. Formulario de PSP

PSP2.1 Etapas del proceso de software personal Tiempo estimado (minutos) Tiempo real (minutos)
Planificación Plan 1200 1680
· Estimación · Estime cuánto tiempo llevará esta tarea 1200 1680
Desarrollo Desarrollo 1000 1540
· Análisis · Análisis de necesidades (incluido el aprendizaje de nuevas tecnologías) 120 240
· Especificaciones de diseño · Generar documentos de diseño. 30 40
· Revisión de diseño · Revisión de diseño (revisión de documentos de diseño con colegas) 20 30
· Estándar de codificación · Especificaciones de código (haciendo especificaciones apropiadas para el desarrollo actual) 30 10
· Diseño · Diseño específico 30 70
· Codificación · Codificación específica 600 1000
· Revisión de código · Revisión de código 100 120
· Prueba · Prueba (autocomprobación, modificar código, enviar cambios) 70 30
Informes Informe 80 90
· Informe de prueba · Informe de prueba 30 20
· Medida del tamaño · Calcular la carga de trabajo 20 30
· Plan de mejora de procesos y autopsias · Resumen luego, y proponer un plan de mejora de procesos 30 40
Total 1400 1680

3. Descripción del título

Número de pregunta y requisitos del operador:

  • Puntajes verdaderos: 1/2, 1/3, 2/3, 1/4, 1'1 / 2,….
  • Números naturales: 0, 1, 2, ...
  • Operadores: +, -, ×, ÷.
  • Soportes: (,).
  • Signo igual: =.
  • Separador: espacio (usado antes y después de los cuatro operadores y el signo igual).
  • Expresión aritmética:

    e = n | e1 + e2 | e1 - e2 | e1 × e2 | e1 ÷ e2 | (e)

    Donde e, e1 y e2 son expresiones, yn es un número natural o fracción verdadera.

  • Cuatro problemas aritméticos: e =, donde e es una expresión aritmética.

El proceso de operación específico y el formato de las preguntas generadas:

  • Use el parámetro -n para controlar el número de preguntas generadas, por ejemplo: Myapp.exe -n 10 generará 10 preguntas.

  • Use el parámetro -r para controlar el rango de valores numéricos (números naturales, fracciones verdaderas y denominadores de fracciones verdaderas) en la pregunta, por ejemplo: Myapp.exe -r 10 generará cuatro preguntas aritméticas dentro de 10 (excluyendo 10). Este parámetro se puede establecer en 1 u otros números naturales. Se debe proporcionar este parámetro; de lo contrario, el programa informa un error y proporciona información de ayuda.

  • En el problema generado, el proceso de cálculo no puede producir números negativos, es decir, si hay una subexpresión de la forma e1 − e2 en la expresión aritmética, entonces e1≥ e2.

  • Si hay una subexpresión de la forma e1 ÷ e2 en la pregunta generada, el resultado debería ser una fracción verdadera.

  • El número de operadores que aparecen en cada pregunta no excede de 3.

  • Las preguntas generadas por el programa en una ejecución no pueden repetirse, es decir, dos preguntas no pueden transformarse en la misma pregunta mediante un número limitado de intercambios de expresiones aritméticas sobre + y ×. Por ejemplo, 23 + 45 = y 45 + 23 = son preguntas repetidas, y 6 × 8 = y 8 × 6 = también son preguntas repetidas. Las dos preguntas 3+ (2 + 1) y 1 + 2 + 3 son repetitivas, ya que + está asociado a la izquierda, 1 + 2 + 3 es equivalente a (1 + 2) +3, que es 3+ (1 +2), que es 3+ (2 + 1). Pero 1 + 2 + 3 y 3 + 2 + 1 son dos preguntas que no se repiten, porque 1 + 2 + 3 es equivalente a (1 + 2) +3, y 3 + 2 + 1 es equivalente a (3 + 2 ) +1, no pueden convertirse en el mismo problema a través de un número limitado de intercambios.

  • Las preguntas generadas se almacenan en el archivo Exercises.txt en el directorio actual del programa de ejecución en el siguiente formato:

    1. Cuatro problemas aritméticos 1
    2. Cuatro problemas aritméticos 2
         ...

 Entre ellos, el puntaje verdadero está en el siguiente formato cuando se ingresa y sale: el puntaje verdadero de tres quintos se expresa como 3/5, y el puntaje verdadero de dos y octavos se expresa como 2'3 / 8.

  • Mientras genera las preguntas, calcule las respuestas a todas las preguntas y guárdelas en el archivo Answers.txt en el directorio actual del programa en ejecución, en el siguiente formato:

    1. Respuesta 1
    2. Respuesta 2
    ...

  • El cálculo de la puntuación real se muestra en el siguiente ejemplo: 1/6 + 1/8 = 7/24.

  • El programa debería ser capaz de soportar la generación de 10,000 preguntas.

  • El programa admite el archivo de preguntas y el archivo de respuestas dados para determinar lo correcto y lo incorrecto en la respuesta y para contar el número. Los parámetros de entrada son los siguientes:

  Myapp.exe -e .txt -a Los resultados estadísticos .txt se envían al archivo Grade.txt en el siguiente formato:

    Correcto: 5 (1, 3, 5, 7, 9)

    Incorrecto: 5 (2, 4, 6, 8, 10)

  El número 5 después de ":" indica el número de preguntas correctas / incorrectas, y el número de preguntas correctas / incorrectas está entre paréntesis. En aras de la simplicidad, se supone que las preguntas de entrada son todas preguntas numeradas que cumplen con las especificaciones.

4. Análisis de efectividad

  • La recuperación de cuatro expresiones normalizadas requiere mucho tiempo para pensar;
  • Para el cálculo de expresiones, la expresión de infijo se convierte en una expresión de sufijo y se procesa a través de la estructura de almacenamiento de la pila;
  • Para la deduplicación de expresiones, se adopta el método de deduplicación de "cuando cada número es el mismo, el símbolo es el mismo y el resultado es el mismo en la misma fórmula de cálculo" como método de deduplicación.
  • El programa tarda más tiempo en guardar, por lo que cada vez que los datos a guardar se ensamblan en un archivo y se escriben en un archivo, lo que mejora la eficiencia.

Cinco, ideas de diseño y experiencia en procesos de diseño

5.1 Segmentación de arquitectura

  • El primer análisis de diseño :
  • Proceso de diseño final :

5.2 División del trabajo

  • Clase :
    • Análisis de comando : CommandAnalyze ----- Chai Zheng
    • Generación de expresiones : Expresión ----- Qiting
    • Cálculo de expresión : Calcular ----- Qiting
    • Comprobación de respuesta : AnswerChecking ----- Chai Zheng
    • Almacenamiento de datos : almacenamiento de datos ----- Chai Zheng
    • Tipo de gráfico : Gráfico ----- Chai Zheng
  • Interfaz :
    • Cálculo y generación : CalculateGenerate ----
  • Clase de enumeración :
    • Operador : Símbolo ---- Citando

5.2 Ideas para generar preguntas y calcular preguntas

  • Generación de números : el diseño se divide en dos tipos: entero y fracción. En el proceso de generación de fracciones, se busca si hay un denominador de 0 o un numerador de cero, y se genera iterativamente.

  • Generación de símbolos : mi diseño es que los operadores y los corchetes están separados. El operador se genera con una probabilidad de 1/4, y los corchetes que elijo para seleccionar aleatoriamente una posición específica de la expresión para la inserción.

  • División : las medidas que tomé se dividieron entre números y símbolos con espacios, que solo satisfacían las necesidades del proyecto

  • Cálculo y deduplicación de la pregunta: la deduplicación y el cálculo de la pregunta se sincronizan. Al calcular la pregunta y la respuesta calculada y la pregunta y la respuesta almacenadas, la respuesta de búsqueda es coherente y luego determina el tipo de símbolo y el formato de número para determinar si la pregunta se repite. Doble protección. El cálculo consiste en convertir la expresión generada en una expresión de sufijo para obtener el resultado. Esto es simple y no se extiende. El pseudocódigo de deduplicación es el siguiente :

    if (容器存在一毛一样的表达式){
    	重新生成表达式
    }
    if (容器里存在一毛一样的结果){
        if (判断数字类型、符号是否完全符合,判断顺序是否有变换){
            重新生成表达式
        }
    }
    
  • El proceso de generar números negativos en el proceso de operación : durante el proceso de cálculo, cuando se encuentra el resultado de generar un número negativo, la expresión se devuelve directamente y luego se regenera una nueva expresión.

5.3 Almacenamiento de preguntas y respuestas e ideas para verificación

  • ** Almacene expresiones y respuestas: Convierta las listas de expresiones y respuestas en cadenas y escríbalas en el archivo línea por línea con la secuencia del búfer. Tenga en cuenta que el índice de control y la codificación están configurados en "UTF-8" para garantizar que no haya caracteres ilegibles.
  • ** Corrección de las respuestas del usuario: Primero, juzgue el archivo de preguntas especificado y el archivo de respuestas a verificar. Si el archivo de preguntas es un archivo generado por el sistema, se llama al archivo de respuestas correspondiente al número de versión para corregir el archivo de respuestas del usuario; si el archivo de preguntas Si se trata de un archivo nuevo, llame a la función de cálculo del programa para obtener la Lista de respuestas con las respuestas correctas, y use esta Lista de respuestas para corregir la respuesta que se verificará. Guarde la información de revisión como correctList y wrongList en el archivo Grade.txt.

5.3 Problemas encontrados en el proceso de codificación

  • Chen Qiting: es principalmente vago, y mi cerebro es estúpido. No me concentro en la codificación, por lo que pierdo mucho tiempo. Todo el diseño no es difícil. Algunos algoritmos tienen sus propias ideas. .
    (Al principio fue difícil, y de repente sentí que estaba terminado)
  • Chai Zheng: La corte es muy perezosa. Esto se puede vislumbrar a partir del resumen de mis problemas con él y, por supuesto, también desde un lado muestra la habilidad de Qi Ting en la redacción de proyectos y el uso de estructuras de datos.
    Después de la división del trabajo para resolver la clase de comando de usuario y la clase de datos de almacenamiento, casi se terminó en una noche. Más tarde, encontré los siguientes problemas:
    1. Cuando el proyecto atracó por primera vez, se decidió cambiar el tipo del parámetro de transferencia ([Mapa]: clave: título, valor: respuesta --- cambiar ---> [Lista]: título, [lista]: respuesta);
    2. Se descubrió que la función de verificar la respuesta se ignoraba al analizar los requisitos por primera vez, por lo que tardó un día en modificar y mejorar ;
    3. Al atracar nuevamente, el tribunal señaló muchas irregularidades en el código. Después de recordarlo, se modificaron los derechos de acceso de algunos métodos y el alcance de las variables, lo que aumentó la seguridad del programa y redujo el consumo;
    4. El más lento El lugar es que la primera cooperación de programación emparejada usa Github, que lleva mucho tiempo configurar y familiarizarse. Puede ser que varias tiradas y fusiones hayan fallado debido a problemas de red y otros. Aquí estoy muy agradecido por la guía remota de Qiting;
    5. medio día, porque no hay uso de componentes de arrastrar y soltar, pero la codificación manual, nos encontramos con muchos problemas pequeños, por lo que la programación orientada a CSDN, el proceso es muy doloroso;
    6. el más doloroso es para compilar y ejecutar Después de la prueba correctamente etiquetada envase frasco después en recursos de archivos ejecutables exe encontrado la imagen no se puede guardar, para encontrar una solución no es el resultado final se convertirá en un frasco de archivos exe paquete directamente en la línea de comandos para ejecutar el archivo jar a su uso.

Seis, el código clave

  • Cálculo de fracciones y enteros.

      /***
         * 相加操作
         */
        ADD("+") {
            @Override
            public String calculate(String a, String b) {
                boolean flagA = a.contains("/");
                boolean flagB = b.contains("/");
                //两个都是分数
                if (flagA && flagB) {
                    int[] anInt = ResolveUtil.analysis(a);
                    int[] bnInt = ResolveUtil.analysis(b);
                    //以AB为分母
                    int denominator = anInt[1] * bnInt[1];
                    //相加后的分子
                    int molecule = anInt[0] * bnInt[1] + anInt[1] * bnInt[0];
                    return ResolveUtil.createFraction(molecule, denominator);
                } else if (flagA) {
                    int[] anInt = ResolveUtil.analysis(a);
                    //直接更新分子便可
                    anInt[0] += Integer.parseInt(b) * anInt[1];
                    return ResolveUtil.createFraction(anInt[0], anInt[1]);
                } else if (flagB) {
                    int[] bnInt = ResolveUtil.analysis(b);
                    //直接更新分子便可
                    bnInt[0] += Integer.parseInt(a) * bnInt[1];
                    return ResolveUtil.createFraction(bnInt[0], bnInt[1]);
                } else {
                    return String.valueOf(Integer.parseInt(a) + Integer.parseInt(b));
                }
            }
        },
        /***
         * 相乘操作
         */
        MULTIPLY("×") {
            @Override
            public String calculate(String a, String b) {
                boolean flagA = a.contains("/");
                boolean flagB = b.contains("/");
    
                if (flagA && flagB) {
                    int[] anInt = ResolveUtil.analysis(a);
                    int[] bnInt = ResolveUtil.analysis(b);
                    //以AB为分母
                    int denominator = anInt[1] * bnInt[1];
                    //分子相乘
                    int molecule = anInt[0] * bnInt[0];
                    return ResolveUtil.createFraction(molecule, denominator);
                } else if (flagA) {
                    int[] anInt = ResolveUtil.analysis(a);
                    return ResolveUtil.createFraction(anInt[0] * Integer.parseInt(b), anInt[1]);
                } else if (flagB) {
                    int[] bnInt = ResolveUtil.analysis(b);
                    return ResolveUtil.createFraction(bnInt[0] * Integer.parseInt(a), bnInt[1]);
                } else {
                    return String.valueOf(Integer.parseInt(a) * Integer.parseInt(b));
                }
            }
        },
        /***
         * 相除操作
         */
        DIVIDE("÷") {
            @Override
            public String calculate(String a, String b) {
                //除法,从另外一种角度来说,是乘法的倒转,所以,只需要把b分子分母倒过来用乘法就行了
                boolean flag = b.contains("/");
                //新的数b的字符串
                String newB;
                //判断b是否为分数
                if (flag) {
                    int[] bnInt = ResolveUtil.analysis(b);
                    newB = ResolveUtil.createFraction(bnInt[1], bnInt[0]);
                } else {
                    newB = 1 + "/" + b;
                }
                return Symbol.MULTIPLY.calculate(a, newB);
            }
        },
        /***
         * 相减操作
         */
        SUB("-") {
            @Override
            public String calculate(String a, String b) {
                //减是加的特例,把b弄成-就可以了
                return Symbol.ADD.calculate(a, "-" + b);
            }
        },
    
  • Expresión de infijo a sufijo

    /***
         * 中缀表达式转换成后缀表达式
         * @param expression 表达式
         * @return 数组
         */
        private String[] middleToAfter(String expression) {
            //用来转换的栈
            Stack<String> stack = new Stack<>();
            //表达式每个字符前后都会生成一个空格
            String[] strings = expression.split("\\s");
            //返回的list
            List<String> stringList = new ArrayList<>(strings.length);
            for (int index = 0; index < strings.length; index++) {
                if ('0' <= strings[index].charAt(0) && strings[index].charAt(0) <= '9') {
                    //数字直接输出
                    stringList.add(strings[index]);
                } else if (strings[index].equals(Symbol.BEGIN.getSymbol())) {
                    //开始括号压进栈
                    stack.push(strings[index]);
                } else if (strings[index].equals(Symbol.END.getSymbol())) {
                    //把所有运算符都出栈
                    while (!stack.peek().equals(Symbol.BEGIN.getSymbol())) {
                        stringList.add(stack.pop());
                    }
                    //出栈开始括号
                    stack.pop();
                } else if (strings[index].equals(Symbol.MULTIPLY.getSymbol())
                        || strings[index].equals(Symbol.DIVIDE.getSymbol())) {
                    //判断上一级符号是什么
                    boolean flag = !stack.isEmpty() && (stack.peek().equals(Symbol.MULTIPLY.getSymbol())
                            || stack.peek().equals(Symbol.DIVIDE.getSymbol()));
                    if (flag) {
                        stringList.add(stack.pop());
                    }
                    stack.push(strings[index]);
                } else if (strings[index].equals(Symbol.SUB.getSymbol())
                        || strings[index].equals(Symbol.ADD.getSymbol())) {
                    //此处应该为+,-号
                    boolean flag = !stack.isEmpty() && (stack.peek().equals(Symbol.ADD.getSymbol())
                            || stack.peek().equals(Symbol.SUB.getSymbol()));
                    if (flag) {
                        stringList.add(stack.pop());
                    }
                    stack.push(strings[index]);
                } else {
                    //有其他符号,直接跳出,可能是=号
                    break;
                }
            }
            while (!stack.isEmpty()) {
                stringList.add(stack.pop());
            }
            //返回数组
            return stringList.toArray(new String[0]);
        }
    
  • Cálculo de sufijo

    /***
         * 计算表达式
         * @param expression 表达式
         * @param permit 允许存在负数的运算过程
         * @return 结果
         */
        public String calculate(String expression, boolean permit) {
            if (expression == null) {
                return null;
            }
            //先生成后缀表达式数组,然后手动控制数组进行操作
            String[] afterExp = middleToAfter(expression);
            Stack<String> stack = new Stack<>();
            try {
                for (int index = 0; index < afterExp.length; index++) {
                    if (afterExp[index].matches("[0-9/']+")) {
                        stack.push(afterExp[index]);
                    } else {
                        String b = stack.pop();
                        String a = stack.pop();
    
                        String result = Symbol.value(afterExp[index]).calculate(a, b);
                        //计算过程中存在负数,重新生成表达式
                        if (result.startsWith("-") && !permit) {
                            return null;
                        }
                        stack.push(result);
                    }
                }
            } catch (NullPointerException e) {
                e.printStackTrace();
            } catch (Exception e) {
                System.out.println("存在表达式不合法");
            }
            return stack.pop();
        }
    
    
  • Generar expresión

    /***
         * 生成表达式
         * @return 生成表达式
         */
        private String generateExpression() {
            //随机运算符大小
            int operatorSize = (int) (Math.random() * MAX_OPERATOR_SIZE) + 1;
            int numberSize = operatorSize + 1;
            //判断是否需要生成括号,1/4的概率
            boolean flag = (int) (Math.random() * MAX_OPERATOR_SIZE) == 0;
            //标记(产生的位置)
            int mark = -1;
            if (flag) {
                //随机插入括号的位置
                mark = (int) (Math.random() * operatorSize);
            }
    
            StringBuilder expression = new StringBuilder();
            //遍历产生数字和符号,你一下我一下
            for (int i = 0; i < numberSize; i++) {
                if (mark == i) {
                    myAppend(expression, "(");
                }
                //生成数字
                myAppend(expression, (int) (Math.random() * 2) == 0 ? generateFraction() : generateInt());
    
                //判断是否加入结束符号,判断是否结尾
                if (mark >= 0 && mark < i) {
                    //已经到了表达式结尾, 此时必须结束
                    if (i == operatorSize) {
                        myAppend(expression, ")");
                        break;
                    }
                    //判断是否需要结束
                    flag = (int) (Math.random() * 2) == 0;
                    if (flag) {
                        myAppend(expression, ")");
                        mark = -1;
                    }
                }
                if (i < operatorSize) {
                    //然后生成一个操作符
                    myAppend(expression, generateOperator());
                }
            }
            //最后补充等号
            expression.append("=");
            return expression.toString();
        }
    
  • Comprobación de deduplicación

         /***
         * 检查表达式是否已经存在或者重复
         * @param expression 表达式
         * @param result  结果
         * @return 是否重复
         */
        private boolean checkExpressionExistAndResultIllegal(String expression, String result) {
            if (Objects.isNull(result)) {
                return true;
            }
            //当前没有表达式
            if (nowExpressionSize == 0) {
                return false;
            }
            //API的一些操作也是循环,效率低下,手动循环
            for (int i = 0, j = nowExpressionSize - 1; i <= j; i++, j--) {
                if (expressionList.get(i).equals(expression) || expressionList.get(j).equals(expression)) {
                    return true;
                }
                //查看是否答案有相同的
                if (answerList.get(i).equals(result)) {
                    return checkCharEquals(expressionList.get(i), expression);
                } else if (answerList.get(j).equals(result)) {
                    return checkCharEquals(expressionList.get(j), expression);
                }
            }
            return false;
        }  
    
    	/***
         *
         * @param oldExpression 存在的表达式
         * @param newExpression 还没存进去的表达式
         * @return 相同,不相同
         */
        private boolean checkCharEquals(String oldExpression, String newExpression) {
            String[] oldExpressionArrays = oldExpression.split("\\s+");
            String[] newExpressionArrays = newExpression.split("\\s+");
            int oldExpressionNumber = 0;
            int equalsNumber = 0;
            //是否为数字
            boolean flag;
            //开始遍历
            for (String oldString : oldExpressionArrays) {
                flag = oldExpression.matches("[0-9'/]+");
                if (flag) {
                    oldExpressionNumber++;
                }
                //比对
                for (String newString : newExpressionArrays) {
                    if (oldString.equals(newString)) {
                        equalsNumber++;
                    }
                }
            }
    
  • Responda la corrección de pruebas

      //保存正确/错误题号的队列
      private List<Integer> correctList = new ArrayList<>();
      private List<Integer> wrongList = new ArrayList<>();
    
      /**
       * 校验待检测文件状态
       * @param exersicesFile
       * @param myAnswer
       * @Author Naren
       */
      public void checkFile(String exersicesFile,String myAnswer) {
              //存储表达式的文件
              File expFile = new File(exersicesFile);//Exercise002.txt
              //待校验答案的文件
              File myAnsFile = new File(myAnswer);//myAnswers001.txt
              //待校验答案文件不存在
              if(!myAnsFile.exists()){
                  //System.out.println("未找到待检验答案文件。");
                  new Tips().displayTips("noExpTip.png");
                  return;
              }
              //如果表达式文件不存在
              if(!expFile.exists()) {
                  //System.out.println("未找到指定题目文件。");
                  new Tips().displayTips("noAnsTip.png");
                  return;
              }
              //如果全部文件名都正确,检测待校对题目文件是否存在于系统生成历史中
              String id = exersicesFile.substring(9,12);
              String sysAnsFile = "Answers" + id + ".txt"; //Myapp.exe -e Exercises001.txt -a myAnswers001.txt
              File ansFile = new File(sysAnsFile);//Answers002.txt(不存在)
              //若系统中不存在与题目文件相符合的答案文件
              if(!ansFile.exists()){
                  try {
                      FileReader fr = new FileReader(expFile);
                      BufferedReader br = new BufferedReader(fr);
                      String content = null;
                      ArrayList<String> questionList = new ArrayList<>();
                      while((content = br.readLine()) != null){//(?m)^.*$
                          content = content.split("\\.")[1];
                          questionList.add(content);
                      }
                      //调用起廷方法获得答案队列
                      Expression ex = new Expression(new Calculate());
                      List<String> answerList = ex.getCorrectAnswerList(questionList);
                      //比对
                      checkAnswer(myAnsFile,answerList);
                  } catch (Exception e) {
                      System.out.println("Class:AnswerChecking,Method:checkFile(String,String) is wrong!");
                  }
              }else{
                  //调用本类检验方法比对答案文件
                  checkAnswer(myAnsFile,ansFile);
              }
      }
    
      /**
       * 将待校验答案文件与现场计算出的答案队列进行比对
       * @param myAnswer
       * @param answerList
       * @author Naren
       */
      private void checkAnswer(File myAnswer, List<String> answerList){
          try {
              //待检测答案文件
              FileReader fr1 = new FileReader(myAnswer);
              BufferedReader br1 = new BufferedReader(fr1);
    
              LinkedHashMap<Integer,String> map1 = new LinkedHashMap<>();
    
              String content = "";
              while((content = br1.readLine()) != null){
                  content = content.replaceAll(" +", "").replaceAll("\uFEFF", "");
                  //map1待校验答案:key:序号,value:答案
                  map1.put(Integer.valueOf(content.split("\\.")[0]),content.split("\\.")[1]);
              }
    
              //开始比对
              for (int i = 0; i < answerList.size(); i++) {
                  if(map1.containsKey(i + 1)){
                      if(map1.get(i + 1).equals(answerList.get(i))) {
                          correctList.add(i + 1);//正确题号添加进队列
                      }
                      else{
                          wrongList.add(i + 1);//错误题号添加进队列
                      }
                  }else{
                      //漏写
                      wrongList.add(i + 1);
                  }
              }
              //将校验结果写入文件
              //System.out.println("检验信息已写入Grade.txt文件。");
              new Tips().displayTips("checkSuccess.png");
              new DataStorage().storeCheckInfo(correctList,wrongList);
          } catch (Exception e) {
              System.out.println("Class:AnswerChecking,Method:checkAnswer(File,List) is wrong!");
          }
      }
    
      /**
       * 【重载】将待校验答案文件与本地答案文件进行比对
       * @param myAnswer 待校验答案文件
       * @param ansFile  正确答案文件
       * @author Naren
       */
      private void checkAnswer(File myAnswer, File ansFile) {
    
          try {
              FileReader fr1 = new FileReader(myAnswer);
              FileReader fr2 = new FileReader(ansFile);
              BufferedReader br1 = new BufferedReader(fr1);
              BufferedReader br2 = new BufferedReader(fr2);
    
              LinkedHashMap<Integer,String> map1 = new LinkedHashMap<>();//待检测 key:序号,value:答案
              LinkedHashMap<Integer,String> map2 = new LinkedHashMap<>();//正  确 key:序号,value:答案
    
              //分别按行读出答案
              String content = "";
              while((content = br1.readLine()) != null){
                  content = content.replaceAll(" +", "").replaceAll("\uFEFF", "");
                  map1.put(Integer.valueOf(content.split("\\.")[0]),content.split("\\.")[1]);
              }
              while((content = br2.readLine()) != null){
                  content = content.replaceAll(" +", "").replaceAll("\uFEFF", "");
                  map2.put(Integer.valueOf(content.split("\\.")[0]),content.split("\\.")[1]);
              }
    
              //开始比对
              for (int i = 0; i < map2.size(); i++) {
                  if(map1.containsKey(i + 1)){
                      if(map1.get(i + 1).equals(map2.get(i + 1))) {
                          correctList.add(i + 1);//正确题号添加进队列
                      }
                      else{
                          wrongList.add(i + 1);//错误题号添加进队列
                      }
                  }else{
                      //漏写
                      wrongList.add(i + 1);
                  }
              }
              //将校验结果写入文件
              //System.out.println("检验信息已写入Grade.txt文件。");
              new Tips().displayTips("checkSuccess.png");
              new DataStorage().storeCheckInfo(correctList,wrongList);
          } catch (Exception e) {
              System.out.println("Class:AnswerChecking,Method:checkAnswer(File,File) is wrong!");
          }
      } 
    

Siete, resultados de la prueba

7.1 Prueba de interfaz de consola:

7.1.1 Ejemplos de error

  • Generar error

    • [Parámetro] Error
    • Error [El archivo ya existe]
  • Error de revisión

    • Error [El archivo del título no existe]
    • Error [El archivo de respuesta no existe]

7.1.2 Ejemplos correctos

  • Correctamente generado

    • Genera 100 preguntas correctamente

    • Genera 12,000 preguntas correctamente

  • Verificacion correcta

    • Comprueba correctamente 100 preguntas

    • Verifique correctamente 12,000 preguntas


7.2 Prueba de interfaz gráfica (línea de comando para ejecutar el paquete jar)


7.2.1 Ejemplo incorrecto

7.2.2 Ejemplo correcto

  • Correctamente generado

  • Corrección correcta

Debido a que hay pruebas constantes durante el proceso de codificación, y dos personas eligen errores entre sí, la última prueba cubrió manualmente las posibles entradas Se puede decir que las expectativas de "los resultados del programa son correctos" están cerca de 1.

8. Percepción del proceso

  • Chen Qiting: El emparejamiento es muy bueno. Lanza todo lo que no quieras hacer a otra persona. También puedes hacer un discurso falso (bromas). La finalización del código está bastante bien, y no es la primera vez que se ha desarrollado con otros. Cada vez que se arrastra desde github, no se siente un código, sino un shock. En todo el proceso del proyecto, también utilicé algunos puntos de conocimiento que aprendí para simplificar el código, y gané algo.
  • Chai Zheng: La primera cooperación para completar un proyecto, aunque no hay muchas funciones, pero después del éxito, todavía siento una sensación de satisfacción con los demás para completar una cosa. En el proceso de programación y optimización, tengo una comprensión más hábil de la arquitectura general del proyecto, y gracias a las instrucciones de los compañeros de equipo para agregar un código hermoso y habilidades de rendimiento. La conexión entre dos personas es un proceso para encontrar errores entre ellos (risas), pero al final, se pueden resolver bien. Espero que el próximo proyecto preste más atención a la planificación y el registro del tiempo, así como a una comprensión más profunda de los mecanismos subyacentes de Java.

ps. 花絮 【"Te empujo, tú ..."】


  • Corte : este error se ha solucionado ~

Supongo que te gusta

Origin www.cnblogs.com/narenblogs/p/12694647.html
Recomendado
Clasificación