说实话,看本人队友的代码已有1年之余,也帮忙上刀山下火海不辞劳苦为她找BUG,有时找了n个小时就是因为把i达成了1,==打成了=,然而凭心而论此人代码武功高强,内力深厚,不仅人长得漂亮而且代码风格确实登得大雅之堂,括号该对称就对称,该缩进就缩进,除了注释略微不多让本人略感头疼外,一切都非常...真香。
队友采用C++编写,在dev上跑,说起代码,那是和本人一样好看,比如队友把代码分成几个模块,(在鄙人强烈建议下)将其变成了工程,整个工程由5个文件组成:
- main.cpp:除了实现的主函数文件
- logIn.h:存储登录信息头文件,用户信息存于其中,可增加或修改用户信息
- question.h:三个函数question1()、question2()、question3()分别用于生成小学,初中和高中的题目
- sign.h:三个函数sign1()、sign2()、sign3()分别用于生成小学初中高中需求的运算符
- search.h:用于查找该用户文件夹下所有的文件
虽然sign.h,logln.h(对你没看错是logln不是login)模块略微有凑工程之嫌疑,比如他们长下面这样:
#include<iostream> #include<fstream> #include<string> #include<cstdlib> #include<ctime> #include<cstdlib> using namespace std; char sign1(int n) {//生成小学运算符 // srand((unsigned)time(NULL)); char s1[] = {‘+‘ , ‘-‘ , ‘*‘ , ‘/‘} ; return s1[n]; } string sign2(int n) {//生成初中运算符 string s2[] = { "^2" , "√"} ; return s2[n]; } string sign3(int n) {//生成高中运算符 string s3[] = { "sin" , "cos" , "tan"} ; return s3[n]; }
和:
#include<iostream> #include<fstream> #include<string> #include<cstdlib> #include<ctime> #include<cstdlib> using namespace std; int logIn(string name , string password) {//判断用户名和密码是都正确,返回1为小学用户,2为初中用户,3为高中用户 if((name == "张三1" || name == "张三2" || name == "张三3" )&& password == "123") return 1; else if((name == "李四1" || name == "李四2" || name == "李四3" )&& password == "123") return 2; else if((name == "王五1" || name == "王五2" || name == "王五3" )&& password == "123") return 3; else return 0; }
但是代码从整体上看可以说是相当的规范。
好的,让我们重新把目光放到代码的算法部分,由于我用的python写的,确实不知道C++写UI的切肤之痛,所以UI部分我们暂且不论,控制台稍后再说,我们看核心部分如何操作,生成小学题目代码如下:
string question1() //生成小学题目 { string s = ""; char str[10]; srand((unsigned)time(NULL)); int n1 = 0 , n2 = 0 , n3 = 0; int flag = 1; int length = (rand()%4 + 2); int a[5]; char b[5]; int left[5] = {0,0,0,0,0}; //每个数左边有几个左括号 int right[5] = {0,0,0,0,0};//每个数右边有几个右括号 if(flag == 1) { for(int i = 0 ; i < length - 1; i++) { a[i] = rand()%(100 - 1 + 1) + 1;//随机生成操作数 n1 = rand()%(4-0)+0; //随机生成四则运算符号 b[i] = sign1(n1); } a[length - 1] = rand()%(100 - 1 + 1) + 1; b[length - 1] = ‘=‘; //最后加上等号 int exit[5] ={0,0,0,0,0}; int count = 0; //计数有几个右括号还需要加 for(int i = 0 ; i < length ; i++) { if(rand()%3 == 2 && exit[i] > 0 && left[i] == 0 && count > 0)//一个数右边加括号的条件 { right[i]++; exit[i]--; count--; } if(rand()%3 == 1 && i != length - 1 && right[i] == 0)//一个数左边加括号的条件 { left[i]++; count++; for(int j = i ; j < length ; j++) exit[j]++; } } while(count != 0) //左右括号不一样多就需要再次遍历 { for(int i = 1; i < length ; i++) if(rand()%3 == 2 && exit[i] > 0 && left[i] == 0 && count > 0) { right[i]++; exit[i]--; count--; } } for(int i = 0 ; i < length; i++) { while(left[i] > 0) { s = s + "("; left[i]--; } s = s + itoa(a[i],str,10); while(right[i] > 0) { s = s + ")"; right[i]--; } s = s + b[i]; } } return s; }
这套算法比我的投机取巧(直接套娃式生成法,详见彭依依博客)简直好了太多,完全实现真随机,首先生成操作数和数字,对一个已经生成好的,对可以加括号的5个位置随机插空,之后再对应生成右括号。队友调试该模块也算是费劲了心思(别问我怎么知道,我看着一个BUG一个BUG改过来的,最后成功一刻差点跪下来谢天谢地),这个代码优点也非常的明显,比我的代码随机性更大,之后的初中高中也直接加上去就好。但是建议写成类,做继承或者多态,会更显得牛*。
当然代码也有缺点的地方,查重部分比较拖沓,查重代码如下:
infile.open(distAll.data()); str = question2(); notok = 0; p = 0; while(getline(infile,s1)) { mypath[p] = s1; p++; } infile.close(); for(int m = 0 ; m < p ; m++) { infile.open(mypath[m].data()); while(getline(infile,s2)) { string tem = ""; tem = s2.substr(4) ; //去掉题号,留下题目进行比对 if(strcmp(str.c_str() , tem.c_str()) == 0) notok = 1; } infile.close(); } if(notok == 0) { outfile << k + 1 ; if((k + 1) < 10) outfile << " "; outfile << "、" << str << endl; outfile << " " << endl; } else k--; Sleep(1000);
三次出题三次查重,自己都承认自己多写了200多行。
最后有一个BUG当事人和我全都一脸懵逼,摸不着头脑,就是产生随机数时,用的种子,结果每个随机数产生前不加sleep就不会有变化???请往上看这个代码,最后一个Sleep(1000),虽然解决了BUG,但是程序生成每个题目要等待1s,太慢了爸爸!真香...
执笔至此,不再多言,队友已经柳眉倒竖,怒目圆睁看着我,就差撸袖子上了,为了求生欲,下次再聊。
原文地址:https://www.cnblogs.com/tursa/p/9715326.html