结队编程:对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()函数,将不同账户不同类型的题目分到不同的文件夹。在看他代码的过程中我也学到了一些有用的函数。

猜你喜欢

转载自www.cnblogs.com/plllll/p/11553005.html
今日推荐