中小学数学卷子自动生成程序——结对编程队友互评
一、题目介绍
本博客是对结对编程队友严同学编写的个人项目的分析评价,编写语言为C++。项目要求实现生成小学、初中和高中难度的题目,题目数量范围在10~30,每次生成的题目数量可自行选择并产生在相应的文件夹中。
二、代码分析
整个项目由一个cpp文件组成,定义了一个User类,通过该类实现项目的功能调用:
User类
class User {
public:
void Sign_In(); //登录
void Create_Exam(); //生成试卷
void Create_File(); //生成文件
void Change_Type(); //转换试卷类型
bool Check_Topic(); //检查是否题目重复
private:
string name; //用户名
string passward; //密码
string type; //用户年级类型
string folder_path; //文件夹路径
string path; //.txt文件路径
int num; //题目数目
bool state; //登录状态
stringstream topic; //临时保存题目
string all_topic; //题目合集
};
用户登录
void User::Sign_In() { //用户登录
while(1) {
cout<<"请输入用户名和密码,两者之间用空格隔开:"<<endl;
cin>>name>>passward;
if(passward=="123") {
state=1;
if(name=="张三1" || name=="张三2" || name=="张三3")
type="小学";
else if(name=="李四1" || name=="李四2" || name=="李四3")
type="初中";
else if(name=="王五1" || name=="王五2" || name=="王五3")
type="高中";
cout<<"登录成功!"<<endl;
Change_Type();
}
else
cout<<"请输入正确的用户名、密码"<<endl;
}
}
生成文件
void User::Create_File() { //生成文件
folder_path="./"+name; //文件夹路径
if(access(folder_path.c_str(),0)!=0)
mkdir(folder_path.c_str());
char filename[30];
struct tm *ptr;
time_t t=time(NULL);
ptr=localtime(&t);
strftime(filename,30,"%y-%m-%d-%H-%M-%S.txt",ptr); //将文件以"年-月-日-时-分-秒.txt"的形式保存
path=name+"\\"+filename; //生成.txt文件的路径
}
生成试卷
void User::Create_Exam() { //生成试卷
cout<<"准备生成"<<type<<"数学题目,请输入生成题目数量(范围10~30,-1退出当前用户):"<<endl;
cin>>num;
if(num==-1){
system("cls");
cout<<"退出登录成功"<<endl;
state=0;
return;
}
while(num<10 || num>30) {
cout<<"生成失败,题目数量范围10~30,请重新输入:"<<endl;
cin>>num;
}
ofstream write;
write.open(path.c_str()); //创建文件打开
write<<type<<"数学,共"<<num<<"题"<<endl<<endl;
int N=num;
while(N!=0) {
N--;
int operand; //操作数个数
if(type=="小学")
operand=rand()%4+2;
else
operand=rand()%5+1;
if(operand==1) //减少仅有一个操作数的几率
operand+=rand()%5;
int op=operand;
int bracket_left=0; //括号开始位置
int bracket_size=0; //括号内操作数个数
if(operand>2 && rand()%2==1) { //1/2几率生成有括号题目
if(operand==3){ //操作数个数为3时两种括号生成情况
bracket_left=rand()%2+1;
bracket_size=2;
}
else if(operand==4) { //操作数个数为4时
bracket_left=rand()%3+1;
if(bracket_left==3) //左括号在第3个操作数前时
bracket_size=2; //左括号在第1或第2个操作数前时
else
bracket_size=rand()%2+2;
}
else if(operand==5) { //操作数个数为5时
bracket_left=rand()%4+1;
if(bracket_left==4) //左括号在第4个操作数前时
bracket_size=2;
else if(bracket_left==3) //左括号在第3个操作数前时
bracket_size=rand()%2+2;
else //左括号在第1或第2个操作数前时
bracket_size=rand()%3+2;
}
}
bool flag=0; //初中题目是否有平方/根号,高中题目是否有三角函数
while(op!=0) {
int value=rand()%100+1; //随机生成操作数的值
op--;
if(op==operand-bracket_left)
topic<<"(";
int choose; //运算符选择,1、2为平方根号,3、4、5为sin,cos,tan
if(type=="小学")
choose=0;
else if(type=="初中") {
choose=rand()%4;
if(choose!=0) //至少有一个平方或根号了
flag>1;
if(op==0 && flag==0) //到最后一个操作数都没有平方或根号
choose=rand()%2+2;
}
else if(type=="高中") {
choose=rand()%7;
if(choose>3) //至少有一个三角函数
flag=1;
if(op==0 && flag==0)
choose=rand()%3+4; //到最后一个操作数都没有三角函数
}
if(choose==0 || choose==1) //操作数加上初中高中运算符
topic<<value;
else if(choose==2)
topic<<"√"<<value;
else if(choose==3)
topic<<value<<"^2";
else if(choose==4)
topic<<"sin"<<value;
else if(choose==5)
topic<<"cos"<<value;
else if(choose==6)
topic<<"tan"<<value;
if(op==operand-bracket_left-bracket_size+1) //加右括号
topic<<")";
if(op!=0) {
choose=rand()%4; //choose为1、2、3、4对应加减乘除
if(choose==0)
topic<<"+";
else if(choose==1)
topic<<"-";
else if(choose==2)
topic<<"×";
else if(choose==3)
topic<<"÷";
}
else
topic<<"=";
}
if(Check_Topic()) {
write<<num-N<<"、"<<topic.str()<<endl<<endl;
topic.str(""); //清空topic
}
else
N++;
}
write.close();
cout<<"已成功生成"<<type<<"数学试卷!"<<endl<<endl;
}
切换题目类型
void User::Change_Type() { //切换题目类型
string change;
char flag;
while(state) {
cout<<"-----------当前选择为"<<type<<"出题-----------"<<endl;
cout<<"-----------是否切换出题类型?(y/n)----------"<<endl;
cin>>flag;
if(flag=='y') {
cout<<"请输入要转换的类型:";
while(1) {
cin>>change;
if(change!="小学" && change!="初中" && change!="高中")
cout<<"转换失败!请输入正确的类型:";
else {
type=change;
break;
}
}
}
Create_File();
Create_Exam();
}
}
查重
bool User::Check_Topic() {
string check_path=name+"\\Check_Topic.txt";
fstream check;
check.open(check_path.c_str(),ios::in|ios::app); //生成Check_Topic.txt文件
stringstream ss;
ss<<check.rdbuf();
all_topic=ss.str(); //将Check_Topic.txt文件的题目读到all_topic中用来判断是否有题重复
if(all_topic.find(topic.str())==string::npos) { //没有重复
check<<topic.str(); //更新Check_Topic文件
return 1;
}
return 0;
}
main
int main() {
User user;
srand((unsigned)time(NULL)); // 产生随机数种子
user.Sign_In();
return 0;
}
代码观看感受:
1、整个项目结构清晰,函数功能简洁实用,必要地方使用注释,极好地缩短分析时间,缩进和变量名的命名都按照了Google的编码规范执行;
2、文件输出部分使用相对路径,保证能正常输出结果且方便后期查看输出的题目;
3、在终端运行的界面也较为人性化,合理的操作提示,让使用者用的很舒服。
三、代码运行测试
用户登录,生成初始难度题目
切换难度,生成高中难度题目
程序使用感受:
具体使用下来,除了每次操作都会询问是否切换难度,会导致使用时有点糟心,其他的都是完成的非常好的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】