写了个看起来功能比较全的对拍器

· · 个人记录

支持 Special Judge,直接通过源代码对拍,自定义比较器。

另外鉴于 Linux 自带的 diff 不能处理行空格和文末换行,我自己写了个比较器。

所有功能组合都测试过了一遍。

欢迎大佬们看蒟蒻有没有写挂。

帮助写在了注释里面。

对拍器:

/* 
这个对拍器支持 SPJ,支持直接通过源代码对拍,支持自由选择文件比较器。  

这些选项都是可以自由切换的,对拍器内可以选择 全文比较/Special Judge,源代码对拍/可执行文件对拍,自由选择文件比较器。  

- 对于 Special Judge 对拍  
本程序将执行:<SpecialJudge> <input> <Output> <answer>  
即和 testlib 的 checker 命令格式一样。  
SPJ 返回代码为 0,代表正确,否则错误。  
*/
#include <bits/stdc++.h>
using namespace std;
int main()
{
    cout<<"==============对拍程序=============\n";
    string stdname,bruname,genname,spjname;
    string stdexe,bruexe,genexe,spjexe;
    int time_now=clock();
    int op,op2;
    cout<<"待对拍程序以源文件给出,请输入 0,以可执行文件给出,请输入 1:";
    cin>>op;
    if(op!=0&&op!=1)
    {
        cerr<<"不合法\n";
        exit(0);
    }
    cout<< "若使用 Special Judge,输入 1,否则输入 0:";
    cin>>op2;
    if(op2!=0&&op2!=1)
    {
        cerr<<"不合法\n";
        exit(0);
    }
    if(op==0)
    {
        cout<<"待对拍程序 1 源文件:";
        cin>>stdname;
        cout<<"待对拍程序 2 源文件:";
        cin>>bruname;
        cout<<"输入数据生成器源文件:";
        cin>>genname;
        if(op2==1)
        {
            cout<<"请输入 Special Judge 源文件:";
            cin>>spjname;
        }
        stdexe=stdname+to_string(time_now);
        bruexe=bruname+to_string(time_now+1);
        genexe=genname+to_string(time_now+2);
        spjexe=spjname+to_string(time_now+3);
        string compile_std="g++ "+stdname+" -o "+stdexe+" -std=c++14";
        string compile_bru="g++ "+bruname+" -o "+bruexe+" -std=c++14";
        string compile_gen="g++ "+genname+" -o "+genexe+" -std=c++14";
        string compile_spj="g++ "+spjname+" -o "+spjexe+" -std=c++14";
        system(compile_std.c_str());
        system(compile_bru.c_str());
        system(compile_gen.c_str());
        if(op2==1)
        {
            system(compile_spj.c_str());
        }
    }
    else
    {
        cout<<"待对拍程序 1 可执行文件:";
        cin>>stdexe;
        cout<<"待对拍程序 2 可执行文件:";
        cin>>bruexe;
        cout<<"输入数据生成器可执行文件:";
        cin>>genexe;
        if(op2==1)
        {
            cout<<"请输入 Special Judge 可执行程序\n";
            cin>>spjexe;
        }
    }
    string dataname=to_string(time_now)+to_string(random_device{}());
    string in=dataname+".in";
    string std_out=dataname+".out_std";
    string bru_out=dataname+".out_bru";
    string makeinput=genexe+" > "+in;
    string execstd=stdexe+" < "+in+" > "+std_out;
    string execbru=bruexe+" < "+in+" > "+bru_out;
    string execspj=spjexe+" "+in+" "+std_out+" "+bru_out+" > "+dataname+".spj";
    string chkdiff;
    string execchkdif;
    if(op2==0)
    {
        cout<<"请输入文件比较器可执行程序:";
        cin>>chkdiff;
    }
    execchkdif=chkdiff+" "+std_out+" "+bru_out+" > "+dataname+".dif";
    int testcnt=0;
    while(1)
    {
        testcnt++;
        system(makeinput.c_str());
        system(execstd.c_str());
        system(execbru.c_str());
        if(op2==1)
        {
            cout<<"Test#"<<testcnt<<" verdict: ";
            if(system(execspj.c_str())==0)
            {
                cout<<"OK\n";
            }
            else
            {
                cout<<"Wrong answer\n";
                break;
            }
        }
        else
        {
            cout<<"Test#"<<testcnt<<" verdict: ";
            if(system(execchkdif.c_str())==0)
            {
                cout<<"OK\n";
            }
            else
            {
                cout<<"Wrong answer\n";
                break;
            }
        }
        sleep(1);
    }
    return 0;
}

文件比较器:

/*
比较两个文件,忽略行末空格,文末空格,制表符,换行。  

用法:  
- 帮助
file-diff --help
- 比较
file-diff <file1> <file2>
- 返回值  
若命令行参数错误,返回代码 -2  
若在比较模式下,文件不同,返回 -1  
否则返回 0,代表正常  
*/
#pragma GCC optimize("O2")
#include <bits/stdc++.h>
using namespace std;
string help="比较两个文件,忽略行末空格,文末空格,制表符,换行。\n \
用法:  \n\
- 帮助  \n\
file-diff --help  \n\
- 比较  \n\
file-diff <file1> <file2>  \n\
- 返回值   \n\
若命令行参数错误,返回代码 -2  \n\
若在比较模式下,文件不同,返回 -1   \n\
否则返回 0,代表正常   \n\
*/";
bool check(string& s)
{
    if(s.empty())return 1;
    for(char v:s)
    {
        if(v!=' '&&v!='\n'&&v!='\r'&&v!='\t')return 0;
    }
    return 1;
}
int main(int argc,char* argv[])
{
    if(argc==1)
    {
        cerr << "没有输入命令行参数,通过 --help 获取帮助\n";
        return -2;
    }
    if(argc==2)
    {
        if(string(argv[1])=="--help")
        {
            cout<<help;
            return 0;
        }
        else
        {
            cerr << "未知命令\n";
            return -2;
        }
    }
    else
    {
        if(argc!=3)
        {
            cerr << "命令行参数数量错误\n";
            return -2;
        }
        else
        {
            string filename1=argv[1];
            string filename2=argv[2];
            auto file1=ifstream(filename1);
            auto file2=ifstream(filename2);
            vector<string> get1,get2;
            string temp;
            while(getline(file1,temp))
            {
                for(size_t idx=temp.size()-1;idx>=0;idx--)
                {
                    if(temp[idx]!='\n'&&temp[idx]!=' '&&temp[idx]!='\t')break;
                    temp.pop_back();
                }
                get1.emplace_back(temp);
            }
            while(!get1.empty()&&check(get1.back()))
            {
                get1.pop_back();
            }
            while(getline(file2,temp))
            {
                for(size_t idx=temp.size()-1;idx>=0;idx--)
                {
                    if(temp[idx]!='\n'&&temp[idx]!=' '&&temp[idx]!='\t')break;
                    temp.pop_back();
                }
                get2.emplace_back(temp);
            }
            while(!get2.empty()&&check(get2.back()))
            {
                get2.pop_back();
            }
            if(get1.size()!=get2.size())
            {
                cerr << "文件行数不匹配。"<<"文件 "<<filename1<<" 行数为 "<<get1.size()<< "\n文件 "<<filename2 <<"行数为 "<<get2.size()<<'\n';
                return -1;
            }
            for(int i=0;i<get1.size();i++)
            {
                if(get1[i]!=get2[i])
                {
                    cerr<<"第 "<< i+1 <<" 行不匹配"<<'\n';
                    cerr<<"分别为:"<<'\n';
                    cerr<<get1[i]<<'\n'<<get2[i]<<'\n'; 
                    return -1;
                }
            }
        }
    }
    cerr<<"找不到任何差异\n";
    return 0;
}