写了个看起来功能比较全的对拍器
__vector__ · · 个人记录
支持 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;
}