队友使用C++实现该个人项目,十分地面向过程
1、首先是用户初始化
优点:使用map方便检索
缺点:增加用户比较麻烦
2、main函数实现 登陆、生成题目、切换题目难度功能
其中使用while循环来实现各功能界面间切换的功能,第一层while循环是登陆,登陆成功进入第二层循环生成题目,若输入“切换为XX”,但XX不为小学初中高中的任意一个,会进入第三层循环要求输入以上任一难度。
优点:层次分明,层层递进
缺点:如果界面数量变多,继续使用该方法会使得代码臃肿,可读性变差
3、使用流水线方式生成一道题目
操作数的可能性为1~5个,将1个操作数的情况与其余情况分开考虑,其中小学不能生成1个操作数的题目
只有一个操作数时:
初中题目会固定生成带有根号或者平方的式子,操作数为1~100
高中题目会固定生成带有三角函数的式子,不过函数里的数字是从给定的数组中选取,数组如下
然后要保证tan值要存在,即(数字+90°)%180 != 0
2~5个操作数时,使用流水线的方式生成,即一个一个地生成操作数,在生成操作数的过程中使用随机数不断判断是否插入左右括号、根号、平方,或者判断该操作数是否用三角函数替代。需要保证具体代码如下:
#level是题目难度,其中0代表小学,1代表初中,2代表高中 string GetOneQuestion(int level) { stringstream ss; int bracketNum = 0; //括号的数量,单位为对 int operateNum; //操作数 bool leftBracket; //判断该操作数前是否有左括号,若有,则在该操作数后不加右括号,因为要避免出现“(?)”的情况 bool need = false; //判断是否满足备注要求,初中题目至少一个根号或平方(概率皆为1/2),高中题目至少一个三角函数 if (level == 0) { operateNum = 2+rand()%4; //小学题目2~5个操作数 } else { operateNum = 1+rand()%5; //初中和高中题目1~5个操作数 } if (operateNum == 1) { if (level == 1) { if (rand()%2 == 0) { ss << "√" << 1+rand()%100; } else { ss << 1+rand()%100 << "^2"; } } else if (level == 2) { string fun; int num; //tan值要存在 do { fun = g_triFun[rand()%3]; num = g_triNum[rand()%46]; } while (fun == "tan(" && (num+90)%180 == 0); ss << fun << num << "°" << ‘)‘; } } else { //生成第一个操作数 if (rand()%4 == 0) { ss << ‘(‘; bracketNum++; } if (level == 1 && rand()%4 == 0) //根号 { need = true; ss <<"√"; } if (level == 2 && rand()%4 == 0) //操作数,或者sin(?)cos(?)tan(?) { need = true; string fun; int num; //tan值要存在 do { fun = g_triFun[rand()%3]; num = g_triNum[rand()%46]; } while (fun == "tan(" && (num+90)%180 == 0); ss << fun << num << "°" << ‘)‘; } else { ss << 1+rand()%100; } if (level == 1 && rand()%4 == 0) //平方 { need = true; ss << "^2"; } //生成后续运算符与操作数 for (int i = 0; i < operateNum; i++) { char c = g_operators[rand()%4]; //运算符 ss << c; if (level == 1 && (rand()%4 == 0 || (!need && i == operateNum-1 && rand()%2 == 0))) //根号 { need = true; ss <<"√"; } leftBracket = false; if (rand()%4 == 0 && i != operateNum-1) //左括号 { ss << ‘(‘; leftBracket = true; bracketNum++; } if (level == 2 && (rand()%4 == 0 || (!need && i == operateNum-1))) //操作数,或者sin(?)cos(?)tan(?) { need = true; string fun; int num; //不能发生除0的情况,并且tan值要存在 do { fun = g_triFun[rand()%3]; num = g_triNum[rand()%46]; } while ((c == ‘/‘ && ((fun == "sin(" && num%180 == 0) || (fun == "cos(" && (num+90)%180 == 0))) ||(fun == "tan(" && (num+90)%180 == 0)); ss << fun << num << "°" << ‘)‘; } else { ss << 1+rand()%100; } if (level == 1 && rand()%8 == 0) //平方在操作数右边 { need = true; ss << "^2"; } if (rand()%4 == 0 && bracketNum > 0 && !leftBracket) //右括号 { ss << ‘)‘; bracketNum--; } if (level == 1 && (rand()%8 == 0 || (!need && i == operateNum-1))) //平方有可能在括号右边 { need = true; ss << "^2"; } } while (bracketNum--) { ss << ‘)‘; } } ss << ‘=‘; if (g_questions.find(ss.str()) != g_questions.end()) { return GetOneQuestion(level); } else { g_questions.insert(ss.str()); return ss.str(); } }
优点:按流程一步步来,清晰明了,有考虑三角函数值能够手算、tan值要存在,当三角函数前一个运算符为除号时,三角函数的值不为0
缺点:要按流程仔细考虑,根号、平方、左右括号应该有可能在哪出现都得考虑周全,经常会遗漏某些条件
4、题目查重
使用set容器实现,将该用户文件夹下所有题目都添加到该集合中,当生成一道题目时,判断是否已保存在集合中,若已存在则再生成一道题目,否则将其输出到文件中并加入到集合里
原文地址:https://www.cnblogs.com/ling1527/p/11553134.html