第一次个人作业——小学生四则运算


Coding.net仓库地址:https://dev.tencent.com/u/yangmt735/p/arithmatic/git/tree/master/test2

一、需求分析

基本需求:

  1. 0-100之间的四则运算
  2. 3-5个运算符
  3. 运算过程中不允许出现负数和分数
  4. 系统输入生成的题数量
  5. 输出到 result.txt 文件中,文件目录为当前classpath
  6. 文件首行输出学号

附加需求:
1.真分数的运算
2.加括号(未完成)

二、实现

Main类:主类,输入数字。
ProperFraction类:生成真分数的算式。
gcd():求最大公因数
index():产生操作符的下标数组
CreatFile类:生成文件。
writeExpressionsToFile():将练习题输出到文件
Arithmatic类
getNextExpression():生成练习题
getOperatorList():获取运算符
getCalValueList():获取运算数
getDivideCalValue():当为除法时校验除数不为0且能被整除

三、算法

使用java调用js中的eval(String)函数求解算式。

四、代码展示

仅展示Arithmatic类中的代码,完整代码请进入codng.net观看

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class Arithmatic {
	private static ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("JavaScript");
    /**
     * 定义需要用到的常量
     */
    final char PLUS = '+';
    final char MINUS = '-';
    final char MULTIPLY = '*';
    final char DIVIDE = '/';
    final char DISPLAY_DIVIDE = '÷';
    final char EQUALS = '=';
    final String DOT = ".";
    final String DOT_REGEX = "\\.";
    /**
     * 运算符及输入的限制
     */
    final char[] operators = {PLUS, MINUS, MULTIPLY, DIVIDE};
    final Integer MIN_OPERATOR_COUNT = 3;
    final Integer MAX_OPERATOR_COUNT = 5;
    final Integer MIN_CAL_VALUE = 0;
    final Integer MAX_CAL_VALUE = 100;
    
    Random random = new Random();
	/**
     * 生成练习题
     *
     * @return
     * @throws ScriptException
     */
    public String getNextExpression() throws ScriptException {
        //System.out.println("尝试生成下一道题");

        // 运算符数量
        int operatorCount = random.nextInt(MAX_OPERATOR_COUNT + 1 - MIN_OPERATOR_COUNT) + MIN_OPERATOR_COUNT;

        StringBuilder expression = new StringBuilder();

        // 运算符
        List<Character> operatorList = getOperatorList(operatorCount);

        // 运算数
        List<Integer> calValueList = getCalValueList(operatorCount + 1);

        for (int i = 0; i < operatorList.size(); i++) {
            Character operator = operatorList.get(i);// 运算符

            Integer previousCalValue = calValueList.get(i);// 运算数
            Integer nextCalValue = calValueList.get(i + 1);
            expression.append(previousCalValue);

            // 除法校验除数不为0且能被整除
            if (DIVIDE == operator) {
                calValueList.set(i + 1, getDivideCalValue(previousCalValue, nextCalValue));
            } 
            else if (MINUS == operator) {
                // 减法校验被减数大于减数
                // 当包含小数点时向下取整
                String currentResultString = scriptEngine.eval(expression.toString()).toString();//eval是Javascript内置函数,用于计算字符串表达式的值
                if (currentResultString.contains(DOT)) {
                    currentResultString = currentResultString.split(DOT_REGEX)[0];
                }
                Integer currentResult = Integer.valueOf(currentResultString);
                while (currentResult < nextCalValue) {
                    nextCalValue = random.nextInt(MAX_CAL_VALUE + 1);
                }
                calValueList.set(i + 1, nextCalValue);
            }

            expression.append(operator);
        }

        expression.append(calValueList.get(operatorCount));

        // 计算当前结果是否为正整数
        String result = scriptEngine.eval(expression.toString()).toString();

        if (result.contains(DOT) || Integer.valueOf(result) < 0) {
            //System.out.println("当前题目不符合要求");
            return getNextExpression();
        }

        String currentExpression = expression.append(EQUALS).append(result)
                .toString()
                .replaceAll(String.valueOf(DIVIDE), String.valueOf(DISPLAY_DIVIDE));
        return currentExpression;
    }

    /**
     * 获取运算符
     *
     * @param operatorCount
     * @return
     */
    public List<Character> getOperatorList(int operatorCount) {
        List<Character> operatorList = new ArrayList<>();
        for (int i = 0; i < operatorCount; i++) {
            Character operator = operators[random.nextInt(operators.length)];
            operatorList.add(operator);
        }
        return operatorList;
    }

    /**
     * 获取运算数
     *
     * @param calValueCount
     * @return
     */
    public List<Integer> getCalValueList(int calValueCount) {
        List<Integer> calValueList = new ArrayList<>();
        for (int i = 0; i < calValueCount; i++) {
            calValueList.add(random.nextInt(MAX_CAL_VALUE + 1));
        }
        return calValueList;
    }

    /**
     * 当为除法时校验除数不为0且能被整除
     *
     * @param previousCalValue
     * @param nextCalValue
     * @return
     */
    public int getDivideCalValue(Integer previousCalValue, Integer nextCalValue) {
        if (nextCalValue == 0 || previousCalValue % nextCalValue != 0) {
            nextCalValue = random.nextInt(MAX_CAL_VALUE) + 1;
            return getDivideCalValue(previousCalValue, nextCalValue);
        }
        return nextCalValue;
    }
   
}

五、测试

第一次个人作业——小学生四则运算
第一次个人作业——小学生四则运算

六、遇到的问题

1.编码gbk的不可映射字符
解决方式:编译时用javac -encoding UTF-8 Main.java
2.找不到主类
原因:没有进入主目录
3.数组溢出
原因:范围出错

七、PSP

PSP2.1 任务内容 计划共完成需要的时间(min) 实际完成需要的时间(min)
Planning 计划 10 30
· Estimate · 估计这个任务需要多少时间,并规划大致工作步骤 10 30
Development 开发 360 1042
· Analysis · 需求分析(包括学习新技术) 30 60
·Design Spec · 生成设计文档 0 0
· Design Review · 设计复审 (和同事审核设计文档) 0 0
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 10
· Design · 具体设计 10 12
· Coding · 具体编码 240 300
· Code Review · 代码复审 10 60
· Test · 测试(自我测试,修改代码,提交修改) 60 600
Reporting 报告 35 65
· Test Report · 测试报告 0 0
· Size Measurement · 计算工作量 5 5
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 60

八、总结

刚开始的时候,我是先想了想具体实现,然后就开始打代码了,但是打着打着就打不下去了,没有思路,或者是有思路但打不出来,浪费了大量时间,后来看了看学长学姐们的博客并找了一些代码看,发现他们都写了需求分析,我就从头开始,先分析需求,然后想具体应该怎样实现,并记下来,然后开始重新打代码,但还是有很多不会,java之前就没学好,然后就一边学一边打,实在遇到不会的就上网查,就这样磕磕盼盼的打出来了,但是测试的时候又遇到了很多问题,又一个个的解决,我知道会很困难,但真的没想到会难成这样,真的中途烦躁了很久,但终于还是打出来了。原本没想着实现扩展的功能,因为开始我就觉得我打不出来,后来看博客又想试一试,这个过程也是很艰难,但最后还是做出来了,那一刻真的很开心,虽然过程很艰难,但从中我学到了很多,比如eval()的用法,命令行的使用等等,也充分意识到了自己的不足,以后我会继续努力的。