第二次博客作业
《构建之法》第二次博客 熟悉工具
一、作业要求
GIT地址 | GIT地址 |
GIt用户名 | Loserhqs |
学号后五位 | 62322 |
我的博客地址 | 博客 |
二、项目背景
阿超家里的孩子上小学一年级了,这个暑假老师给家长们布置了一个作业:家长每天要给孩子出一些合理的,但要有些难度的四则运算题目,并且家长要对孩子的作业打分记录。
作为程序员的阿超心想,既然每天都需要出题,那何不做一个可以自动生成小学四则运算题目与解决题目的命令行 “软件”呢。他把老师的话翻译一下,就形成了这个软件的需求:
程序接收一个命令行参数 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
三、环境配置
Visual Studio 2013是我大一的时候就安装好的,版本不是很高,但是觉得再安装一个Visual Studio 2017或者Visual Studio 2019很浪费时间,同时也增加了电脑的负担。所以这次四则运算的作业我还是用的Visual Studio 2013来实现的。如果没有的可以去官网下载或者在网上找百度云盘的资源。
同时github也是以前就开始用了,当然注册一个账号也不是什么难事,有的博客说最好用谷歌浏览器来注册,我记得当时没有用谷歌,也没遇到什么问题。所以我觉得用什么浏览器应该没关系吧,当然最好用谷歌浏览器嘛。
对于git的安装,在Git的官网https://git-scm.com/点击Downloads
下载git 2.23
下载完成后,点击该应用程序,跟着引导一步一步的点击Next就OK了。git的安装十分简单,应该不需要什么安装教程,如果有需要的可以参考:https://www.cnblogs.com/wj-1314/p/7993819.html。
四、项目克隆
登录自己的github账号,登陆成功后,输入阿超的仓库地址:
https://github.com/Cherish599/AchaoCalculator,进入阿超四则运算生成器仓库,点击右上角的Fork键,将该仓库拷贝到自己的同名仓库中。
回到自己的首页中,查看是否拷贝成功。如果自己主页下面有“阿超四则运算生成器”,则说明拷贝成功,否则还需要重新拷贝。
点击该页面右下角的Clone or download会出现一个网址,将该网站复制下来。
在想要下载该项目的地方,鼠标右键点击Git Bash Here,在给窗口下输入git clone并且将刚刚复制的网址粘贴上去。
在保存的地方会出现刚下载的文件。在此我们可以新建自己的项目保存在这个文件夹中。
五、创建项目
打开自己的Visual Studio,在开始栏下点击新建项目。
选择Visual C#的控制台应用程序,将该项目保存在刚刚下载的四则运算文件夹下。如果不熟悉C#的话,也可以用C++语言来编程。
代码块:
产生随机数的方法
public class Rand
{
//产生随机数
public static Random rand = new Random();
/*
public int n1 = rand.Next(0, 100);
public int n2 = rand.Next(0, 100);
public int n3 = rand.Next(0, 100);
public int n4 = rand.Next(0, 100);
public int s1 = rand.Next(0, 4);
public int s2 = rand.Next(0, 4);
public int s3 = rand.Next(0, 4);
public int type = rand.Next(0, 2);
*/
}
输入输出的方法
public class Input
{
public static int input()
{
Console.WriteLine("请输入需要产生的题目数:");
//题目数量
int n = Convert.ToInt32(Console.ReadLine());
return n;
}
//文本输出
public static StreamWriter sw1 = new StreamWriter(@"E:\gitKU\AchaoCalculator\Loserhqs\Primarymath\Primarymath\result.txt");
}
衔接的方法,即中间过程
将运算的情况进行分类
public class Linkup
{
//判断算式结果是否为整数
public static bool nonnegint(double sum)
{
if (sum == (int)sum)
return true;
else
return false;
}
//两个数的运算
public static double arith(int a, int b, int s)
{
if (s == 0)
return a + b;
else if (s == 1)
return a - b;
else if (s == 2)
return a * b;
else
{
if (b != 0)
{
int temp = a / b;
if (temp * b == a)
return a / b;
else
return -1;
}
else
return -1;
}
}
}
public class Opterator
{
//两个运算符
public static int optwo(int n1, int n2, int n3, int s1, int s2, char[] oper)
{
int flag = 0;
//if ((oper[s1] == '+' || oper[s1] == '-') && (oper[s2] == '*' || oper[s2] == '/'))
if ((s1 / 2) == 0 && (s2 / 2) == 1)
{
double sum = Linkup.arith(n2, n3, s2);
if (sum >= 0)
{
if (Linkup.nonnegint(sum))
{
double temp = Linkup.arith(n1, (int)sum, s1);
if (temp >= 0)
{
if (Linkup.nonnegint(temp))
{
flag = 1;
Console.WriteLine(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "=" + (int)temp);
Input.sw1.Write(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "=" + (int)temp + "\r\n");
}
}
}
}
}
else
{
double sum = Linkup.arith(n1, n2, s1);
if (sum >= 0)
{
if (Linkup.nonnegint(sum))
{
double temp = Linkup.arith((int)sum, n3, s2);
if (temp >= 0)
{
if (Linkup.nonnegint(temp))
{
flag = 1;
Console.WriteLine(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "=" + (int)temp);
Input.sw1.Write(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "=" + (int)temp + "\r\n");
}
}
}
}
}
return flag;
}
//三个运算符
public static int opthree(int n1, int n2, int n3, int n4, int s1, int s2, int s3, char[] oper)
{
int flag = 0;
//if ((oper[s1] == '+' || oper[s1] == '-') && (oper[s2] == '*' || oper[s2] == '/') && (oper[s3] == '*' || oper[s3] == '/'))
if ((s1 / 2) == 0 && (s2 / 2) == 1 && (s3 / 2) == 1)
{
double sum = Linkup.arith(n2, n3, s2);
if (sum >= 0)
{
if (Linkup.nonnegint(sum))
{
double temp = Linkup.arith((int)sum, n4, s3);
if (temp >= 0)
{
double temp1 = Linkup.arith(n1, (int)temp, s1);
if (temp1 >= 0)
{
if (Linkup.nonnegint(temp1))
{
flag = 1;
Console.WriteLine(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1);
Input.sw1.Write(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1 + "\r\n");
}
}
}
}
}
}
else if ((s1 / 2) == 0 && (s2 / 2) == 1 && (s3 / 2) == 0)
{
double sum = Linkup.arith(n2, n3, s2);
if (sum >= 0)
{
if (Linkup.nonnegint(sum))
{
double temp = Linkup.arith(n1, (int)sum, s1);
if (temp >= 0)
{
double temp1 = Linkup.arith((int)temp, n4, s3);
if (temp >= 0)
{
if (Linkup.nonnegint(temp1))
{
flag = 1;
Console.WriteLine(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1);
Input.sw1.Write(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1 + "\r\n");
}
}
}
}
}
}
else if ((s1 / 2) == 0 && (s2 / 2) == 0 && (s3 / 2) == 1)
{
double sum = Linkup.arith(n3, n4, s3);
if (sum >= 0)
{
if (Linkup.nonnegint(sum))
{
double temp = Linkup.arith(n1, n2, s1);
if (temp >= 0)
{
double temp1 = Linkup.arith((int)temp, (int)sum, s2);
if (temp1 >= 0)
{
if (Linkup.nonnegint(temp1))
{
flag = 1;
Console.WriteLine(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1);
Input.sw1.Write(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1 + "\r\n");
}
}
}
}
}
}
else if ((s1 / 2) == 1 && (s2 / 2) == 0 && (s3 / 2) == 1)
{
double sum = Linkup.arith(n1, n2, s1);
if (sum >= 0)
{
if (Linkup.nonnegint(sum))
{
double temp = Linkup.arith(n3, n4, s3);
if (temp >= 0)
{
double temp1 = Linkup.arith((int)sum, (int)temp, s2);
if (temp1 >= 0)
{
if (Linkup.nonnegint(temp1))
{
flag = 1;
Console.WriteLine(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1);
Input.sw1.Write(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1 + "\r\n");
}
}
}
}
}
}
else
{
double sum = Linkup.arith(n1, n2, s1);
if (sum >= 0)
{
if (Linkup.nonnegint(sum))
{
double temp = Linkup.arith((int)sum, n3, s2);
if (temp >= 0)
{
double temp1 = Linkup.arith((int)temp, n4, s3);
if (temp1 >= 0)
{
if (Linkup.nonnegint(temp1))
{
flag = 1;
Console.WriteLine(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1);
Input.sw1.Write(n1 + "" + oper[s1] + "" + n2 + "" + oper[s2] + "" + n3 + "" + oper[s3] + n4 + "=" + (int)temp1 + "\r\n");
}
}
}
}
}
}
return flag;
}
}
生成一定数量的题目
public class Produce
{
//存放运算符号的数组
public static char[] oper = new char[4] { '+', '-', '*', '/' };
public static void produce(int n)
{
int i=0;
//有n道题
while(i<n)
{
//生成两个或三个运算符的题目
int type = Rand.rand.Next(0, 2);
if (type == 0)
{
//随机生成三个数
int num1 = Rand.rand.Next(0, 100);
int num2 = Rand.rand.Next(0, 100);
int num3 = Rand.rand.Next(0, 100);
//随机生成两种运算符号
int index1 = Rand.rand.Next(0, 4);
int index2 = Rand.rand.Next(0, 4);
int flag=Opterator.optwo(num1, num2, num3, index1, index2, Produce.oper);
if(flag==1)
{
i++;
}
}
else
{
//随机生成四个数
int num1 = Rand.rand.Next(0, 10);
int num2 = Rand.rand.Next(0, 100);
int num3 = Rand.rand.Next(0, 100);
int num4 = Rand.rand.Next(0, 100);
//随机生成三种运算符号
int index1 = Rand.rand.Next(0, 4);
int index2 = Rand.rand.Next(0, 4);
int index3 = Rand.rand.Next(0, 4);
int flag=Opterator.opthree(num1, num2, num3, num4, index1, index2, index3, Produce.oper);
if(flag==1)
{
i++;
}
}
}
}
}
运行结果:
控制台输出:
记事本TXT文件:
六、单元测试与回归测试
点击项目解决方案,选择该菜单页中的添加,然后新建项目。
选择Visual C#下的测试,然后选择单元测试项目。在.cs文件下编写单元测试的程序。
如果没有加该项目的引用的话,在写测试代码时,调用该项目中的方法会报错,我们需要在解决方案中添加该项目的引用。
当单元测试程序编写完成后,对项目中各个类进行单元测试,测试所编写的代码是否有错误。
如果有,找到相应的位置进行修改;如果没有则通过测试。
回归测试是测试在修改了原有代码的基础上还能不能运行通过,会不会影响程序的整体实现,步骤其实和单元测试相同。
单元测试与回归分析的代码:
public class UnitTest1
{
[TestMethod]
public void TestMethod()
{
//TestMethod1();
//TestMethod2();
//TestMethod3();
//TestMethod4();
TestMethod5();
}
public void TestMethod1()
{
//测试随机数
int testnum = Rand.rand.Next(0, 100);
int testopr = Rand.rand.Next(0, 4);
int testtype = Rand.rand.Next(0, 2);
Console.WriteLine(testnum);
Console.WriteLine(Produce.oper[testopr]);
if (testtype == 0)
{
Console.WriteLine("三个数的运算");
}
else
{
Console.WriteLine("四个数的运算");
}
}
//测试两个数的运算
public void TestMethod2()
{
//testA=8*9
double ResultA = 72;
double TestA = Linkup.arith(8, 9, 2);
if (ResultA == TestA)
{
Console.WriteLine("testA的测试结果正确");
}
else
{
Console.WriteLine("testA的测试结果错误");
}
//testB=20/40
double ResultB = 0.5;
double TestB = Linkup.arith(20, 40, 3);
if (ResultB == TestB)
{
Console.WriteLine("testB的测试结果正确");
}
else
{
Console.WriteLine("testB的测试结果错误");
}
//testC=56/8
double ResultC = 7;
double TestC = Linkup.arith(56, 8, 3);
if (ResultB == TestB)
{
Console.WriteLine("testC的测试结果正确");
}
else
{
Console.WriteLine("testC的测试结果错误");
}
}
//测试结果是否为整数
public void TestMethod3()
{
double testnum1 = 5.63;
double testnum2 = 45;
if(Linkup.nonnegint(testnum1))
{
Console.WriteLine("testnum1测试正确");
}
else
{
Console.WriteLine("testnum1测试错误");
}
if (Linkup.nonnegint(testnum2))
{
Console.WriteLine("testnum2测试正确");
}
else
{
Console.WriteLine("testnum2测试错误");
}
}
//测试运算函数
public void TestMethod4()
{
//三个数的运算
//testop1=78-5*9
//int resultop1 = 33;
Console.WriteLine("预测结果为33");
Console.WriteLine("真实结果如下:");
int flag1 = Opterator.optwo(78, 5, 9, 1, 2, Produce.oper);
if(flag1==1)
{
Console.WriteLine("结果正确");
}
else
{
Console.WriteLine("结果错误");
}
//testop2=23+12/4
//int resultop2 = 26;
Console.WriteLine("预测结果为26");
Console.WriteLine("真实结果如下:");
int flag2 = Opterator.optwo(23, 12, 4, 0, 3, Produce.oper);
if (flag2 == 1)
{
Console.WriteLine("结果正确");
}
else
{
Console.WriteLine("结果错误");
}
//四个数的运算
//testop3=5*9-42/7
//int resultop3 = 39;
Console.WriteLine("预测结果为26");
Console.WriteLine("真实结果如下:");
int flag3 = Opterator.opthree(5, 9, 42, 7, 2,1,3 ,Produce.oper);
if (flag3 == 1)
{
Console.WriteLine("结果正确");
}
else
{
Console.WriteLine("结果错误");
}
//testop4=5-9+77/11
//int resultop4 = 11;
Console.WriteLine("预测结果为11");
Console.WriteLine("真实结果如下:");
int flag4 = Opterator.opthree(5, 9, 77, 11, 1, 0, 3, Produce.oper);
if (flag4 == 1)
{
Console.WriteLine("结果正确");
}
else
{
Console.WriteLine("结果错误");
}
}
//测试能否生成相应数量的题目
public void TestMethod5()
{
int n = 5;
Produce.produce(n);
}
}
七、断点调试
在主函数中设置断点,然后可以按F11步入,逐语句调试。
下面是在F11逐语句调试过程中的情况。
八、效能分析
通过分析栏下的性能与诊断,我们可以看到该项目的调用关系树:
调用方/被调用方的情况,函数名称,非独占/独占样本数。
还可以喊道调用函数,当前函数以及已调用函数的情况。
同时也可以看到进程的情况。
所有函数的的情况:非独占样本数,独占样本数以及它们的百分比都可以清楚的看到。
九、上传提交
在AchaoCalculator 文件夹下,右键鼠标,git bash here,输入git add . 将项目文件添加到版本控制中。
因为没有绑定github 用户的原因,我需要git config的指令来绑定我的用户,如果绑定的的话,可以直接输入git commit -m以及相关的备注,进行提交修改。
下图为绑定用户的过程:
下图为提交的过程:
输入git push,上传到github上面去。
打开自己的github,查看是否上传成功。如果上传成功的话,会出现自己的文件名。
点击走上角的New pull requst,将该项目的代码上传到阿超四则运算的仓库中去。打开刚开始获取阿超四则运算仓库中是否有自己的文件。
十、总结
1.在安装git过程中,没有什么意外。整体来说,安装软件也是没有什么难的地方。只是第一次用git,不是很清楚它的一些指令,需要看相关的资料才能交文件下载与上传。
2.在用C#编程的过程中,也没有什么大的问题。可能是因为这个题的难度我还能接受的原因吧。但是有一段时间没有用C#编程了,有些用法与Python都能搞混,我也真是垃圾。
3.在用C#编程的过程中一定要注意静态变量的使用,因为C#是没有全局变量一说的。
4.第一次使用单元测试和回归测试,觉得很棒。以后的学习工作中,要经常使用这一功能。