本篇博客为对结对编程搭档李津松的个人项目(中小学数学卷子自动生成程序)的评价。该代码使用语言为c++。本次点评仅为个人观点,如有错误,请多指正!
/* copyright jinsong li 2021/9/26 */ #include <direct.h> #include <time.h> #include <string.h> #include <cstdio> #include <cstdlib> #include <cmath> #include <iostream> #include <fstream> #include <vector> using std::cin; using std::cout; using std::endl; using std::string; using std::to_string; using std::vector; using std::ifstream; using std::ofstream; void getFiles(string path, vector<string> &files) { // 文件句 int16_t hFile = 0; // 文件信息 struct _finddata_t fileinfo; string pathName; if ((hFile = _findfirst(pathName.assign(path).c_str(), &fileinfo)) != -1) { do { if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) files.push_back(pathName.assign(path). append("/").append(fileinfo.name)); } while (_findnext(hFile, &fileinfo) == 0); _findclose(hFile); } } // 查重函数:将先前的文档进行遍历, // 然后在提取出每一行的字符串, // 比较每一行的字符串, // 若没有重复则返回1,重复了就返回-1 int find(string test, int ty) { string FindType = ""; switch (ty) { case 1: { FindType = "./张三1/"; break; } case 2: { FindType = "./张三2/"; break; } case 3: { FindType = "./张三3/"; break; } case 4: { FindType = "./李四1/"; break; } case 5: { FindType = "./李四2/"; break; } case 6: { FindType = "./李四3/"; break; } case 7: { FindType = "./王五1/"; break; } case 8: { FindType = "./王五2/"; break; } case 9: { FindType = "./王五3/"; break; } } vector<string> files; getFiles(FindType, files); int size = files.size(); for (int i = 0; i < size; i++) { ifstream fin(files[i]); string past; while (fin >> past) { if (past == test) return (-1); } } return 1; } // 试卷生成函数:通过随机数生成不同操作数, // 根据引用的不同类型的试卷, // 生成不同的试卷并保存在相应的位置。 void get(int NUM, int USER, int TYPE) { time_t t = time(NULL); ofstream File; char ttime[33]; // 确定用户 switch (USER) { case 1: { strftime(ttime, 33, "./张三1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 2: { strftime(ttime, 33, "./张三2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 3: { strftime(ttime, 33, "./张三3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 4: { strftime(ttime, 33, "./李四1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 5: { strftime(ttime, 33, "./李四2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 6: { strftime(ttime, 33, "./李四3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 7: { strftime(ttime, 33, "./王五1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 8: { strftime(ttime, 33, "./王五2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 9: { strftime(ttime, 33, "./王五3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } } File.open(ttime); int randNum = 0; int diff = 0; // 确定类型 switch (TYPE) { case 1: { diff = 0; break; } case 2: { diff = 2; break; } case 3: { diff = 5; break; } } int syn = 0, spin = 0; // 生成题目 for (int i = 1; i <= NUM; i++) { File << i << ". " << endl; if (diff == 0) { randNum = rand() % 4 + 2; } else { randNum = rand() % 5 + 1; } int Number[randNum] = {0, 0, 0, 0, 0}; string sNumber[randNum] = {"", "", "", "", ""}; for (int j = 0; j < randNum; j++) { Number[j] = rand() % 100 + 1; sNumber[j] = to_string(Number[j]); } string FileWrite = ""; if (diff == 0) { spin = 0; } else if (diff == 2) { spin = rand() % 2 + 1; } else if (diff == 5) { spin = rand() % 3 + 3; } string spis = ""; switch (spin) { case 0: { FileWrite = FileWrite + sNumber[0]; break; } case 1: { spis = spis + "^2"; FileWrite = FileWrite + sNumber[0]; FileWrite = FileWrite + spis; break; } case 2: { spis = spis + "√"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 3: { spis = spis + "sin"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 4: { spis = spis + "cos"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 5: { spis = spis + "tan"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } } if (randNum != 1) { int flag = 0; int dir = 0; for (int j = 1; j < randNum; j++) { syn = rand() % 4; string symbol = ""; switch (syn) { case 0: { symbol = symbol + '+'; break; } case 1: { symbol = symbol + '-'; break; } case 2: { symbol = symbol + '*'; break; } case 3: { symbol = symbol + '/'; break; } } FileWrite = FileWrite + symbol; if ((rand() % 3 == 1) && (flag == 0) && (j != randNum - 1)) { FileWrite = FileWrite + "("; flag = 1; dir = j; } FileWrite = FileWrite + sNumber[j]; if ((dir != j) && (flag == 1) && (rand() % 3 == 2)) { FileWrite = FileWrite + ")"; flag = 2; } } if (flag == 1) { FileWrite = FileWrite + ")"; flag = 2; } } if (find(FileWrite, USER) == 1) { File << FileWrite; File << endl << endl; } else { i = i - 1; } } File.close(); } int user = 0; int type = 0; // 主函数 int main() { cout << "试卷生成系统" << endl; cout << "请输入用户名和密码" << endl; while (1) { // user等于0时表示登录初始界面,不同的user的值表示不同的账户 if (user == 0) { char username[20] = ""; char password[20] = ""; cin >> username >> password; if ((strcmp(username, "张三1") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为小学出题" << endl; user = 1; type = 1; } else if ((strcmp(username, "张三2") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为小学出题" << endl; user = 2; type = 1; } else if ((strcmp(username, "张三3") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为小学出题" << endl; user = 3; type = 1; } else if ((strcmp(username, "李四1") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为初中出题" << endl; user = 4; type = 2; } else if ((strcmp(username, "李四2") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为初中出题" << endl; user = 5; type = 2; } else if ((strcmp(username, "李四3") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为初中出题" << endl; user = 6; type = 2; } else if ((strcmp(username, "王五1") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为高中出题" << endl; user = 7; type = 3; } else if ((strcmp(username, "王五2") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为高中出题" << endl; user = 8; type = 3; } else if ((strcmp(username, "王五3") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为高中出题" << endl; user = 9; type = 3; } else { cout << "请输入正确的用户名、密码:" << endl; } } // user大于等于1时进入生成试卷系统 if (user >= 1) { char choosetype[20] = ""; cout << "是否更换当前出题类型" << endl; cin >> choosetype; // 切换出题类型 if (strcmp(choosetype, "切换为小学") == 0) { type = 1; } else if (strcmp(choosetype, "切换为初中") == 0) { type = 2; } else if (strcmp(choosetype, "切换为高中") == 0) { type = 3; } else { cout << "请输入小学、初中和高中三个选项中的一个" << endl; continue; } switch (type) { case 1: { cout << "准备生成小学数学题目,请输入生成题目数量"; cout << "(输入-1将退出当前用户,重新登录):" << endl; break; } case 2: { cout << "准备生成初中数学题目,请输入生成题目数量"; cout << "(输入-1将退出当前用户,重新登录):" << endl; break; } case 3: { cout << "准备生成高中数学题目,请输入生成题目数量"; cout << "(输入-1将退出当前用户,重新登录):" << endl; break; } } int number = 0; cin >> number; // 选择出题数量 if (number == -1) { user = 0; } else if ((number <= 30) && (number >= 10)) { // 调用生成试卷函数:将试题数量、用户、类型传入 get(number, user, type); cout << "卷子生成成功!已退出" << endl; cout << "试卷生成系统" << endl; cout << "请输入用户名和密码" << endl; user = 0; } } } }View Code
本次代码使用将近400行代码来实现出卷功能。我将以登录,切换出卷模式,出卷,查重这四个功能进行讲述。
使用while循环用if来判断用户及密码是否正确,并设定了用户类型跟出卷类型为user跟type。
cout << "试卷生成系统" << endl; cout << "请输入用户名和密码" << endl; while (1) { // user等于0时表示登录初始界面,不同的user的值表示不同的账户 if (user == 0) { char username[20] = ""; char password[20] = ""; cin >> username >> password; if ((strcmp(username, "张三1") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为小学出题" << endl; user = 1; type = 1; } else if ((strcmp(username, "张三2") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为小学出题" << endl; user = 2; type = 1; } else if ((strcmp(username, "张三3") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为小学出题" << endl; user = 3; type = 1; } else if ((strcmp(username, "李四1") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为初中出题" << endl; user = 4; type = 2; } else if ((strcmp(username, "李四2") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为初中出题" << endl; user = 5; type = 2; } else if ((strcmp(username, "李四3") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为初中出题" << endl; user = 6; type = 2; } else if ((strcmp(username, "王五1") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为高中出题" << endl; user = 7; type = 3; } else if ((strcmp(username, "王五2") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为高中出题" << endl; user = 8; type = 3; } else if ((strcmp(username, "王五3") == 0) && (strcmp(password, "123") == 0)) { cout << "登录成功" << endl; cout << "当前选择为高中出题" << endl; user = 9; type = 3; } else { cout << "请输入正确的用户名、密码:" << endl; } }登录代码
在每次出卷前都要输入出卷的类型如”切换为小学“才能进入出卷,并输出当时为什么类型的出卷。
if (user >= 1) { char choosetype[20] = ""; cout << "是否更换当前出题类型" << endl; cin >> choosetype; // 切换出题类型 if (strcmp(choosetype, "切换为小学") == 0) { type = 1; } else if (strcmp(choosetype, "切换为初中") == 0) { type = 2; } else if (strcmp(choosetype, "切换为高中") == 0) { type = 3; } else { cout << "请输入小学、初中和高中三个选项中的一个" << endl; continue; } switch (type) { case 1: { cout << "准备生成小学数学题目,请输入生成题目数量"; cout << "(输入-1将退出当前用户,重新登录):" << endl; break; } case 2: { cout << "准备生成初中数学题目,请输入生成题目数量"; cout << "(输入-1将退出当前用户,重新登录):" << endl; break; } case 3: { cout << "准备生成高中数学题目,请输入生成题目数量"; cout << "(输入-1将退出当前用户,重新登录):" << endl; break; } }切换出卷类型代码
使用get(int NUM, int USER, int TYPE)来进行出卷,传入参数出卷题目数量,出卷人,出卷的类型。
并把出的试卷生成并保存在该用户的目录下,以出卷时间为命名的txt文件。根据小学加减乘除括号,初中有根号或者平方,高中有三角函数来进行分类编写,用rand产生随机数来确定使用什么操作数,操作符,操作数大小,并用string进行拼接,虽然满足了加减乘除,但是在特殊符号的处理上只放在第一位来对算术进行特殊化,如sin50+6*5=。
void get(int NUM, int USER, int TYPE) { time_t t = time(NULL); ofstream File; char ttime[33]; // 确定用户 switch (USER) { case 1: { strftime(ttime, 33, "./张三1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 2: { strftime(ttime, 33, "./张三2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 3: { strftime(ttime, 33, "./张三3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 4: { strftime(ttime, 33, "./李四1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 5: { strftime(ttime, 33, "./李四2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 6: { strftime(ttime, 33, "./李四3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 7: { strftime(ttime, 33, "./王五1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 8: { strftime(ttime, 33, "./王五2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 9: { strftime(ttime, 33, "./王五3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } } File.open(ttime); int randNum = 0; int diff = 0; // 确定类型 switch (TYPE) { case 1: { diff = 0; break; } case 2: { diff = 2; break; } case 3: { diff = 5; break; } } int syn = 0, spin = 0; // 生成题目 for (int i = 1; i <= NUM; i++) { File << i << ". " << endl; if (diff == 0) { randNum = rand() % 4 + 2; } else { randNum = rand() % 5 + 1; } int Number[randNum] = {0, 0, 0, 0, 0}; string sNumber[randNum] = {"", "", "", "", ""}; for (int j = 0; j < randNum; j++) { Number[j] = rand() % 100 + 1; sNumber[j] = to_string(Number[j]); } string FileWrite = ""; if (diff == 0) { spin = 0; } else if (diff == 2) { spin = rand() % 2 + 1; } else if (diff == 5) { spin = rand() % 3 + 3; } string spis = ""; switch (spin) { case 0: { FileWrite = FileWrite + sNumber[0]; break; } case 1: { spis = spis + "^2"; FileWrite = FileWrite + sNumber[0]; FileWrite = FileWrite + spis; break; } case 2: { spis = spis + "√"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 3: { spis = spis + "sin"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 4: { spis = spis + "cos"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 5: { spis = spis + "tan"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } } if (randNum != 1) { int flag = 0; int dir = 0; for (int j = 1; j < randNum; j++) { syn = rand() % 4; string symbol = ""; switch (syn) { case 0: { symbol = symbol + '+'; break; } case 1: { symbol = symbol + '-'; break; } case 2: { symbol = symbol + '*'; break; } case 3: { symbol = symbol + '/'; break; } } FileWrite = FileWrite + symbol; if ((rand() % 3 == 1) && (flag == 0) && (j != randNum - 1)) { FileWrite = FileWrite + "("; flag = 1; dir = j; } FileWrite = FileWrite + sNumber[j]; if ((dir != j) && (flag == 1) && (rand() % 3 == 2)) { FileWrite = FileWrite + ")"; flag = 2; } } if (flag == 1) { FileWrite = FileWrite + ")"; flag = 2; } } if (find(FileWrite, USER) == 1) { File << FileWrite; File << endl << endl; } else { i = i - 1; } } File.close(); }View Code
首先是传入该用户的信息,以此来进入该用户目录下的文件,在遍历目录下所有文件,进入文件中的txt,提取每一行成string,并于出的题作比较,如果相同返回-1,如果不同返回1.
void getFiles(string path, vector<string> &files) { // 文件句 int16_t hFile = 0; // 文件信息 struct _finddata_t fileinfo; string pathName; if ((hFile = _findfirst(pathName.assign(path).c_str(), &fileinfo)) != -1) { do { if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) files.push_back(pathName.assign(path). append("/").append(fileinfo.name)); } while (_findnext(hFile, &fileinfo) == 0); _findclose(hFile); } } // 查重函数:将先前的文档进行遍历, // 然后在提取出每一行的字符串, // 比较每一行的字符串, // 若没有重复则返回1,重复了就返回-1 int find(string test, int ty) { string FindType = ""; switch (ty) { case 1: { FindType = "./张三1/"; break; } case 2: { FindType = "./张三2/"; break; } case 3: { FindType = "./张三3/"; break; } case 4: { FindType = "./李四1/"; break; } case 5: { FindType = "./李四2/"; break; } case 6: { FindType = "./李四3/"; break; } case 7: { FindType = "./王五1/"; break; } case 8: { FindType = "./王五2/"; break; } case 9: { FindType = "./王五3/"; break; } } vector<string> files; getFiles(FindType, files); int size = files.size(); for (int i = 0; i < size; i++) { ifstream fin(files[i]); string past; while (fin >> past) { if (past == test) return (-1); } } return 1; }查重
本次编程基本实现了功能,在每个用户下正确出小学,初中,高中试卷,出卷题目满足要求。代码使用get函数进行出题,getFile和find函数进行查重,查重通过才写入txt。
注释太少,操作数,操作符的注释没有,让人刚开始理解起来不是那么流畅。功能实现有不合理性,因为只在第一位数字才进行特殊化处理,题目就没有那么合理性。
我的也是使用的是C++,大体是一样的,但是在出题的时候,他是三份类型试卷一起写,理解起来较为困难。对比起来,总会发现自己与他人的差别,在之后也会学习别人的优点,运用更好的方法。