上篇文章讲到使用Cena评测C++代码时,必须在源文件中添加重定向语句,这还得专门写在比赛的说明中,太不人性化了;而且目前为止Cena还不能评测Java代码,今天就一并解决了这两个问题~
先说一下Cena评测的原理。评测时首先把源文件复制到试题目录下的tmp目录,然后随机重命名源文件。然后在该目录中创建你新建试题时设置的输入文件,并把测试点的输入文件的内容复制进去。其次编译、运行源文件,运行时从创建的输入文件读取数据,把程序输出重定向到你创建试题设置的那个输出文件。最后,比较该输出文件和该测试点的输出文件从而判分。(细节上可能有误,但就是这个大概流程。)
知道了原理,那我们就能更好地理解为什么要在源程序里加上输入输出重定向语句了。那么怎么解决能够不添加也好使呢?最快想到的方法就是在配置编译器那里:工具-选项…-编程语言-cpp的运行一栏,把%s.exe修改为%s.exe 。然而,亲测无效 :(
好吧,运行命令自己写一个怎么样?
这是我写的,亲测可用:
#include <cstring>
#include <cstdlib>
int main(int argc,char** argv){
//bc.exe %s
if(argc!=2)return 0;
std::string temp(argv[1],strlen(argv[1]));
std::string cmd=temp+".exe <in.txt >out.txt";
system(cmd.c_str());
return 0;
/*
//并不需要自己写编译工具,g++即可
//ac.exe %s [path/to/g++]
if(argc!=2 && argc!=3)return 0;
string g="g++";
if(argc==3){
g=argv[2];
}
string cmd=g;
string temp(argv[1],strlen(argv[1]));
cout<<temp<<endl;
cmd = cmd +" "+temp+".cpp -o "+temp+".exe";
cout<<cmd<<endl;
system(cmd.c_str());
return 0;
*/
}

第二个问题,解决不能评测java代码的问题。
问题症结在于,天杀的cena在复制源文件时会随机重命名!好吧,那么我们得把文件名改回正确的文件名,再使用javac编译即可。然而,怎么才能知道正确的文件名呢?嗯,程序的公共主类(public class)名就是主类吧,然而我并不想自己一行一行地扫描源文件找public class后面的那个词是什么,万一人家把public class 写在不同的行呢。比较折衷的方法是,约定选手在源文件的第一行加上一条双斜线开头的注释,注释内容为文件名并紧接着换一行。这样就可以很容易地获取到源文件的正确文件名了。
那么我们可以把随机名文件复制到正确名文件,然后调用javac编译。运行时也是一行,调用java 主类名执行。
下面是用C++写的用于Cena编译java的小程序:
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
int main(int argc,char** argv){
//ajavac.exe %s [path/to/javac]
if(argc!=2 && argc!=3){cout<<"Usage: path/to/ajavac.exe %s [path/to/javac]\n";return 0;}
string cmd="javac";
if(argc==3){
cmd=argv[2];
//可能有空格,所以要加引号:
//"D:\Program Files\Java\jdk1.8.0_05\bin\javac.exe"
cmd="\""+cmd+"\"";
}
string filename(argv[1],strlen(argv[1]));
ifstream fin;
filename+=".java";
fin.open(filename.c_str(),ios_base::in);
char temp;
string rightname;
while(fin.get(temp) && temp!='\n'){
if(temp=='/')continue;
rightname+=temp;
}
cmd +=" "+rightname;
//复制
system(("copy "+filename+" "+rightname).c_str());
//编译
system(cmd.c_str());
return 0;
}

这是C++写的用于Cena的运行java的工具:
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
using namespace std;
int main(int argc,char** argv){
//bjavac.exe %s [path/to/java.exe]
if(argc!=2 && argc!=3){cout<<"Usage: path/to/bjava %s\n";return 0;}
string cmd="java";
if(argc==3){
cmd=argv[2];
//可能有空格,所以要加引号:
//"D:\Program Files\Java\jdk1.8.0_05\bin\java.exe"
cmd="\""+cmd+"\"";
}
string filename(argv[1],strlen(argv[1]));
filename += ".java";
ifstream fin(filename.c_str(),ios_base::in);
char temp;
string classname;
while(fin.get(temp) && temp!='.'){//A.java
if(temp=='/')continue;
classname+=temp;
}
cmd += " "+classname+" <in.txt >out.txt";
system(cmd.c_str());
return 0;
}

感谢这篇文章的思路:关于cena配置java编译器和basic编译器的问题
大功告成!
不过,有可能你还想让选手在评测时及时查看自己的成绩,下篇文章我们再看这个需求如何解决~
声明
- 本作品采用署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。除非特别注明, 霖博客文章均为原创。
- 转载请保留本文(《Cena代码评测软件系列之二:评测Java代码》)链接地址: https://youthlin.com/?p=990
- 订阅本站:https://youthlin.com/feed/
“Cena代码评测软件系列之二:评测Java代码”上的3条回复
[…] 上篇文章讲到约定源文件注释格式来提取正确文件名从而使用Cena评测Java代码,这篇文章分享使用php解析Cena生成的xml评测结果文件的方法从而使得选手能够在一轮评测后查看自己的成绩。 […]
你已经掉入C++和JAVA双重二次元世界。。
我就看看,什么都看不懂,五颜六色的字母,很好看。![[/可爱]](https://youthlin.com/wp-content/themes/twentytwenty-child/images/smilies/可爱.gif)