山竹哈

导航

小学生的随机四则运算

GitHub项目地址:https://github.com/Juneflyfire/jisuan

一、需求分析

  • 程序可接收一个输入参数n,然后随机产生n道加减乘除练习题,每个数字在 0 和 100 之间,运算符在3个到5个之间。
  • 为了让小学生得到充分锻炼,每个练习题至少要包含2种运算符。同时,由于小学生没有分数与负数的概念,你所出的练习题在运算过程中不得出现负数与非整数,比如不能出 3/5+2=2.6,2-5+10=7等算式。
  • 练习题生成好后,将你的学号与生成的n道练习题及其对应的正确答案输出到文件“result.txt中,不要输出额外信息,文件目录与程序目录一致。
  • 当程序接收的参数为4时,以下为输出文件示例。
  • 支持有括号的运算式,包括出题与求解正确答案。注意,算式中存在的括号必须大于2个,且不得超过运算符的个数。(5分)
  • 扩展程序功能支持真分数的出题与运算,例如:1/6 + 1/8 + 2/323/24。注意在实现本功能时,需支持运算时分数的自动化简,比如 1/2+1/6=2/3,而非4/6。

二、功能分析

根据需求分析,可以得出该项目所需的功能:

  • 随机产生自定义的n道二位数的四则运算题,运算题的运算符号不少于2。
  • 学生可以输入做题的答案
  • 将随机产生的题目以及正确答案保存在一个包含自己学号的TXT文件中,

三、设计实现

 

四、测试运行

如下图所示,当n=50时,循环产生50个算式,学生可输入答案,与result文件中的正确答案对比是否正确。

 

五、核心代码

     /**
     * 提前将 符号的优先级定义好
     */
    private static final Map<Character, Integer> basic = new HashMap<Character, Integer>();
    static {
        basic.put('-', 1);
        basic.put('+', 1);
        basic.put('*', 2);
        basic.put('/', 2);
        basic.put('(', 0);
    }
/**
     * 得到计算式的字符串
     */
    public String getString() {
        String[] operate = new String[] { "+", "-", "*", "/" };
        int[] number = new int[101];
        for (int i = 0; i <= 100; i++)
            number[i] = i;
        int[] type = new int[3];
        for (int i = 0; i < 3; i++)
            type[i] = i;
        Random r = new Random();
        int t = type[r.nextInt(3)];
        if (t == 0){
            String  str1 = operate[r.nextInt(4)];
            String  str2 = operate[r.nextInt(4)];
            if (str1.equals(str2))
                return null;
            else 
                return number[r.nextInt(101)] + str1 + number[r.nextInt(101)] + str2
                        + number[r.nextInt(101)];            
        }
        else if (t == 1){
            String  str1 = operate[r.nextInt(4)];
            String  str2 = operate[r.nextInt(4)];
            String  str3 = operate[r.nextInt(4)];
            if(str1.equals(str2)&&str1.equals(str3))
                return null;
            else 
                return number[r.nextInt(101)] + str1 + number[r.nextInt(101)] + str2
                        + number[r.nextInt(101)] + str3 + number[r.nextInt(101)];
        }
        else{
            String  str1 = operate[r.nextInt(4)];
            String  str2 = operate[r.nextInt(4)];
            String  str3 = operate[r.nextInt(4)];
            String  str4 = operate[r.nextInt(4)];
            if(str1.equals(str2)&&str1.equals(str3)&&str1.equals(str4))
                return null;
            else
                return number[r.nextInt(101)] + str1 + number[r.nextInt(101)] + str2
                        + number[r.nextInt(101)] + str3 + number[r.nextInt(101)] + str4
                        + number[r.nextInt(101)];
        }
            
    }
/**
     * 将 中缀表达式 转化为 后缀表达式
     */
    public String toSuffix(String infix) {
        if(infix==null)
            return null;
        List<String> queue = new ArrayList<String>();// 定义队列 用于存储 数字 以及最后的 后缀表达式
        List<Character> stack = new ArrayList<Character>();// 定义栈 用于存储 运算符,最后stack中会被 弹空

        char[] charArr = infix.trim().toCharArray();// 字符数组 用于拆分数字或符号
        String standard = "*/+-()"; // 判定标准 将表达式中会出现的运算符写出来
        char ch = '&';// 在循环中用来保存 字符数组的当前循环变量的 这里仅仅是初始化一个值 没有意义
        int len = 0;// 用于记录字符长度 【例如100*2,则记录的len为3 到时候截取字符串的前三位就是数字
        for (int i = 0; i < charArr.length; i++) {// 开始迭代

            ch = charArr[i]; // 保存当前迭代变量
            if (Character.isDigit(ch)) { // 如果当前变量为 数字
                len++;
            } else if (Character.isLetter(ch)) {// 如果当前变量为 字母
                len++;
            } else if (ch == '.') {// 如果当前变量为 . 会出现在小数里面
                len++;
            } else if (Character.isSpaceChar(ch)) {// 如果当前变量为 空格 支持表达式中有空格出现
                if (len > 0) {// 若为空格 代表 一段结束 ,就可以往队列中 存入了 【例如100 * 2 100后面有空格
                                // 就可以将空格之前的存入队列了】
                    queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));// 往队列存入截取的字符串
                    len = 0;// 长度置空
                }
                continue;// 如果空格出现,则一段结束 跳出本次循环
            } else if (standard.indexOf(ch) != -1) { // 如果是上面标准中的 任意一个符号
                if (len > 0) { // 长度也有
                    queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));// 说明符号之前的可以截取下来做数字
                    len = 0;// 长度置空
                }
                if (ch == '(') {// 如果是左括号
                    stack.add(ch);// 将左括号 放入栈中
                    continue; // 跳出本次循环 继续找下一个位置
                }
                if (!stack.isEmpty()) {// 如果栈不为empty
                    int size = stack.size() - 1;// 获取栈的大小-1 即代表栈最后一个元素的下标
                    boolean flag = false;
                    while (size >= 0 && ch == ')' && stack.get(size) != '(') {
                        queue.add(String.valueOf(stack.remove(size)));
                        size--;
                    }
                    while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) {
                        queue.add(String.valueOf(stack.remove(size)));
                        size--;
                    }
                }
                if (ch != ')') {
                    stack.add(ch);
                } else {
                    stack.remove(stack.size() - 1);
                }
            }
            if (i == charArr.length - 1) {
                if (len > 0) {
                    queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len + 1, i + 1)));
                }
                int size = stack.size() - 1;
                while (size >= 0) {
                    queue.add(String.valueOf(stack.remove(size)));
                    size--;
                }
            }

        }
        return queue.stream().collect(Collectors.joining(","));
    }

    

六、总结

本次项目花了很长的时间,首先是代码的完成部分,由于自己很久没有使用过Java语言,所以一直都觉得这个代码很难,写不出来。渐渐有同学提交了,deadline将至,便硬着头皮上,先是百度看别人的,然后自己尝试着写,从产生随机数开始,一点一点的积少成多,也突然觉得其实Java也并没有自己想象中的那么难,把它和C语言一样当成一个工具就好了。还有就是刚开始写这个项目的时候,由于自己没有真正的理清头绪,为了实现老师要求的三到五个运算符,在随机产生两个数字的计算题的前提下,投机取巧将加减乘除运算符定死。如下

int a=(int)(Math.random()*100);//随机生成一个1-100的整数
             int b=(int)(Math.random()*100);//随机生成一个1-100的整数
             int c=(int)(Math.random()*100);//随机生成一个1-100的整数
             int d=(int)(Math.random()*4);//随机生成一个1-4的整数,0表示加法,1表示减法,2表示乘法,3表示除法
             String temp;
             switch((int)(Math.random()*3))
             {
                case 0:
                    if(d==0)
                       System.out.println(a+"+"+b+"+"+c+"=");
                       temp=Integer.toString(a)+"+"+Integer.toString(b)+"+"+Integer.toString(c)+"="+Integer.toString(a+b+c);
                       fos.write(temp.getBytes());
                    if(d==1)
                       System.out.println(a+"+"+b+"-"+c+"=");
                       temp=Integer.toString(a)+"+"+Integer.toString(b)+"-"+Integer.toString(c)+"="+Integer.toString(a+b-c);
                       fos.write(temp.getBytes());
                    if(d==2)
                        System.out.println(a+"+"+b+"*"+c+"=");
                        temp=Integer.toString(a)+"+"+Integer.toString(b)+"*"+Integer.toString(c)+"="+Integer.toString(a+b*c);
                        fos.write(temp.getBytes());
                    if(d==3)
                        System.out.println(a+"+"+b+"/"+c+"=");
                        temp=Integer.toString(a)+"+"+Integer.toString(b)+"/"+Integer.toString(c)+"="+Integer.toString(a+b/c);
                        fos.write(temp.getBytes());
                    int sum = in.nextInt();
                    count++;   
                    break;
                case 1:
                    if(d==0)
                        System.out.println(a+"-"+b+"+"+c+"=");
                        temp=Integer.toString(a)+"-"+Integer.toString(b)+"+"+Integer.toString(c)+"="+Integer.toString(a-b+c);
                        fos.write(temp.getBytes());
                    if(d==1)
                        System.out.println(a+"-"+b+"-"+c+"=");
                        temp=Integer.toString(a)+"-"+Integer.toString(b)+"-"+Integer.toString(c)+"="+Integer.toString(a-b-c);
                        fos.write(temp.getBytes());
                    if(d==2)
                        System.out.println(a+"-"+b+"*"+c+"=");

运行结果表面上符合老师的部分要求,然而在数据流的写入却是乱的。我从中也学会了要提前设计好程序流程,着眼全局。

代码部分还有一个问题就是功能没有完全是实现,代码中虽然涉及到了括号的优先级,并且也用逆波兰式模拟了括号的出栈入栈情况,但是在随机产生运算符的时候依旧不知道该如何处理。这个问题希望可以得到解决。

其次就是将项目在上传GitHub时花费了很长的时间,看视频看了一半就开始在GitHub上建立仓库,开始新建文件,殊不知这是一知半解。在求助他人的时候,知道了可以本地上传,就开始百度各种资料,依旧遇到很多的问题。比如本地git访问到gihub账号等等。好在都解决了,也让我在此学会了静心尽力去主动解决问题,而不是去恐惧它。

总之呢,这个作业很磨人,尤其是对于我这种基础不好的同学,但是当看着这个项目聚沙成塔的时候,也算痛并快乐着。

七、生成PSP

PSP2.1

任务内容

计划完成需要的时间(min)

实际完成需要的时间(min)

Planning

计划

8

15

·       Estimate

·  估计这个任务需要多少时间,并规划大致工作步骤

8

15

Development

开发

120

201

··       Analysis

  需求分析 (包括学习新技术)

6

10

·       Design Spec

·  生成设计文档

5

6

·       Design Review

·  设计复审 (和同事审核设计文档)

4

6

·       Coding Standard

  代码规范 (为目前的开发制定合适的规范)

3

25

·       Design

  具体设计

10

18

·       Coding

  具体编码

36

100

·       Code Review

·  代码复审

7

15

·       Test

·  测试(自我测试,修改代码,提交修改)

13

21

Reporting

报告

9

10

··       Test Report

·  测试报告

3

5

·       Size Measurement

  计算工作量

2

2

·       Postmortem & Process Improvement Plan

·  事后总结 ,并提出过程改进计划

3

3

 

posted on 2018-03-20 18:33  山竹哈  阅读(469)  评论(2编辑  收藏  举报