第二次作业

Git地址 https://github.com/bibubu/AchaoCalculator
Git用户名 bibubu
学号后5位 62327
博客地址 https://www.cnblogs.com/cadaver/
作业链接 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/homework/2793

一.环境配置过程

因为以前做项目已经安装过vs2013,所以环境配置这一块儿没有遇到问题。

 

二.注册GitHub账号

 因为以前经自己的程序员老哥介绍来浏览过这个网站,所以已经有账号了

三.代码设计

 3.1 题目背景

阿超家里的孩子上小学一年级了,这个暑假老师给家长们布置了一个作业:家长每天要给孩子出一些合理的,但要有些难度的四则运算题目,并且家长要对孩子的作业打分记录。作为程序员的阿超心想,既然每天都需要出题,那何不做一个可以自动生成小学四则运算题目与解决题目的命令行 “软件”呢。他把老师的话翻译一下,就形成了这个软件的需求:程序接收一个命令行参数 n,然后随机产生 n 道加减乘除(分别使用符号+-*/来表示)练习题,每个数字在 0和 100 之间,运算符在 2 个 到 3 个之间。由于阿超的孩子才上一年级,并不知道分数。所以软件所出的练习题在运算过程中不得出现非整数,比如不能出现 3÷5+2=2.6 这样的算式。练习题生成好后,将生成的 n 道练习题及其对应的正确答案输出到一个文件 subject.txt 中。当程序接收的参数为4时,以下为一个输出文件示例。

13+17-1=29

11*15-5=160

3+10+4-16=1

15÷5+3-2=4

3.2 程序设计思路及核心代码

首先,我想到的是用随机数来决定要生成的四则运算题目的计算数和运算符,具体实现代码如下:

/// <summary>
        /// 随机生成m个0-100之间的数
        /// </summary>
        /// <param name="m">要生成的个数</param>
        /// <returns>一个双精度小数集合</returns>
        public static List<double> numProduce(int m)
        {
            List<double> num = new List<double>();
            Random rand = new Random(Guid.NewGuid().GetHashCode());
            for (int i = 0; i < m;i++ )
                num.Add(rand.Next(101));
            return num;
        }

        /// <summary>
        /// 随机生成x个+.-.*./符号分别用0.1.2.3代替并储存在一个整型集合中返回
        /// </summary>
        /// <param name="x">要生成的符号个数</param>
        /// <returns>一个整型集合</returns>
        public static List<int> symbolProduce(int x)
        {
            List<int> symbol = new List<int>();
            Random rand = new Random(Guid.NewGuid().GetHashCode());
            for (int i = 0; i < x; i++)
                symbol.Add(rand.Next(4));
            return symbol;
        }

 

然后我又觉得不好保存于是创建了一个题目类来保存这些信息

 /// <summary>
    /// 自定义题目类
    /// </summary>
    public class Subject
    {
        public List<double> num;                //用于储存题目中的计算数
        public List<int> symbol;                //用于储存题目中的计算符号
        public double result;                   //用于储存题目计算结果
        public Subject()                        //无参构造
        {
            num = new List<double>();
            symbol = new List<int>();
            result = 0;
        }
        public void set(List<double> num, List<int> symbol)//赋值函数
        {
            this.num = num;
            this.symbol = symbol;
        }
    }

 

于是题干信息基本解决了,到了最关键的计算环节了,其中因为我的运算符是用0,1,2,3来代替+,-,*,/来储存的,在计算两个数之间的运算时不好做,所以我设计了一个识别运算符的计算函数

/// <summary>
        /// 计算两个数的+.-.*./结果
        /// </summary>
        /// <param name="a">运算符,0.1.2.3分别代表+.-.*./运算符</param>
        /// <param name="x">第一个运算数据</param>
        /// <param name="y">第二个运算数据</param>
        /// <returns></returns>
        public static double Calculate(int a, double x, double y)
        {
            double result = 0;
            if (a == 0)
                result = x + y;
            else if (a == 1)
                result = x - y;
            else if (a == 2)
                result = x * y;
            else if (a == 3)
                result = x / y;
            return result;
        }

 

然后又出现了一个很难受的问题,就是计算中的优先级问题,乘法和除法的运算优先级肯定是比加减要高的,要优先计算,我想了很久,最后决定用递归来做。先判断运算中是否有乘号和除号,有的话找到第一个乘号或除号先计算掉然后将剩余的信息生成一个新的运算返回;若没有就将第一个运算符计算掉然后将剩余信息生成一个新的运算返回;直到返回的新运算中没有运算符说明计算完成,将计算结果保存并返回最终的对象。

/// <summary>
        /// 递归计算四则运算题目的结果并返回
        /// </summary>
        /// <param name="sb"></param>
        /// <returns>一个题目类</returns>
        public static Subject CalculateResult(Subject sb)
        {
            double result_1 = 0;            //临时计算结果
            if (sb.num.Count == 1)          //若计算完毕返回结果
            {
                sb.result = sb.num[0];
                return sb;
            }
            else if (sb.symbol.Exists(x => x == 2) || sb.symbol.Exists(x => x == 3))    //若运算中有*或/运算优先计算掉
            {
                for (int i = 0; i < sb.symbol.Count; i++)
                {
                    if (sb.symbol[i] == 2 || sb.symbol[i] == 3)                         //找到第一个为*或/的运算符
                    {
                        result_1 = Calculate(sb.symbol[i], sb.num[i], sb.num[i + 1]);   //将这个运算符计算掉
                        //将计算结果保存并生成一个新的四则运算
                        sb.num[i] = result_1;
                        sb.num.RemoveAt(i+1);
                        sb.symbol.RemoveAt(i);
                        return CalculateResult(sb);
                    }
                }
            }
            else                                                                        //运算中只有+.-运算
            {
                result_1 = Calculate(sb.symbol[0], sb.num[0], sb.num[1]);
                //将计算结果保存并生成一个新的四则运算
                sb.num[0] = result_1;
                sb.num.RemoveAt(1);
                sb.symbol.RemoveAt(0);
                return CalculateResult(sb);
            }
            return CalculateResult(sb);
        }

 

到这里,核心的算法就已经基本实现完成了,然后根据题目要求将生成的题目和答案信息输出到文件中则是小菜一碟,在程序中添加了一些代码就搞定了。

 

四.使用github克隆项目以及提交代码

4.1 进入GitHub将项目克隆到自己的仓库中

打开网址https://github.com/Jupi4ter/AchaoCalculator点击fork

4.2 下载使用Git将项目下载到本地

 在上一步点击fork后

然后新建一个文件夹进去后点击右键选择Git Bash Here出现命令行窗口输入git clone 外加复制的地址就可以克隆项目到本地了

 

 好像是网速有点慢在83%卡了一段时间,然后克隆完成后会有个文件夹,项目就在这个文件夹中

 

然后就可以上传自己的代码文件了,将自己的代码文件拷贝到这个项目文件夹中然后右键选择git bash here然后在命令窗口输入git push即可开始上传了,期间需要输入账号密码。上传成功后还需要进入github点击自己仓库界面的“New Pull Request”,然后点击Create pull request 即可成功提交。

 

五.单元测试以及效能分析

5.1单元测试

 

 5.2效能分析

 

六.感想

 感觉自己对C#运用的还不是很好,感觉算法优化上还有很大的进步空间,还有就是太久没敲代码了,以前学过的东西有些都已经忘了,还得百度一下。但是这次作业还是学到了很多东西,像单元测试,以前写代码都从来不知道有这个东西,最多打个断点单步运行一下,不会像单元测试这样把每个模块拿来测试,感觉这样做更高效。还有就是对Github有了更多的了解,虽然说以前浏览过网站上的一些项目,但是这次是自己上传了一个项目。总的来说还不错,遇到了一些困难但都解决了。

 

posted @ 2019-03-29 17:48  cadaver  阅读(321)  评论(2编辑  收藏  举报