• 结队编程:对411同学的代码分析


    
    

    上一周,我们完成了个人项目编程。看过我队友的源码之后,我感触颇深,觉得非常有必要来写一篇文章分析一下队友的代码。他的代码是用C++写的,兼顾性能和可读性,下面是我对我队友源码的一些思考。

    一、主函数

    int main()
    {
        string type="",id="";
        int number=0;    
        id=login();
        cout<<"请输入题目数量(10-30,输入-1则退出当前用户,重新登陆,输入0则表示切换出题类型):"<<endl;
        while(1)
        {
            cin>>number;
            if(number==-1) 
            {
                id=login();
                cout<<"请输入题目数量(10-30,输入-1则退出当前用户,重新登陆;输入0则表示切换出题类型):"<<endl;
            }
            else if(number==0) 
            {
                cout<<"请输入要切换的类型:小学、初中或高中" <<endl; 
                string s;
                int count;
                while(1)
                {
                    cin>>s;
                    if(s.find("小学")!=s.npos)
                    {
                        type="小学";
                        cout<<"准备生成小学数学题目,请输入题目数量:"<<endl; 
                        cin>>count;
                        CreateProblemforLow(id,type,count);
                        break;
                    }
                    else if(s.find("初中")!=s.npos)
                    {
                        type="初中";
                        cout<<"准备生成初中数学题目,请输入题目数量:"<<endl; 
                        cin>>count; 
                        CreateProblemforMid(id,type,count);
                        break;
                    }
                    else if(s.find("高中")!=s.npos)
                    {
                        type="高中"; 
                        cout<<"准备生成高中数学题目,请输入题目数量:"<<endl; 
                        cin>>count;
                        CreateProblemforHigh(id,type,count);
                        break;
                    }
                    else 
                    {
                        cout<<"请输入小学、初中和高中三个选项中的一个"<<endl;
                    }
                }
                break; 
            }
            else 
            {
                if(id.find("张三")!=type.npos) 
                {
                    type="小学"; 
                    CreateProblemforLow(id,type,number);
                }
                else if(id.find("李四")!=type.npos)
                {
                    type="初中"; 
                    CreateProblemforMid(id,type,number);
                } 
                else if(id.find("王五")!=type.npos)
                {
                    type="高中";
                    CreateProblemforHigh(id,type,number);
                } 
                break;
            }
        }    
        return 0;
    }

    主函数基本实现了全部需求的逻辑,但逻辑不是非常的清晰,还有循环的嵌套,但函数名、变量名命名规范,从命名即可得知其功能,提升了代码的可读性,在主函数中将出卷类型以及账户名分开,为后续的分情况调用函数以及将题目输出到对应文件夹提供了参数。

    二、为小学生成题目:

    int CreateProblemforLow(string id,string type,int number)                //生成number个小学题目
    
    {
    
        string topic[60][30];
    
        for(int i=0;i<60;i++)
    
        {
    
            for(int j=0;j<30;j++)
    
            {
    
                topic[i][j]="";
    
            }
    
        }
    
        srand((unsigned)time(NULL));
    
        int flag=0;            //对是否有括号进行标记
    
        int flag2=0;           //对括号是否只括了一个操作数进行标记
    
        for(int i=0;i<number*2;i+=2)
    
        {
    
            int operand=(rand()%(5-1))+2;//操作数数量
    
            int z=2;
    
           
    
            stringstream temp;
    
            temp<<i/2+1;
    
            temp>>topic[i][0];
    
            topic[i][1]=". ";//题目序号
    
           
    
            for(int j=0;j<operand;j++)
    
            {
    
                int l_bracket=(rand()%2);//随机选择是否产生括号,0无括号,1有括号
    
                if(flag==0&&l_bracket==1&&j<operand-1&&j>0)       //左括号
    
                {
    
                    topic[i][z]="(";
    
                    z++;
    
                    flag=1;
    
                }
    
                int operand_data=(rand()%100)+1;//操作数
    
               
    
                         stringstream ss;
    
                ss<<operand_data;
    
                ss>>topic[i][z];//写入操作数
    
               
    
                if(flag==1)
    
                {
    
                    flag2++;
    
                }
    
                z++;
    
                int r_bracket=(rand()%2);
    
                if(flag==1&&r_bracket==1&&flag2>1)     //右括号
    
                {
    
                    topic[i][z]=")";
    
                    z++;
    
                    flag=0;
    
                    flag2=0;
    
                }
    
                if(j==operand-1&&flag==1)
    
                {
    
                    topic[i][z]=")";
    
                    z++;
    
                    flag=0;
    
                    flag2=0;
    
                }
    
                if(j<operand-1)
    
                {
    
                    int sign=(rand()%4)+1;
    
                    switch(sign)
    
                    {
    
                        case 1:topic[i][z]="+";z++;break;
    
                        case 2:topic[i][z]="-";z++;break;
    
                        case 3:topic[i][z]="*";z++;break;
    
                        case 4:topic[i][z]="/";z++;break;
    
                    }
    
                }
    
                else
    
                {
    
                    topic[i][z]="=";
    
                }
    
            }
    
        }
    
        number*=2;
    
        Makefile(number,id,"小学",topic);
    
        cout<<"小学试题已生成完毕,请在对应文件夹查看"<<endl;
    
    }

    出题过程中充分体现了随机的想法,特别是在括号是否出现以及括号的位置考虑了各种可能出现的情况,十分全面,但是,过多的随机数+if语句的组合使得代码显得有些臃肿,而且,似乎没有考虑题目可能重复的情况。关键的、难以理解的地方有简洁明了的注释,恰到好处。看代码的过程中了解了stringstream的用法。

    三、为初中生成题目:

    int CreateProblemforMid(string id,string type,int number)                //生成number个初中题目
    
    {
    
        string topic[60][30];
    
        for(int i=0;i<60;i++)
    
        {
    
            for(int j=0;j<30;j++)
    
            {
    
                topic[i][j]="";
    
            }
    
        }
    
        srand((unsigned)time(NULL));
    
        int flag=0;            //对是否有括号进行标记
    
        int flag2=0;           //对括号是否只括了一个操作数进行标记
    
        for(int i=0;i<number*2;i+=2)
    
        {
    
            int operand=(rand()%5)+1;//操作数数量 1-5
    
            int p=2;
    
            int exp=rand()%2,pos=rand()%operand;//保证至少有一个平方或开根号运算
    
            stringstream temp;
    
            temp<<i/2+1;
    
            temp>>topic[i][0];
    
            topic[i][1]=". ";//题目序号
    
            
    
            for(int j=0;j<operand;j++)
    
            {
    
                int l_bracket=(rand()%2);//随机选择是否产生括号,0无括号,1有括号
    
                if(flag==0&&l_bracket==1&&j<operand-1&&j>0)       //左括号
    
                {
    
                    topic[i][p]="(";
    
                    p++;
    
                    flag=1;
    
                }
    
                int operand_data=(rand()%100)+1;//操作数
    
               
    
                         stringstream ss;
    
                ss<<operand_data;
    
                ss>>topic[i][p];//写入操作数
    
                         p++;
    
                         int ex=rand()%2;
    
                         if(j==pos)
    
                         {
    
                                if(exp==0) topic[i][p++]="^2";
    
                                else if(exp==1)     topic[i][p++]="^(1/2)";
    
                         }
    
                         else if(ex==1)
    
                         {
    
                                if(exp==0) topic[i][p++]="^2";
    
                                else if(exp==1)     topic[i][p++]="^(1/2)";
    
                         }
    
                if(flag==1)
    
                {
    
                    flag2++;
    
                }
    
                int r_bracket=(rand()%2);
    
                if(flag==1&&r_bracket==1&&flag2>1)     //右括号
    
                {
    
                    topic[i][p]=")";
    
                    p++;
    
                    flag=0;
    
                    flag2=0;
    
                }
    
                if(j==operand-1&&flag==1)
    
                {
    
                    topic[i][p]=")";
    
                    p++;
    
                    flag=0;
    
                    flag2=0;
    
                }
    
                if(j<operand-1)
    
                {
    
                    int sign=(rand()%4)+1;
    
                    switch(sign)
    
                    {
    
                        case 1:topic[i][p]="+";p++;break;
    
                        case 2:topic[i][p]="-";p++;break;
    
                        case 3:topic[i][p]="*";p++;break;
    
                        case 4:topic[i][p]="/";p++;break;
    
                    }
    
                }
    
                else
    
                {
    
                    topic[i][p]="=";
    
                }
    
            }
    
        }
    
        number*=2;
    
        Makefile(number,id,type,topic);
    
        cout<<"初中试题生成完毕,请在对应文件夹查看"<<endl;
    
    }
    

    这个函数的大部分代码是重用了上一个函数的代码,包括为高中生成题目的函数也是一样,只是增加了平方和根号或者三角函数的部分,其实可以想办法将这三个函数合并,可以大大减小代码冗余程度。

    四、输出到文件函数:

    int Makefile(int number,string account,string type,string topic[60][30])
    
    {
    
           time_t t=time(0);
    
           char file[30];
    
           strftime(file,sizeof(file),"%Y-%m-%d-%H-%M-%S.txt",localtime(&t));
    
           ofstream openfile((account+'/'+type+'/'+file).c_str());
    
           for(int i=0;i<number;i++)
    
           {
    
                  for(int j=0;j<30;j++)
    
                  {
    
                         openfile<<topic[i][j];
    
                  }
    
                  openfile<<endl;
    
           }
    
    }

    这部分基本都是在调用函数,运用了c++的输入输出流,strftime()函数,将不同账户不同类型的题目分到不同的文件夹。在看他代码的过程中我也学到了一些有用的函数。

  • 相关阅读:
    iOS多线程与网络开发之NSURLCache
    NEFU 117-素数个数的位数(素数定理)
    UISegmentedControl 的使用
    C++使用ADO存取图片
    王立平-- Swift
    浮生猫绘——落入平一的精灵
    BZOJ 1692: [Usaco2007 Dec]队列变换 [后缀数组 贪心]
    POJ2774 Long Long Message [后缀数组]
    BZOJ 2119: 股市的预测 [后缀数组 ST表]
    BZOJ 1717: [Usaco2006 Dec]Milk Patterns 产奶的模式 [后缀数组]
  • 原文地址:https://www.cnblogs.com/plllll/p/11553005.html
Copyright © 2020-2023  润新知