20180925-6 四则运算试题生成

此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2148

git地址:https://git.coding.net/gongylx/f4.git

功能一:

    四则运算的功能一,最开始分析这个功能时,我和队友选择了用两人较为擅长的python进行编写,通过分析spec,总结出具体框架,要完成的目标是随机生成表达式,在控制台输入答案,后台进行运算与控制台输入的答案进行比较,给出比较的结果,控制表达式数量,用一个变量计算答对题目数目。这里控制台输入的是f4 ,通过控制台终端直接把.py文件转换成.exe程序。所以考虑实现上,决定用python 。利用python 里的random.randint()方法随机生成数字和运算符进行情况判断。这时候的代码如下:

  1 def newint(encoding='utf-8'):
  2     opr = ['+', '-', '*', '/']
  3     fh1 = random.randint(0, 3)
  4     fh2 = random.randint(0, 3)
  5     fh3 = random.randint(0, 3)
  6     n1 = random.randint(1, 20)
  7     n2 = random.randint(1, 20)
  8     n3 = random.randint(1, 20)
  9     n4 = random.randint(1, 20)
 10     rjg = 0
 11     if fh1 == 0:
 12       if fh2 == 0:
 13         if fh3 == 0:
 14           rjg = n1+n2+n3+n4
 15         elif fh3 == 1:
 16           rjg = n1+n2+n3-n4
 17         elif fh3 == 2:
 18           rjg = n1+n2+n3*n4
 19         elif fh3 == 3:
 20           rjg = n1+n2+n3/n4
 21       elif fh2 == 1:
 22         if fh3 == 0:
 23           rjg = n1+n2-n3+n4
 24         elif fh3 == 1:
 25           rjg = n1+n2-n3-n4
 26         elif fh3 == 2:
 27           rjg = n1+n2-n3*n4
 28         elif fh3 == 3:
 29           rjg = n1+n2-n3/n4
 30       elif fh2 == 2:
 31         if fh3 == 0:
 32           rjg = n1+n2*n3+n4
 33         elif fh3 == 1:
 34           rjg = n1+n2*n3-n4
 35         elif fh3 == 2:
 36           rjg = n1+n2*n3*n4
 37         elif fh3 == 3:
 38           rjg = n1+n2*n3/n4
 39       elif fh2 == 3:
 40         if fh3 == 0:
 41           rjg = n1+n2/n3+n4
 42         elif fh3 == 1:
 43           rjg = n1+n2/n3-n4
 44         elif fh3 == 2:
 45           rjg = n1+n2/n3*n4
 46         elif fh3 == 3:
 47           rjg = n1+n2/n3/n4
 48     elif fh1 == 1:
 49       if fh2 == 0:
 50         if fh3 == 0:
 51           rjg = n1-n2+n3+n4
 52         elif fh3 == 1:
 53           rjg = n1-n2+n3-n4
 54         elif fh3 == 2:
 55           rjg = n1-n2+n3*n4
 56         elif fh3 == 3:
 57           rjg = n1-n2+n3/n4
 58       elif fh2 == 1:
 59         if fh3 == 0:
 60           rjg = n1-n2-n3+n4
 61         elif fh3 == 1:
 62           rjg = n1-n2-n3-n4
 63         elif fh3 == 2:
 64           rjg = n1-n2-n3*n4
 65         elif fh3 == 3:
 66           rjg = n1-n2-n3/n4
 67       elif fh2 == 2:
 68         if fh3 == 0:
 69           rjg = n1-n2*n3+n4
 70         elif fh3 == 1:
 71           rjg = n1-n2*n3-n4
 72         elif fh3 == 2:
 73           rjg = n1-n2*n3*n4
 74         elif fh3 == 3:
 75           rjg = n1-n2*n3/n4
 76       elif fh2 == 3:
 77         if fh3 == 0:
 78           rjg = n1-n2/n3+n4
 79         elif fh3 == 1:
 80           rjg = n1-n2/n3-n4
 81         elif fh3 == 2:
 82           rjg = n1-n2/n3*n4
 83         elif fh3 == 3:
 84           rjg = n1-n2/n3/n4
 85     elif fh1 == 2:
 86       if fh2 == 0:
 87         if fh3 == 0:
 88           rjg = n1*n2+n3+n4
 89         elif fh3 == 1:
 90           rjg = n1*n2+n3-n4
 91         elif fh3 == 2:
 92           rjg = n1*n2+n3*n4
 93         elif fh3 == 3:
 94           rjg = n1*n2+n3/n4
 95       elif fh2 == 1:
 96         if fh3 == 0:
 97           rjg = n1*n2-n3+n4
 98         elif fh3 == 1:
 99           rjg = n1*n2-n3-n4
100         elif fh3 == 2:
101           rjg = n1*n2-n3*n4
102         elif fh3 == 3:
103           rjg = n1*n2-n3/n4
104       elif fh2 == 2:
105         if fh3 == 0:
106           rjg = n1*n2*n3+n4
107         elif fh3 == 1:
108           rjg = n1*n2*n3-n4
109         elif fh3 == 2:
110           rjg = n1*n2*n3*n4
111         elif fh3 == 3:
112           rjg = n1*n2*n3/n4
113       elif fh2 == 3:
114         if fh3 == 0:
115           rjg = n1*n2/n3+n4
116         elif fh3 == 1:
117           rjg = n1*n2/n3-n4
118         elif fh3 == 2:
119           rjg = n1*n2/n3*n4
120         elif fh3 == 3:
121           rjg = n1*n2/n3/n4
122     elif fh1 == 3:
123       if fh2 == 0:
124         if fh3 == 0:
125           rjg = n1/n2+n3+n4
126         elif fh3 == 1:
127           rjg = n1/n2+n3-n4
128         elif fh3 == 2:
129           rjg = n1/n2+n3*n4
130         elif fh3 == 3:
131           rjg = n1/n2+n3/n4
132       elif fh2 == 1:
133         if fh3 == 0:
134           rjg = n1/n2-n3+n4
135         elif fh3 == 1:
136           rjg = n1/n2-n3-n4
137         elif fh3 == 2:
138           rjg = n1/n2-n3*n4
139         elif fh3 == 3:
140           rjg = n1/n2-n3/n4
141       elif fh2 == 2:
142         if fh3 == 0:
143           rjg = n1/n2*n3+n4
144         elif fh3 == 1:
145           rjg = n1/n2*n3-n4
146         elif fh3 == 2:
147           rjg = n1/n2*n3*n4
148         elif fh3 == 3:
149           rjg = n1/n2*n3/n4
150       elif fh2 == 3:
151         if fh3 == 0:
152           rjg = n1/n2/n3+n4
153         elif fh3 == 1:
154           rjg = n1/n2/n3-n4
155         elif fh3 == 2:
156           rjg = n1/n2/n3*n4
157         elif fh3 == 3:
158           rjg = n1/n2/n3/n4
159     print(n1, opr[fh1], n2,opr[fh2] ,n3 ,opr[fh3], n4 ,'= ', end='')
160     return rjg

      这里实现4个数字和3个运算符的表达式的方法我们俩人都认为比较笨拙,虽然功能实现了,但是代码十分冗余,这里考虑到用栈、逆波兰式去计算,但是又碍于自己的python编程能力还不精进,这时候又考虑到后面的功能2和3,需要加上括号,这时候如果再用列举的方法去实现的话,形式太多,很难实现。这时候选择了更换语言,我们俩商量结果是用老师推荐的 C# 和 VS 环境进行编写,由于本科学习的C#至今没用过,所以我们决定在复习中编码,首先我们俩从网上百度用C#实现四则运算的方法,然后我们俩一人选了一个觉得功能比较全的进行剖析学习,互相讲解,这时候发现了一系列的问题。

    对于功能一,首先是用Random方法实现数字和运算符的生成。这里运用switch进行判断识别+-*/,这里遇到的难点是老师spec里讲到的不允许出现除不尽的小数,我们百度了好多,最后选择用度娘的一个方法,我们要避免十进制下的无限小数,只需要让被除数的素因子只有2和5,所以我们将分别判断后三个数为被除数的时候,3种情况下,我们将这3个被除数生成为素因子2和5的幂的形式,这样就保证了表达式结果不会出现无限循环的小数,代码如下:

 1 public class Test
 2     {
 3         public char RandSymbol()//生成运算符
 4         {
 5             Random r = new Random();
 6             int rr = r.Next(4);
 7             switch (rr)
 8             {
 9                 case 0:
10                     return '+';
11                 case 1:
12                     return '-';
13                 case 2:
14                     return '*';
15                 case 3:
16                     return '/';
17                 default:
18                     return '0';
19             }
20         }
21 
22         public int RandNumber()//生成一个0到100的数
23         {
24             Random rn = new Random();
25             return rn.Next(13);
26         }
27         public double ansr = 0;//表达式的结果  
28         public int num1, num2, num3, num4;//生成4个数字进行运算
29         public int n2, m5;//pow(2,n)*pow(5,m)
30         public char op1, op2, op3;//运算符
31         public int BracketPattern;//增加括号
32         public char eq = '=';//等号
33         public char lb = '(';//左括号
34         public char rb = ')';//右括号
35         public string ToEval;//表达式的累加
36         public void GetExp()//获取没有括号的表达式
37         {
38             num1 = RandNumber();
39             System.Threading.Thread.Sleep(15);
40             num2 = RandNumber();
41             System.Threading.Thread.Sleep(15);
42             num3 = RandNumber();
43             System.Threading.Thread.Sleep(15);
44             num4 = RandNumber();
45             System.Threading.Thread.Sleep(15);
46             op1 = RandSymbol();
47             System.Threading.Thread.Sleep(15);
48             op2 = RandSymbol();
49             System.Threading.Thread.Sleep(15);
50             op3 = RandSymbol();
51             if (op1 == '/')//如果我们要避免十进制下的无限小数,只需要让被除数的素因子只有2和5,以下同理。
52             {
53                 Random rd = new Random();
54                 n2 = rd.Next(1, 5);
55                 System.Threading.Thread.Sleep(15);
56                 m5 = rd.Next(1, 3);
57                 num2 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
58             }
59             if (op2 == '/')
60             {
61                 Random rd = new Random();
62                 n2 = rd.Next(1, 5);
63                 System.Threading.Thread.Sleep(15);
64                 m5 = rd.Next(1, 3);
65                 num3 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
66             }
67             if (op3 == '/')
68             {
69                 Random rd = new Random();
70                 n2 = rd.Next(1, 5);
71                 System.Threading.Thread.Sleep(15);
72                 m5 = rd.Next(1, 3);
73                 num4 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
74             }
75             ToEval = num1.ToString() + op1.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString();
76             GetAnsr();
77         
78         }

这里为了更好的实现以后的功能,我们采用了后缀表达式和栈的辅助去处理表达式,计算出结果,然后将控制台输入的结果进行比较,得出答案。展示表达式的代码如下:

 1 public void DispExp()//展示表达式
 2         {
 3             string Disp = ToEval + eq;
 4             Console.WriteLine("{0}", Disp);
 5         }
 6         public void DispExpAns(Test t)
 7         {
 8             string Disp = ToEval + eq;
 9             if (Math.Abs((double)Math.Round(t.ansr) - t.ansr) < 1e-7)
10             {
11                 Console.WriteLine("{0,-20}{1,-7}", Disp, (int)t.ansr);
12             }
13             else
14             {
15                 string floatValue = t.ansr.ToString();
16                 floatValue = floatValue.TrimEnd('.', '0');
17                 Console.WriteLine("{0,-20}{1,-7}", Disp, floatValue);
18 
19             }
20         }

计算答案的方式采用调用逆波兰的表达式的方法,去计算逆波兰表达式的值传递给计算答案,代码如下:

public void GetAnsr()//计算答案
        {
            string TE = ToEval;
            Random rd = new Random();
            this.ansr = this.Calucate(TE);//调用计算逆波兰表达式的方法
                                          //   Console.WriteLine("ans is {0}", this.ansr);
        }

计算答案的时候就要考虑到的问题便是利用栈去计算逆波兰表达式,这时候要用到的是运算符的优先级,确保表达式是按照规定优先级进行运算的,代码如下:

static bool IsSize(string s)//是运算符
        {
            string ts = "+-*/%^";
            return ts.IndexOf(s) > -1;
        }

        Dictionary<char, int> priorities = null;//优先级
        const string operators = "+-*/%^";
        public void opinit()//初始化优先级
        {
            priorities = new Dictionary<char, int>();
            priorities.Add('#', -1);
            priorities.Add('+', 0);
            priorities.Add('-', 0);
            priorities.Add('*', 1);
            priorities.Add('/', 1);
            priorities.Add('%', 1);
            priorities.Add('^', 2);
        }

具体的利用转逆波兰的方式去计算答案的代码如下:

double Compute(double leftNum, double rightNum, char op)//计算答案
        {
            switch (op)
            {
                case '+': return leftNum + rightNum;
                case '-': return leftNum - rightNum;
                case '*': return leftNum * rightNum;
                case '/': return leftNum / rightNum;
                case '%': return leftNum % rightNum;
                case '^': return Math.Pow(leftNum, rightNum);
                default: return 0;
            }
        }

        bool IsOperator(char op)
        {
            return operators.IndexOf(op) > -1;
        }

        bool IsLeftAssoc(char op)
        {
            return op == '+' || op == '-' || op == '*' || op == '/' || op == '%';
        }

        Queue<object> PreOrderToPostOrder(string expression)//转逆波兰表达式
        {
            var result = new Queue<object>();
            var operatorStack = new Stack<char>();
            operatorStack.Push('#');
            char top, cur, tempChar;
            string tempNum;
            if (expression[0] == '-')
                expression = '0' + expression;
            for (int i = 0, j; i < expression.Length;)
            {
                cur = expression[i++];
                top = operatorStack.Peek();

                if (cur == '(')
                {
                    operatorStack.Push(cur);
                }
                else
                {
                    if (IsOperator(cur))
                    {
                        while (IsOperator(top) && ((IsLeftAssoc(cur) && priorities[cur] <= priorities[top])) || (!IsLeftAssoc(cur) && priorities[cur] < priorities[top]))
                        {
                            result.Enqueue(operatorStack.Pop());
                            top = operatorStack.Peek();
                        }
                        operatorStack.Push(cur);
                    }
                    else if (cur == ')')
                    {
                        while (operatorStack.Count > 0 && (tempChar = operatorStack.Pop()) != '(')
                        {
                            result.Enqueue(tempChar);
                        }
                    }
                    else
                    {
                        tempNum = "" + cur;
                        j = i;
                        while (j < expression.Length && (expression[j] == '.' || (expression[j] >= '0' && expression[j] <= '9')))
                        {
                            tempNum += expression[j++];
                        }
                        i = j;
                        result.Enqueue(tempNum);
                    }
                }
            }
            while (operatorStack.Count > 0)
            {
                cur = operatorStack.Pop();
                if (cur == '#') continue;
                if (operatorStack.Count > 0)
                {

                    top = operatorStack.Peek();
                }

                result.Enqueue(cur);
            }

            return result;
        }

        public double Calucate(string expression)//计算表达式的值
        {
            try
            {
                var rpn = PreOrderToPostOrder(expression);
                var operandStack = new Stack<double>();
                double left, right;
                object cur;
                while (rpn.Count > 0)
                {
                    cur = rpn.Dequeue();
                    if (cur is char)
                    {
                        right = operandStack.Pop();
                        left = operandStack.Pop();
                        operandStack.Push(Compute(left, right, (char)cur));
                    }
                    else
                    {
                        operandStack.Push(double.Parse(cur.ToString()));
                    }
                }
                return operandStack.Pop();
            }
            catch
            {
                throw new Exception("表达式格式不正确!");
            }
        }
    }

 主函数里判断控制台输入的是否有-c ,如果没有-c,则实现的便是功能一,这时候通过判断计算答案和表达式结果的比较,这里利用两数相减结果在小数点后7位内相等则判定正确。具体的主函数代码如下:

static void Main(string[] args)
        {
            int num;//输入表达式中的数字
            int cnt = 0;
            int token = 0;
            var arguments = CommandLineArgumentParser.Parse(args);//命令行参数
            int anslen = 1;//用来作为表达式的结果
            double[] ansrep;//排列存储结果
            ansrep = new double[1000];
            ansrep[0] = -23579;
            if (!arguments.Has("-c"))//如果命令行参数没有-c就输出20个算式
                num = 20;
            else
            {
                num = int.Parse(arguments.Get("-c").Next);//命令行参数中得到要输出的表达式数量
                if (num <= 0)
                {
                    throw
                          new Exception("题目数量必须为 正整数!");
                }
                token = 1;
            }
            if (token == 0)
            {
                for (int i = 0; i < num; i++)
                {
                    Test t = new Test();//new Test
                    t.opinit();
                    t.GetBracketExp();
                    // t.GetExp();
                    //t.NoRepeatedAns(anslen, ansrep);
                    ansrep[(anslen++) - 1] = t.ansr;
                    t.DispExp();//显示表达式
                    Console.Write("?");//控制台显示
                    double ans = double.Parse(Console.ReadLine());
                    // Console.WriteLine("{0},{1}",ans,t.ansr);
                    if (Math.Abs(ans - t.ansr) < 1e-7)//答案正确
                    {
                        Console.WriteLine("答对啦,你真是个天才!");
                        cnt++;
                    }
                    else//答案错误
                    {
                        if (Math.Abs((double)Math.Round(t.ansr) - t.ansr) < 1e-7)
                        {
                            Console.WriteLine("再想想吧,答案似乎是{0}喔! ", (int)t.ansr);
                        }
                        else//十进制
                        {
                            string floatValue = t.ansr.ToString();
                            floatValue = floatValue.TrimEnd('.', '0');
                            Console.WriteLine("再想想吧,答案似乎是{0}喔!", floatValue);

                        }
                    }
                    
                }
                Console.WriteLine("你一共答对{0}道题,共20道题。", cnt);
            }
            else//实现打印
            {
                for (int i = 0; i < num; i++)
                {
                    Test t = new Test();//new Test
                    t.opinit();
                    t.GetBracketExp();
                    ansrep[(anslen++) - 1] = t.ansr;
                    t.DispExpAns(t);//展示表达式和答案

                }
            }
            
        }

这里功能一的实现在控制台直接输入程序名字,然后自动生成默认的20道题,回答正确得到回复,错误得到回复然后告诉正确答案,最后给出答对题目的数量和题目总数量。功能实现如下图所示:

这里默认的20道题结束时,给出总结,如下图:

功能二:

    这里功能二的实现是在功能一的基础上实现括号的加入,这里最难的就是当时考虑到括号的加入到底应该如何判断情况,这里我们考虑到的第一种方法是递归的方法,将表达式进行分解,遇到括号的时候先计算括号里面的,然后将结果值存入变量再进行运算。第二种方法便是老师提到的利用栈和逆波兰式进行计算,将所有的表达式入栈,然后利用入栈出栈将相邻最近的两数进行运算,得出总的表达式的值,和计算结果进行比较。

    这里最难的地方是括号情况的判断,4个数字和3个运算符,括号位置一共有9种情况,这里同样的要对被除数进行处理,保证答案不会有无限循环的小数,功能实现图与功能一实现图相同,具体代码如下:

 1  public void GetBracketExp()//获取有括号的表达式
 2         {
 3             num1 = RandNumber();
 4             System.Threading.Thread.Sleep(15);
 5             num2 = RandNumber();
 6             System.Threading.Thread.Sleep(15);
 7             num3 = RandNumber();
 8             System.Threading.Thread.Sleep(15);
 9             num4 = RandNumber();
10             System.Threading.Thread.Sleep(15);
11             op1 = RandSymbol();
12             System.Threading.Thread.Sleep(15);
13             op2 = RandSymbol();
14             System.Threading.Thread.Sleep(15);
15             op3 = RandSymbol();
16             Random rdm = new Random();
17             int brkp = rdm.Next(11);//括号存在的方式
18             if (brkp != 0)//brkp为0时不是包含括号的表达式
19             {
20                 Random rd = new Random();
21                 n2 = rd.Next(1, 3);
22                 System.Threading.Thread.Sleep(15);
23                 m5 = rd.Next(1, 2);
24                 num2 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
25                 n2 = rd.Next(1, 3);
26                 System.Threading.Thread.Sleep(15);
27                 m5 = rd.Next(1, 2);
28                 num3 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
29                 n2 = rd.Next(1, 3);
30                 System.Threading.Thread.Sleep(15);
31                 m5 = rd.Next(1, 2);
32                 num4 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
33                 num1 = num2 * num3 * num4;
34             }
35             else
36             {
37                 if (op1 == '/')
38                 {
39                     Random rd = new Random();
40                     n2 = rd.Next(1, 3);
41                     System.Threading.Thread.Sleep(15);
42                     m5 = rd.Next(1, 2);
43                     num2 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
44                 }
45                 if (op2 == '/')
46                 {
47                     Random rd = new Random();
48                     n2 = rd.Next(1, 3);
49                     System.Threading.Thread.Sleep(15);
50                     m5 = rd.Next(1, 2);
51                     num3 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
52                 }
53                 if (op3 == '/')
54                 {
55                     Random rd = new Random();
56                     n2 = rd.Next(1, 3);
57                     System.Threading.Thread.Sleep(15);
58                     m5 = rd.Next(1, 2);
59                     num4 = (int)(Math.Pow(2, n2) * Math.Pow(5, m5));
60                 }
61             }
62 
63             switch (brkp)
64             {
65                 case 0: ToEval = num1.ToString() + op1.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString(); break;
66                 case 1: ToEval = lb.ToString() + num1.ToString() + op1.ToString() + num2.ToString() + rb.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString(); break;
67                 case 2: ToEval = lb.ToString() + num1.ToString() + op1.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + op3.ToString() + num4.ToString(); break;
68                 case 3: ToEval = lb.ToString() + lb.ToString() + num1.ToString() + op1.ToString() + num2.ToString() + rb.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + op3.ToString() + num4.ToString(); break;
69                 case 4: ToEval = lb.ToString() + num1.ToString() + op1.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + rb.ToString() + op3.ToString() + num4.ToString(); break;
70                 case 5: ToEval = num1.ToString() + op1.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + op3.ToString() + num4.ToString(); break;
71                 case 6: ToEval = num1.ToString() + op1.ToString() + lb.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + rb.ToString() + op3.ToString() + num4.ToString() + rb.ToString(); break;
72                 case 7: ToEval = num1.ToString() + op1.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString() + rb.ToString(); break;
73                 case 8: ToEval = num1.ToString() + op1.ToString() + lb.ToString() + num2.ToString() + op2.ToString() + lb.ToString() + num3.ToString() + op3.ToString() + num4.ToString() + rb.ToString() + rb.ToString(); break;
74                 case 9: ToEval = lb.ToString() + num1.ToString() + op1.ToString() + num2.ToString() + rb.ToString() + op2.ToString() + lb.ToString() + num3.ToString() + op3.ToString() + num4.ToString() + rb.ToString(); break;
75                 default: ToEval = num1.ToString() + op1.ToString() + num2.ToString() + op2.ToString() + num3.ToString() + op3.ToString() + num4.ToString(); break;
76             }
77             GetAnsr();
78         }

功能三:

    功能三是要在控制台输入-c X,这里的spec要求是将控制台参数作为生成题目数量,这里的难点就是main函数中的情况判断,命令行参数获取类的代码如下:

 public class CommandLineArgument//命令行参数获取类
    {
        List<CommandLineArgument> _arguments;

        int _index;

        string _argumentText;

        public CommandLineArgument Next
        {
            get
            {
                if (_index < _arguments.Count - 1)
                {
                    return _arguments[_index + 1];
                }

                return null;
            }
        }
        public CommandLineArgument Previous
        {
            get
            {
                if (_index > 0)
                {
                    return _arguments[_index - 1];
                }

                return null;
            }
        }
        internal CommandLineArgument(List<CommandLineArgument> args, int index, string argument)
        {
            _arguments = args;
            _index = index;
            _argumentText = argument;
        }

        public CommandLineArgument Take()
        {
            return Next;
        }

        public IEnumerable<CommandLineArgument> Take(int count)
        {
            var list = new List<CommandLineArgument>();
            var parent = this;
            for (int i = 0; i < count; i++)
            {
                var next = parent.Next;
                if (next == null)
                    break;

                list.Add(next);

                parent = next;
            }

            return list;
        }

        public static implicit operator string(CommandLineArgument argument)
        {
            return argument._argumentText;
        }

        public override string ToString()
        {
            return _argumentText;
        }
    }
    public class CommandLineArgumentParser//命令行参数解析器
    {

        List<CommandLineArgument> _arguments;
        public static CommandLineArgumentParser Parse(string[] args)
        {
            return new CommandLineArgumentParser(args);
        }

        public CommandLineArgumentParser(string[] args)
        {
            _arguments = new List<CommandLineArgument>();

            for (int i = 0; i < args.Length; i++)
            {
                _arguments.Add(new CommandLineArgument(_arguments, i, args[i]));
            }

        }

        public CommandLineArgument Get(string argumentName)
        {
            return _arguments.FirstOrDefault(p => p == argumentName);
        }

        public bool Has(string argumentName)
        {
            return _arguments.Count(p => p == argumentName) > 0;
        }
    }
}

功能实现图:

 

对于结对编程的体会:

      结对编程的最大好处就在于能够结合俩个人的算法逻辑方面的思维,设计出更为优秀的算法,提高代码质量。结对编程中,双方的互动目的在于开启思路,避免单独编程时思维容易阻塞的情况。在编程期间,两人的角色切换至少6次,两人轮流,不会太过与疲惫。编程耗时最多的方面就是debug,在我们得出设计思路,并将它们初次转化成代码后,编程之路其实才走了一小段。由于个人的疏忽,输入的错误,以及设计思路的偏差,往往会让我们的程序陷入无止尽的BUG泥潭中,难以挣脱,这会消耗我们大量的时间。而结对编程的好处就在于此,由于身边有个领航员角色的存在,在编写代码时,一旦出现输入错误,就会有人及时的提醒。并且,在设计代码时,有个同伴可以一起讨论,融合两个人不同的见解和观点,我们往往可以得出更加准确且更加高效的设计思路。这一切都为我们在完成代码后的debug过程省去了大量的时间。  就我们本次实验一的编程而言,有了领航员的存在,我们在完成代码后,几乎没有花什么时间在debug上,甚至很多阶段性的代码都是一次通过,这大大提高了我们编程的效率,而且我们二人一起讨论出来的编程思路,也使得我们的代码功能更全面,效率更高。

 

5项在编码、争论、复审等活动中花费时间较长,给你较大收获的事件:

(1)第一个争论点是对于编程语言的选择。我擅长Java,而队友擅长Python。后来由于我对Python处于入门阶段,队友对Java完全不通的状态下,且咨询学长学姐后,发现此程序更适合用Python,所以后来初步选择了Python语言。

(2)花费时间较长的在于后期换了语言重新编码。因为用Python实现功能一,我们使用繁琐的 elif 穷举了四个数字以及三种运算符组合的所有情况,导致功能一就使用了300多行代码。在此基础上无法实现功能二。无可奈何之下换了C#语言。虽然后来听说Python有随机生成数字和符号的方法,但也为时已晚。这种临阵换将的做法耗费了大量的编程时间。在以后的编程中,我一定会意志坚定不会遇到困难就轻易转换语言,太过纠结语言并不是成熟的表现。

(3)第二个争论点是利用转逆波兰的方式去计算答案。看到作业要求时,完全忘记了“逆波兰”和“后缀表达式”都是什么。于是我又找出了本科期间的数据结构教材复习一遍,可还是不能完全理解。后来我想到可以用递归方法实现,但是队友坚持利用堆栈和逆波兰,后来我担心递归不符合作业要求,才算和队友达成一致观点使用逆波兰。

(4)第三个争论点是如何处理答案是无限循环小数的情况(即除不尽的情况),我们开始商量的结果是不让被除数为3,后来想到只是不为3还不行,例如13等其他数字也会有这种情况,这时候我们遇到了困难,达到了所学知识的瓶颈,然后我们通过咨询学长,百度,pull别人的代码分析,最终看到了这个解决方法,将被除数设定为素因子只含2和5的数,这时候避免了bug的出现。

(5)较大收获的事件就是重新借此机会复习了一下C#,自从大二学过C#后,就一直没在用过了。十一假期的时候我找出了本科期间的C#教材温习了一遍,虽然达不到精进但终有一些收获,希望在日后学习中自己能够熟练掌握Java,C#和Python。

 

 

工作地点:东北师范大学净月二食堂一楼

 

 

 

 



posted @ 2018-10-08 15:35  Ljr6899  阅读(190)  评论(0编辑  收藏  举报