【结对项目总结】优化的四则运算生成器

结对小组信息:

13070027 郑亦然

13070038 李芳达

基于之前的个人项目(http://www.cnblogs.com/yuki8819/p/5305107.html),本项目将主体功能封装,并加入了新的控制模块,并且制作了GUI

效果如图

程序主要分为三个模块:Controller, Generator, Calculator

Controller负责控制GUI,与后台交互

Generator封装了生成算式的功能

Calculator封装了计算算式的功能

关于Calculator和Generator的设计可见http://www.cnblogs.com/yuki8819/p/5305107.html

Generator支持参数修改:本轮生成多少算式?算式中运算数的最大数值?算式长度?

使用主界面中的Option按钮可以进入修改参数的界面

按下Next按钮可以生成一条算式,在输入框中输入答案后,按OK按钮可以得到结果(作对或做错,以及正确答案)

做完规定的题数后,会得到最后的得分(即作对的题数)

按Restart键可以重新开始一轮答题

测试方面,由于这个程序本身在输入上不会出现非法输入(输入框有格式限制),所以我新建了一个控制台程序来测试Calculator模块,代码如下:

1 static void Main(string[] args)
2 {
3     while (true)
4     {
5         string line = Console.ReadLine();
6         Console.WriteLine(Calculate(line));
7     }
8 }

输入算式,由CMD显示运算结果或错误提示

输入错误测试:

+12-34(以符号开始)

12-34+(以符号结束)

12++34*56(连续的运算符)

12+34/0-56*78(0作被除数)

12x45+56*78/23(非法字符)

(空算式)

12+34/56*78(正确算式)

结果:

这次的结对项目是我和同学李芳达一起完成的,在设计过程中,我们一起讨论了几种可行的解决方案,最后选择了上述方案。对于GUI的选择,我们使用了Unity3D的GUI系统。虽然我们都对这个引擎不很熟悉,但是我们对它很感兴趣,所以决定一起学习使用这个引擎。过程还是比较顺利的,最终结果也比较令人满意。

全部源代码:

PS: 源代码需要在Unity3D工程下才可以运行

Controller

  1 using UnityEngine;
  2 using System.Collections;
  3 using UnityEngine.UI;
  4 using System;
  5 
  6 public class Controller : MonoBehaviour 
  7 {
  8     public GameObject field_Answer;
  9     public GameObject btn_Next;
 10     public GameObject btn_Restart;
 11     public GameObject btn_Options;
 12     public GameObject btn_OK;
 13     public GameObject txt_Quiz;
 14     public GameObject txt_Result;
 15 
 16     public GameObject OptionText;
 17 
 18     public GameObject field_Amount;
 19     public GameObject field_Max;
 20     public GameObject field_Operators;
 21 
 22     public Generator generator;
 23 
 24     public string result;
 25     public int count;
 26     public int correct;
 27 
 28     // Use this for initialization
 29     void Start()
 30     {
 31         generator = new Generator();
 32         field_Answer = new GameObject();
 33         btn_Next = new GameObject();
 34         btn_Restart = new GameObject();
 35         btn_Options = new GameObject();
 36         btn_OK = new GameObject();
 37         OptionText = new GameObject();
 38         txt_Quiz = new GameObject();
 39         txt_Result = new GameObject();
 40         field_Amount = new GameObject();
 41         field_Max = new GameObject("field_Max");
 42         field_Operators = new GameObject("field_Operators");
 43 
 44         field_Answer = GameObject.Find("field_Answer");
 45         btn_Next = GameObject.Find("btn_Next");
 46         btn_Restart = GameObject.Find("btn_Restart");
 47         btn_Options = GameObject.Find("btn_Options");
 48         btn_OK = GameObject.Find("btn_OK");
 49         txt_Quiz = GameObject.Find("txt_Quiz");
 50         txt_Result = GameObject.Find("txt_Result");
 51 
 52         OptionText = GameObject.Find("OptionText");
 53 
 54         field_Amount = GameObject.Find("field_Amount");
 55         field_Max = GameObject.Find("field_Max");
 56         field_Operators = GameObject.Find("field_Operators");
 57 
 58 
 59 
 60         field_Amount.SetActive(false);
 61         field_Max.SetActive(false);
 62         field_Operators.SetActive(false);
 63         txt_Result.SetActive(false);
 64 
 65         count = 0;
 66         correct = 0;
 67     }
 68 
 69     // Update is called once per frame
 70     void Update()
 71     {
 72         
 73     }
 74 
 75     public void OnNext()
 76     {
 77         generator.GenerateLines();
 78         Text txt = txt_Quiz.GetComponent<Text>();
 79         txt.text = generator.lines;
 80         result = Calculator.Calculate(generator.lines_final, generator.tf);
 81         Debug.Log(result);
 82         btn_OK.SetActive(true);
 83         InputField inf = field_Answer.GetComponent<InputField>();
 84         inf.text = "";
 85     }
 86 
 87     public void OnOK()
 88     {
 89         count++;
 90         btn_OK.SetActive(false);
 91         InputField inf = field_Answer.GetComponent<InputField>();
 92         if (inf.text == result)
 93         {
 94             correct++;
 95             Text txt = txt_Quiz.GetComponent<Text>();
 96             txt.text = "Correct!";
 97         }
 98         else
 99         {
100             Text txt = txt_Quiz.GetComponent<Text>();
101             txt.text = "Wrong answer! The answer should be: " + result;
102         }
103         if (count >= generator.rows)
104         {
105             txt_Result.SetActive(true);
106             Text txt = txt_Result.GetComponent<Text>();
107             txt.text = "Finished!
Your Score is: " + correct + " out of " + count;
108             btn_Next.SetActive(false);
109         }
110     }
111 
112     public void OnRestart()
113     {
114         btn_OK.SetActive(false);
115         count = 0;
116         correct = 0;
117         Text txt = txt_Quiz.GetComponent<Text>();
118         txt.text = "";
119         txt_Result.SetActive(false);
120         btn_Next.SetActive(true);
121     }
122 
123     public void OnOptions()
124     {
125         if (!field_Amount.active)
126         {
127             field_Amount.SetActive(true);
128             InputField infa = field_Amount.GetComponent<InputField>();
129             infa.text = "" + generator.rows;
130             field_Max.SetActive(true);
131             InputField infm = field_Max.GetComponent<InputField>();
132             infm.text = "" + generator.max;
133             field_Operators.SetActive(true);
134             InputField info = field_Operators.GetComponent<InputField>();
135             info.text = "" + generator.operators;
136 
137             field_Answer.SetActive(false);
138             btn_Next.SetActive(false);
139             txt_Quiz.SetActive(false);
140             btn_OK.SetActive(false);
141             txt_Result.SetActive(false);
142 
143             Text txt = OptionText.GetComponent<Text>();
144             txt.text = "Confirm";
145         }
146         else
147         {
148             field_Amount.SetActive(false);
149             InputField infa = field_Amount.GetComponent<InputField>();
150             generator.rows = Int32.Parse(infa.text);
151             field_Max.SetActive(false);
152             InputField infm = field_Max.GetComponent<InputField>();
153             generator.max = Int32.Parse(infm.text);
154             field_Operators.SetActive(false);
155             InputField info = field_Operators.GetComponent<InputField>();
156             generator.operators = Int32.Parse(info.text);
157 
158             field_Answer.SetActive(true);
159             btn_Next.SetActive(true);
160             txt_Quiz.SetActive(true);
161             btn_OK.SetActive(false);
162             txt_Result.SetActive(false);
163 
164             Text txt = OptionText.GetComponent<Text>();
165             txt.text = "Options";
166             OnRestart();
167         }
168         
169     }
170 }
View Code

Generator

  1 using System;
  2 using System.Reflection;
  3 using System.Globalization;
  4 using Microsoft.CSharp;
  5 using System.CodeDom;
  6 using System.CodeDom.Compiler;
  7 using System.Text;
  8 using System.Collections.Generic;
  9 using System.IO;
 10 
 11 using UnityEngine;
 12 using System.Collections;
 13 
 14 
 15 public class Generator
 16 {
 17     public int max;//最大数值
 18     public int rows;//生成算式个数
 19     public int operators;//每行运算符个数
 20     public List<int> nums;
 21     public List<int> add_n_minus;
 22     public List<int> div;
 23     public List<int> div_nums;
 24     public int tf;//通分分母
 25     public int amount;
 26     public string lines;
 27     public string lines_tf;//通分分母字符串
 28     public string lines_final;//通分分子字符串
 29     public int count;
 30 
 31 
 32     public Generator()
 33     {
 34         max = 50;
 35         rows = 10;
 36         operators = 10;
 37     }
 38 
 39 
 40     public void GenerateLines()
 41     {
 42         tf = 1;
 43         nums = new List<int>();
 44         add_n_minus = new List<int>();
 45         div = new List<int>();
 46         div_nums = new List<int>();
 47         System.Random rnd = new System.Random(GetRandomSeed());
 48         amount = rnd.Next(1, operators + 1);
 49         lines = "";
 50         lines_tf = "";
 51         lines_final = "";
 52 
 53         int x = 0;
 54         int d = 0;
 55         for (int i = 0; i < amount; i++)
 56         {
 57             //A new number
 58             rnd = new System.Random(GetRandomSeed());
 59             nums.Add(rnd.Next(1, max));
 60             lines += nums[i];
 61             //A new operator
 62             System.Random rnd0 = new System.Random(GetRandomSeed());
 63             int key = rnd0.Next(0, 4);
 64             switch (key)
 65             {
 66                 case 0:
 67                     x = 0;
 68                     lines += "+";
 69                     add_n_minus.Add(lines.Length);
 70                     break;
 71                 case 1:
 72                     x = 0;
 73                     lines += "-";
 74                     add_n_minus.Add(lines.Length);
 75                     break;
 76                 case 2:
 77                     x++;
 78                     if (x <= 3)
 79                     {
 80                         lines += "*";
 81                         break;
 82                     }
 83                     else
 84                     {
 85                         goto case 1;
 86                     }
 87                 case 3:
 88                     x = 0;
 89                     d++;
 90                     if (d <= 3)
 91                     {
 92                         lines += "/";
 93                         div.Add(i);
 94                         break;
 95                     }
 96                     else
 97                     {
 98                         goto case 1;
 99                     }
100                 default:
101                     x = 0;
102                     break;
103             }
104         }
105 
106         rnd = new System.Random(GetRandomSeed());
107         nums.Add(rnd.Next(1, max));
108         lines += nums[amount];
109 
110         for (int i = 0; i < div.Count; i++)
111         {
112             div_nums.Add(nums[div[i] + 1]);
113             lines_tf += div_nums[i];
114             lines_tf += "*";
115             tf *= div_nums[i];
116         }
117 
118         lines_final += lines_tf;
119         lines_final += lines;
120 
121         if (div.Count > 0)
122         {
123             for (int i = 1; i <= add_n_minus.Count; i++)
124             {
125                 lines_final = lines_final.Insert(i * lines_tf.Length + add_n_minus[i - 1], lines_tf);
126             }
127         }
128     }
129 
130     public int GetRandomSeed()
131     {
132         byte[] bytes = new byte[4];
133         System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
134         rng.GetBytes(bytes);
135         return BitConverter.ToInt32(bytes, 0);
136     }
137 }
View Code

Calculator

  1 using UnityEngine;
  2 using System;
  3 using System.Reflection;
  4 using System.Globalization;
  5 using Microsoft.CSharp;
  6 using System.CodeDom;
  7 using System.CodeDom.Compiler;
  8 using System.Text;
  9 using System.Collections.Generic;
 10 using System.IO;
 11 using System.Collections;
 12 
 13 static class Calculator
 14 {
 15     public static string Calculate(string lines)
 16     {
 17         if (lines[0] < '0' || lines[0] > '9')
 18         {
 19             return "Error: the formula must be begun with a number";
 20         }
 21         if (lines[lines.Length - 1] < '0' || lines[lines.Length - 1] > '9')
 22         {
 23             return "Error: the formula must be ended with a number";
 24         }
 25         for (int i = 0; i < lines.Length; i++)
 26         {
 27             if ((lines[i] >= '0' && lines[i] <= '9') || lines[i] == '+' || lines[i] == '-' || lines[i] == '*' || lines[i] == '/')
 28             {
 29                 if (lines[i] < '0' || lines[i] > '9')
 30                 {
 31                     if (lines[i + 1] < '0' || lines[i + 1] > '9')
 32                     {
 33                         return "Error: continuous operators are not allowed";
 34                     }
 35                     if (lines[i] == '/')
 36                     {
 37                         if (lines[i + 1] == '0')
 38                         {
 39                             return "Error: 0 cannot be divided";
 40                         }
 41                     }
 42                 }
 43             }
 44             else
 45             {
 46                 return "Error: invalid characters included";
 47             }
 48         }
 49 
 50         string temp = lines;
 51         List<int> nums = new List<int>();
 52         List<int> add_n_minus = new List<int>();
 53         List<int> div = new List<int>();
 54         List<int> div_nums = new List<int>();
 55         string lines_tf = "";
 56         string lines_final = "";
 57         int tf = 1;
 58         for (int i = temp.Length; i >= 0; i--)
 59         {
 60             if (temp[i] == '+' || temp[i] == '-' || temp[i] == '*' || temp[i] == '/')
 61             {
 62                 string n = temp.Substring(i + 1, temp.Length - i);
 63                 temp = temp.Remove(i);
 64                 nums.Add(Int32.Parse(n));
 65                 if (temp[i] == '+' || temp[i] == '-')
 66                 {
 67                     add_n_minus.Add(lines.Length - i);
 68                 }
 69                 else if (temp[i] == '/')
 70                 {
 71                     div.Add(nums.Count);
 72                 }
 73             }
 74         }
 75         nums.Add(Int32.Parse(temp));
 76         nums.Reverse(0,nums.Count - 1);
 77         div.Reverse();
 78         for (int i = 0; i < div.Count; i++)
 79         {
 80             div[i] = nums.Count - div[i];
 81         }
 82         for (int i = 0; i < div.Count; i++)
 83         {
 84             div_nums.Add(nums[div[i] + 1]);
 85             lines_tf += div_nums[i];
 86             lines_tf += "*";
 87             tf *= div_nums[i];
 88         }
 89 
 90         lines_final += lines_tf;
 91         lines_final += lines;
 92 
 93         if (div.Count > 0)
 94         {
 95             for (int i = 1; i <= add_n_minus.Count; i++)
 96             {
 97                 lines_final = lines_final.Insert(i * lines_tf.Length + add_n_minus[i - 1], lines_tf);
 98             }
 99         }
100 
101         // 1.CSharpCodePrivoder
102         CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();
103 
104         // 2.ICodeComplier
105         ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler();
106 
107         // 3.CompilerParameters
108         CompilerParameters objCompilerParameters = new CompilerParameters();
109         objCompilerParameters.ReferencedAssemblies.Add("System.dll");
110         objCompilerParameters.GenerateExecutable = false;
111         objCompilerParameters.GenerateInMemory = true;
112 
113         // 4.CompilerResults
114 
115 
116         CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode(lines_final, tf));
117 
118         if (cr.Errors.HasErrors)
119         {
120             Debug.Log("编译错误:");
121             foreach (CompilerError err in cr.Errors)
122             {
123                 Debug.Log(err.ErrorText);
124             }
125             return "Error: compiler error.";
126         }
127         else
128         {
129             //通过反射,调用HelloWorld的实例
130             Assembly objAssembly = cr.CompiledAssembly;
131             object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
132             MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");
133             return objMI.Invoke(objHelloWorld, null).ToString();
134         }
135     }
136 
137     public static string Calculate(string lines_final, int tf)
138     {
139         if (tf == 0)
140         {
141             return "Error: 0 cannot be divided";
142         }
143         if (lines_final[0] < '0' || lines_final[0] > '9')
144         {
145             return "Error: the formula must be begun with a number";
146         }
147         if (lines_final[lines_final.Length - 1] < '0' || lines_final[lines_final.Length - 1] > '9')
148         {
149             return "Error: the formula must be ended with a number";
150         }
151         for (int i = 0; i < lines_final.Length; i++)
152         {
153             if ((lines_final[i] >= '0' && lines_final[i] <= '9') || lines_final[i] == '+' || lines_final[i] == '-' || lines_final[i] == '*' || lines_final[i] == '/')
154             {
155                 if (lines_final[i] < '0' || lines_final[i] > '9')
156                 {
157                     if (lines_final[i + 1] < '0' || lines_final[i + 1] > '9')
158                     {
159                         return "Error: continuous operators are not allowed";
160                     }
161                     if (lines_final[i] == '/')
162                     {
163                         if (lines_final[i + 1] == '0')
164                         {
165                             return "Error: 0 cannot be divided";
166                         }
167                     }
168                 }
169             }
170             else
171             {
172                 return "Error: invalid characters included";
173             }
174         }
175 
176         // 1.CSharpCodePrivoder
177         CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();
178 
179         // 2.ICodeComplier
180         ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler();
181 
182         // 3.CompilerParameters
183         CompilerParameters objCompilerParameters = new CompilerParameters();
184         objCompilerParameters.ReferencedAssemblies.Add("System.dll");
185         objCompilerParameters.GenerateExecutable = false;
186         objCompilerParameters.GenerateInMemory = true;
187 
188         // 4.CompilerResults
189         
190 
191         CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode(lines_final, tf));
192 
193         if (cr.Errors.HasErrors)
194         {
195             Debug.Log("编译错误:");
196             foreach (CompilerError err in cr.Errors)
197             {
198                 Debug.Log(err.ErrorText);
199             }
200             return "Error: compiler error.";
201         }
202         else
203         {
204             //通过反射,调用HelloWorld的实例
205             Assembly objAssembly = cr.CompiledAssembly;
206             object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
207             MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");
208             return objMI.Invoke(objHelloWorld, null).ToString();
209         }
210     }
211 
212     public static string GenerateCode(string lines_final, int tf)
213     {
214         StringBuilder sb = new StringBuilder();
215         sb.Append("using System;using System.IO;using System.Collections.Generic;using System.Text;");
216         sb.Append(Environment.NewLine);
217         sb.Append("namespace DynamicCodeGenerate");
218         sb.Append(Environment.NewLine);
219         sb.Append("{");
220         sb.Append(Environment.NewLine);
221         sb.Append("	public class HelloWorld");
222         sb.Append(Environment.NewLine);
223         sb.Append("	{");
224         sb.Append(Environment.NewLine);
225         sb.Append("	public string OutPut()");
226         sb.Append(Environment.NewLine);
227         sb.Append("		{");
228         sb.Append(Environment.NewLine);
229         sb.Append("long tf = " + tf + ";");
230         sb.Append(Environment.NewLine);
231         sb.Append("long re = " + lines_final + ";");
232         sb.Append(Environment.NewLine);
233         sb.Append("for (int i = 2; i < re || i < tf; i++){while (re % i == 0 && tf % i == 0){re = re / i;tf = tf / i;}}");
234         sb.Append(Environment.NewLine);
235         //sb.Append("Console.Write("Result = ");");
236         sb.Append("		if (tf != 1){return re.ToString() + "/" + tf.ToString();} else{return re.ToString();}");
237         sb.Append(Environment.NewLine);
238         sb.Append(Environment.NewLine);
239         sb.Append("		}");
240         sb.Append(Environment.NewLine);
241         sb.Append("	}");
242         sb.Append(Environment.NewLine);
243         sb.Append("}");
244         string code = sb.ToString();
245         return code;
246     }
247 }
View Code
原文地址:https://www.cnblogs.com/yuki8819/p/5391598.html