zoukankan      html  css  js  c++  java
  • 小学生的随机四则运算

    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

  • 相关阅读:
    中国石油大学天梯赛真题模拟第二场
    AtCoder Grand Contest 016 B
    POJ1011 Sticks
    UPC7817: Supermarket
    UPC5652: Ants on a Circle
    石大iCal课表使用指南
    UPC10582: Cowpatibility
    UPC11079: 小P的决斗 POJ3244 Difference between Triplets
    UPC6976:矩阵模板(二维哈希)
    知识点2-3:视图的职责
  • 原文地址:https://www.cnblogs.com/wuqiong666/p/8611384.html
Copyright © 2011-2022 走看看