博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【个人项目总结】四则运算生成器
阅读量:4519 次
发布时间:2019-06-08

本文共 10139 字,大约阅读时间需要 33 分钟。

项目需求:

像阿超那样,花二十分钟写一个能自动生成小学四则运算题目的命令行 “软件”, 分别满足下面的各种需求。下面这些需求都可以用命令行参数的形式来指定:

    a) 除了整数以外,还要支持真分数的四则运算。 (例如:  1/6 + 1/8 = 7/24)

    b) 让程序能接受用户输入答案,并判定对错。 最后给出总共 对/错 的数量。

    c) 逐步扩展功能和可以支持的表达式类型,最后希望能支持下面类型的题目 (最多 10 个运算符,括号的数量不限制):

         25 - 3 * 4 - 2 / 2 + 89 = ?
         1/2 + 1/3 - 1/4 = ? 
        (5 - 4 ) * (3 +28) =?

    d) 一次可以批量出 100 道以上的题目,保存在文本文件中, 并且保证题目不能重复,(1+2) 和 (2+1) 是重复的题目。 

我的实现:

我了解到我的同学们大多都是用前、中、后缀表达式的互相转换来实现算式计算的,这个算法在上学期的课中编写过了,所以我想用个不一样的方法实现。

我使用了C#的反射,动态生成、编译代码。这样,只要在程序中生成了中缀表达式,将其转换为String型然后插入动态代码中编译,即可直接算出结果。

代码动态创建及编译的核心代码:

1                 // 1.CSharpCodePrivoder 2                 CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider(); 3  4                 // 2.ICodeComplier 5                 ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler(); 6  7                 // 3.CompilerParameters 8                 CompilerParameters objCompilerParameters = new CompilerParameters(); 9                 objCompilerParameters.ReferencedAssemblies.Add("System.dll");10                 objCompilerParameters.GenerateExecutable = false;11                 objCompilerParameters.GenerateInMemory = true;12 13                 // 4.CompilerResults14                 GenerateLines();15                 Console.WriteLine("==========No." + (i+1).ToString() + "==========");16                 Console.WriteLine(lines);17 18                 CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode());19 20                 if (cr.Errors.HasErrors)21                 {22                     Console.WriteLine("编译错误:");23                     foreach (CompilerError err in cr.Errors)24                     {25                         Console.WriteLine(err.ErrorText);26                     }27                 }28                 else29                 {30                     //通过反射,调用HelloWorld的实例31                     Assembly objAssembly = cr.CompiledAssembly;32                     object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");33                     MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");34                     string re = objMI.Invoke(objHelloWorld, null).ToString();35                 }

其中,GenerateCode()是我用来生成代码的函数,返回了一个需要被动态编译的代码,其中定义了namespace DynamicCodeGenerate,public class HelloWorld以及其下方法public string OutPut()。

 

代码生成函数GenerateCode()的主要功能即是生成算式。因为题目要求程序可以计算分数,所以GenerateCode()还需要能进行通分、约分的操作。

GenerateCode()函数的主要流程:生成随机数,产生一个中缀表达式;对表达式全通分(即每一项都乘上所有被除项之积),然后将得数与刚才乘上的数约分,即得到分数形式的答案。

之后接受用户输入,和标准答案比对后输出结果即可。

 

完整代码:

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 namespace A_Boring_Project_CSharp 12 { 13     class Program 14     { 15         static int max = 50; 16         static int rows = 10; 17         static List
nums; 18 static List
add_n_minus; 19 static List
div; 20 static List
div_nums; 21 static int tf; 22 static int amount; 23 static string lines; 24 static string lines_tf; 25 static string lines_final; 26 static int count; 27 28 static void Main(string[] args) 29 { 30 31 lines = ""; 32 count = 0; 33 34 for (int i = 0; i < rows; i++) 35 { 36 // 1.CSharpCodePrivoder 37 CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider(); 38 39 // 2.ICodeComplier 40 ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler(); 41 42 // 3.CompilerParameters 43 CompilerParameters objCompilerParameters = new CompilerParameters(); 44 objCompilerParameters.ReferencedAssemblies.Add("System.dll"); 45 objCompilerParameters.GenerateExecutable = false; 46 objCompilerParameters.GenerateInMemory = true; 47 48 // 4.CompilerResults 49 GenerateLines(); 50 Console.WriteLine("==========No." + (i+1).ToString() + "=========="); 51 Console.WriteLine(lines); 52 53 CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode()); 54 55 if (cr.Errors.HasErrors) 56 { 57 Console.WriteLine("编译错误:"); 58 foreach (CompilerError err in cr.Errors) 59 { 60 Console.WriteLine(err.ErrorText); 61 } 62 } 63 else 64 { 65 //通过反射,调用HelloWorld的实例 66 Assembly objAssembly = cr.CompiledAssembly; 67 object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld"); 68 MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut"); 69 string re = objMI.Invoke(objHelloWorld, null).ToString(); 70 71 string answer = Console.ReadLine(); 72 73 if (re == answer) 74 { 75 count++; 76 Console.WriteLine("Correct"); 77 } 78 else 79 { 80 Console.WriteLine("Wrong, the answer should be " + re.ToString()); 81 } 82 } 83 } 84 Console.WriteLine("Your score is: " + count.ToString() + " out of " + rows.ToString()); 85 Console.ReadLine(); 86 } 87 88 static string GenerateCode() 89 { 90 91 StringBuilder sb = new StringBuilder(); 92 sb.Append("using System;using System.IO;using System.Collections.Generic;using System.Text;"); 93 sb.Append(Environment.NewLine); 94 sb.Append("namespace DynamicCodeGenerate"); 95 sb.Append(Environment.NewLine); 96 sb.Append("{
"); 97 sb.Append(Environment.NewLine); 98 sb.Append("\tpublic class HelloWorld"); 99 sb.Append(Environment.NewLine);100 sb.Append("\t{
");101 sb.Append(Environment.NewLine);102 sb.Append("\tpublic string OutPut()");103 sb.Append(Environment.NewLine);104 sb.Append("\t\t{
");105 sb.Append(Environment.NewLine);106 sb.Append("long tf = "+ tf + ";");107 sb.Append(Environment.NewLine);108 sb.Append("long re = " + lines_final + ";");109 sb.Append(Environment.NewLine);110 sb.Append("for (int i = 2; i < re || i < tf; i++){while (re % i == 0 && tf % i == 0){re = re / i;tf = tf / i;}}");111 sb.Append(Environment.NewLine);112 sb.Append("Console.Write(\"Result = \");");113 sb.Append("\t\tif (tf != 1){return re.ToString() + \"/\" + tf.ToString();} else{return re.ToString();}");114 sb.Append(Environment.NewLine);115 sb.Append(Environment.NewLine);116 sb.Append("\t\t}");117 sb.Append(Environment.NewLine);118 sb.Append("\t}");119 sb.Append(Environment.NewLine);120 sb.Append("}");121 122 string code = sb.ToString();123 124 return code;125 }126 127 static void GenerateLines()128 {129 tf = 1;130 nums = new List
();131 add_n_minus = new List
();132 div = new List
();133 div_nums = new List
();134 System.Random rnd = new System.Random(GetRandomSeed());135 amount = rnd.Next(1, 11);136 lines = "";137 lines_tf = "";138 lines_final = "";139 140 int x = 0;141 int d = 0;142 List
anm;143 List
op;144 anm = new List
();145 op = new List
();146 for (int i = 0; i < amount; i++)147 {148 //A new number149 rnd = new System.Random(GetRandomSeed());150 nums.Add(rnd.Next(1, max));151 lines += nums[i];152 //A new operator153 System.Random rnd0 = new System.Random(GetRandomSeed());154 int key = rnd0.Next(0,4);155 op.Add(lines.Length + 1);156 switch (key)157 {158 case 0:159 anm.Add(i);160 x = 0;161 lines += "+";162 add_n_minus.Add(lines.Length);163 break;164 case 1:165 anm.Add(i);166 x = 0;167 lines += "-";168 add_n_minus.Add(lines.Length);169 break;170 case 2:171 x++;172 if (x <= 3)173 {174 lines += "*";175 break;176 }177 else178 {179 goto case 1;180 }181 case 3:182 x = 0;183 d++;184 if (d <= 3)185 {186 lines += "/";187 div.Add(i);188 break;189 }190 else191 {192 goto case 1;193 }194 default:195 x = 0;196 break;197 }198 }199 op.Add(lines.Length);200 201 rnd = new System.Random(GetRandomSeed());202 nums.Add(rnd.Next(1, max));203 lines += nums[amount];204 205 for (int i = 0; i < div.Count; i++)206 {207 div_nums.Add(nums[div[i] + 1]);208 lines_tf += div_nums[i];209 lines_tf += "*";210 tf *= div_nums[i];211 }212 213 lines_final += lines_tf;214 lines_final += lines;215 216 if (div.Count > 0)217 {218 for (int i = 1; i <= add_n_minus.Count; i++)219 {220 lines_final = lines_final.Insert(i * lines_tf.Length + add_n_minus[i - 1], lines_tf);221 }222 }223 224 }225 226 static int GetRandomSeed()227 {228 byte[] bytes = new byte[4];229 System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();230 rng.GetBytes(bytes);231 return BitConverter.ToInt32(bytes, 0);232 }233 234 }235 }

 

小结:

在写GenerateCode()函数时,没有预先设计好控制、变量等等的具体实现,所以最终导致代码有点混乱,下次应该多加注意。

转载于:https://www.cnblogs.com/yuki8819/p/5305107.html

你可能感兴趣的文章
函数名、闭包及迭代器
查看>>
mysql 5.6 参数详解
查看>>
求旋转数组的最小元素
查看>>
jQuery ajax error函数(交互错误信息的获取)
查看>>
Gson解析Json数组
查看>>
Lintcode: Fast Power
查看>>
Pocket Gem OA: Log Parser
查看>>
枚举也能直接转换为对应的数值输出
查看>>
angularjs1-7,供应商
查看>>
BitSet
查看>>
Spring常用注解,自动扫描装配Bean
查看>>
(转载)深入理解WeakHashmap
查看>>
JAVA中的数组
查看>>
爬虫—使用Requests
查看>>
scrollIntoView()窗口滚动
查看>>
No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
查看>>
使用ansible远程管理集群
查看>>
读jQuery源码释疑笔记3
查看>>
手把手教你jmeter压测--适合入门
查看>>
Sequelize+MySQL存储emoji表情
查看>>