目录
前言
评测机终于更新第三版了。这次更新有较大的改动,我也就写了两个晚上吧(真是太肝了),不过这次改动后评测及也就比较完善了。
v1.0.1版本中有以下几个可以改动的地方:
- 由于功能越来越多,评测机文件夹里的东西也越来越多,很杂乱。
- 每次评测完成后光标就会出现(我也不知道为什么)。
完善
1.针对第一个问题,我们可以把输入数据和测试点数据(sample.in和textpoint.in)放在一个名为data的文件夹中。这就需要在读取数据时加入目录操作。
首先就是获得测试点数据,我们只要对getpoint()函数进行改动就ok了。原本我们读取测试点数据用的是FILE。用法如下:
FILE *p;
p = fopen(filename, "r");
但此函数只能打开本文件夹的文件,所以需要换掉。我们换成fstream,具体用法如下:
fstream(文件地址+名称) filename;
filename.open;
其中filename是自己定义的一个变量。
这样我们就可以把getpoint()函数换成以下代码:
void getpoint(string str_filename){
string tool = "\\data\\";
string t1 = buf + tool + str_filename;
const char* filename = t1.c_str();
fstream myfile;
myfile.open(filename);
string s;
char textpoint[1005];
int _cnt = 0;
while(getline(myfile, s)){
for(int i = 0; i < s.length(); i++){
textpoint[++_cnt] = s[i];
}
textpoint[++_cnt] = '\n';
}
int f;
for(int i = 0; i < strlen(textpoint); i++){//获得测试点个数
if(textpoint[i] == '#'){
f = i;
break;
}
if(textpoint[i] >= '0' && textpoint[i] <= '9')
cnt = cnt * 10 + textpoint[i] - '0';
}
int now = 0;
for(int i = f; i <= strlen(textpoint); i++){//获取测试点时间限制及分数
if(textpoint[i] == '#'){
now++;
}
else if(textpoint[i] == ':'){
int nowlimit = 0;
for(int j = i; j <= strlen(textpoint); j++){
if(textpoint[j] == ','){
int nowpoint = 0;
for(int k = j; k <= strlen(textpoint); k++){
if(textpoint[k] == '#'){
break;
}
if(textpoint[k] <= '9' && textpoint[k] >= '0'){
nowpoint = nowpoint * 10 + textpoint[k] - '0';
}
}
sample[now].point = nowpoint;
break;
}
if(textpoint[j] >= '0' && textpoint[j] <= '9') nowlimit = nowlimit * 10 + textpoint[j] - '0';
}
sample[now].time_limit = nowlimit;
}
}
}
这样就可以在data文件夹里读取测试点数据了。其中buf是data文件的地址,我们可以通过一个函数获取评测机的地址,由于data和评测机放在一起,所以也就获得了data的地址:
GetCurrentDirectory(1000, buf);
第一个问题解决啦。
2.前面我们加入了一个函数,使控制台光标小时,但我i们会发现,每次评测完或者改变了控制台的大小都会让光标再次出现。原因作者上网查找了许久,都没有找到原因。下面贴出让光标隐藏的代码,评论区有大神知道原因欢迎告知。
我们可以手动隐藏光标,在主页加入一个选项,每次选中就可以隐藏光标。
printf("1:评测 2:设置 3:隐藏光标\n");
char choose = getch();
if(choose == '1'){
system("cls");
if(!initialize()){
printf("0:返回\n");
Mypause('0');
continue;
}
start_judge();
system("del ans.out");
system("del std.out");
system("del ans.exe");
system("del std.exe");
printf("0:返回\n");
Mypause('0');
continue;
}
else if(choose == '2'){
while(1){
system("cls");
printf("0:返回\n1:评测方式\n2:比较方式\n");
char choosea = getch();
if(choosea == '1'){
system("cls");
printf("暂不支持\n0:返回\n");
Mypause('0');
}else if(choosea == '2'){
while(1){
system("cls");
printf("0:返回\n1:忽略空格");
if(ifblank){
printf("-\n");
}else{
printf("√\n");
}
printf("2:忽略换行");
if(ifenter){
printf("-\n");
}else{
printf("√\n");
}
char choose2 = getch();
if(choose2 == '1') ifblank = !ifblank;
else if(choose2 == '2') ifenter = !ifenter;
else if(choose2 == '0'){
system("cls");
break;
}
}
}else if(choosea == '0'){
system("cls");
break;
}
}
}else if(choose == '3'){
hide();
}
这样就可以暂时解决这个问题了。(有点投机取巧)
完整代码
最后,贴上完整代码
评测机.cpp
//v1.0.2
#include"tools.h"
int main(){
system("title 评测机");
color(7);
GetCurrentDirectory(1000, buf);
Clear_Qiuckedit();
while(1){
hide();
gotoxy(1, 1);
printf("1:评测 2:设置 3:隐藏光标\n");
char choose = getch();
if(choose == '1'){
system("cls");
if(!initialize()){
printf("0:返回\n");
Mypause('0');
continue;
}
start_judge();
system("del ans.out");
system("del std.out");
system("del ans.exe");
system("del std.exe");
printf("0:返回\n");
Mypause('0');
continue;
}
else if(choose == '2'){
while(1){
system("cls");
printf("0:返回\n1:评测方式\n2:比较方式\n");
char choosea = getch();
if(choosea == '1'){
system("cls");
printf("暂不支持\n0:返回\n");
Mypause('0');
}else if(choosea == '2'){
while(1){
system("cls");
printf("0:返回\n1:忽略空格");
if(ifblank){
printf("-\n");
}else{
printf("√\n");
}
printf("2:忽略换行");
if(ifenter){
printf("-\n");
}else{
printf("√\n");
}
char choose2 = getch();
if(choose2 == '1') ifblank = !ifblank;
else if(choose2 == '2') ifenter = !ifenter;
else if(choose2 == '0'){
system("cls");
break;
}
}
}else if(choosea == '0'){
system("cls");
break;
}
}
}else if(choose == '3'){
hide();
}
}
return 0;
}
tools.h
#ifndef TOOLS_H
#define TOOLS_H
#include<bits/stdc++.h>
#include<windows.h>
#include<conio.h>
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
#define WIFEXITED(status) ((status & 0x7f) == 0)
using namespace std;
namespace mname{
char textpoint[10000];
char buf[10000];
struct node{
int time_limit, point;
}sample[1005];
int cnt, mysco, totlesco;
int outcheck_std, outcheck_ans;
const int maxn = 100005;
char ANS[maxn], STD[maxn] = "";
clock_t start, end;
double elapsed_secs;
const char *name1 = "test.in";
string samplename = "sample";
bool ifblank = 1, ifenter = 1;
}
using namespace mname;
void Clear_Qiuckedit(){
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode;
GetConsoleMode(hStdin, &mode);
mode &= ~ENABLE_QUICK_EDIT_MODE;
SetConsoleMode(hStdin, mode);
}
void hide(int hide_type = 0){
CONSOLE_CURSOR_INFO cursor_info = {1, hide_type};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
void color(int x, bool intensity = true){
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
x | (intensity << 3));
}
void gotoxy(int x, int y){
COORD pos = {y - 1, x - 1};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void print(string s, int n){
gotoxy(1, 1);
cout << "状态:";
color(n);
cout << s << " " << endl;
color(7);
}
bool findfile(string str_find_filename, bool data = true){
const char* find_filename;
if(data){
find_filename = str_find_filename.c_str();
FILE *fp;
fp = fopen(find_filename, "r");
fclose(fp);
return fp;
}else{
string tool = "\\data\\";
string t1 = buf + tool + str_find_filename;
find_filename = t1.c_str();
fstream file(find_filename);
return file;
}
}
void enter_deal(const char* filename, bool ifblank = 1, bool ifenter = 1){
int i, j = 0;
char s[10000];
FILE *p;
p = fopen(filename, "r");
fscanf(p, "%[^$]", s);
fclose(p);
for(int i = 0; i < strlen(s); i++){
if((!ifblank && s[i] == ' ') || (!ifenter && s[i] == '\n'))
continue;
s[j++] = s[i];
}
s[j] = 0;
p = fopen(filename, "w");
fprintf(p, "%s", s);
fclose(p);
return;
}
bool compare(const char* filename1, const char* filename2){
int i, j = 0;
char s1[10000];
FILE *p1;
p1 = fopen(filename1, "r");
fscanf(p1, "%[^$]", s1);
fclose(p1);
char s2[10000];
FILE *p2;
p2 = fopen(filename2, "r");
fscanf(p2, "%[^$]", s2);
fclose(p2);
if(strlen(s1) != strlen(s2)) return false;
for(int i = 0; i < strlen(s1); i++){
s1[j++] = s1[i];
}
j = 0;
for(int i = 0; i < strlen(s1); i++){
s2[j++] = s2[i];
}
for(int i = 0; i < strlen(s1); i++){
if(s1[i] != s2[i]) return false;
}
return true;
}
void getpoint(string str_filename){
string tool = "\\data\\";
string t1 = buf + tool + str_filename;
const char* filename = t1.c_str();
fstream myfile;
myfile.open(filename);
string s;
char textpoint[1005];
int _cnt = 0;
while(getline(myfile, s)){
for(int i = 0; i < s.length(); i++){
textpoint[++_cnt] = s[i];
}
textpoint[++_cnt] = '\n';
}
int f;
for(int i = 0; i < strlen(textpoint); i++){//获得测试点个数
if(textpoint[i] == '#'){
f = i;
break;
}
if(textpoint[i] >= '0' && textpoint[i] <= '9')
cnt = cnt * 10 + textpoint[i] - '0';
}
int now = 0;
for(int i = f; i <= strlen(textpoint); i++){//获取测试点时间限制及分数
if(textpoint[i] == '#'){
now++;
}
else if(textpoint[i] == ':'){
int nowlimit = 0;
for(int j = i; j <= strlen(textpoint); j++){
if(textpoint[j] == ','){
int nowpoint = 0;
for(int k = j; k <= strlen(textpoint); k++){
if(textpoint[k] == '#'){
break;
}
if(textpoint[k] <= '9' && textpoint[k] >= '0'){
nowpoint = nowpoint * 10 + textpoint[k] - '0';
}
}
sample[now].point = nowpoint;
break;
}
if(textpoint[j] >= '0' && textpoint[j] <= '9') nowlimit = nowlimit * 10 + textpoint[j] - '0';
}
sample[now].time_limit = nowlimit;
}
}
}
void printsample(string str_filename, string str_filename2){
string tool = "\\data\\";
string t1 = buf + tool + str_filename;
const char* filename = t1.c_str();
const char* filename2 = str_filename2.c_str();
fstream myfile;
myfile.open(filename);
string s;
char ch[1005];
int cnt = 0;
while(getline(myfile, s)){
for(int i = 0; i < s.length(); i++){
ch[++cnt] = s[i];
}
ch[++cnt] = '\n';
}
FILE *p;
p = fopen(filename2, "w");
fprintf(p, "%s", ch + 1);
fclose(p);
return;
}
void judge(){
for(int i = 1; i <= cnt; i++){
totlesco += sample[i].point;
cout << "#" << i << ": ";
char temp[10000];
sprintf(temp, "%d", i);
string toname = samplename + temp + ".in";
const char *name2 = toname.c_str();
if(!findfile(name2, 0)){
cout << "未找到" << name2 << "!\n";
continue;
}
printsample(name2, name1);
outcheck_std = system("std.exe");
start = clock();//
outcheck_ans = system("ans.exe");
end = clock();//
elapsed_secs = static_cast<double>(end - start);//
if(outcheck_std == -1 || outcheck_ans == -1 || WIFEXITED(outcheck_std) == false || WIFEXITED(outcheck_ans) == false || 0 != WEXITSTATUS(outcheck_std) || 0 != WEXITSTATUS(outcheck_ans)){
color(5);
cout << "RE";
color(7);
cout << "(" << elapsed_secs << "ms)\n";
continue;
}
if(elapsed_secs > sample[i].time_limit){
color(3);
cout << "TLE";
color(7);
cout << "(" << elapsed_secs << "ms)\n";
continue;
}
bool ifcontinue = 1;
if(!findfile("ans.out")){
cout << "未找到输出!\n";
ifcontinue = 0;
}
if(!findfile("std.out")){
cout << "未找到输出!\n";
ifcontinue = 0;
}
if(!ifcontinue) continue;
enter_deal("ans.out", ifblank, ifenter);
enter_deal("std.out", ifblank, ifenter);
int count_ans = 0, count_std = 0;
freopen("std.out", "r", stdin);
scanf("%s", STD);
freopen("ans.out", "r", stdin);
scanf("%s", ANS);
fclose(stdin);
if(compare("ans.out", "std.out")){
color(2);
cout << "AC";
color(7);
cout << "(" << elapsed_secs << "ms)\n";
mysco += sample[i].point;
}
else{
color(4);
cout << "WA";
color(7);
cout << "(" << elapsed_secs << "ms)\n";
}
// printf("Your answer:\n%s\nCorrect answer:\n%s\n", ANS, STD);//输出用户答案以及正确答案
}
}
void start_judge(){
getpoint("textpoint.txt");
print("提交中", 7);
int i = 0, j = 0;
gotoxy(1, 1);
print("编译中", 7);
if(sizeof(char*) == 4){
int status_std32 = 0, status_ans32 = 0;
status_std32 = system("g++ -o std.exe -m32 std.cpp");
status_ans32 = system("g++ -o ans.exe -m32 ans.cpp");
if(status_ans32 == -1 || status_std32 == -1 || WIFEXITED(status_ans32) == false || WIFEXITED(status_std32) == false || 0 != WEXITSTATUS(status_ans32) || 0 != WEXITSTATUS(status_std32)){
print("CE", 6);
return ;
}
}
if(sizeof(char*) == 8){
int status_std = 0, status_ans = 0;
status_std = system("g++ -o std.exe std.cpp");
status_ans = system("g++ -o ans.exe ans.cpp");
if(status_ans == -1 || status_std == -1 || WIFEXITED(status_ans) == false || WIFEXITED(status_std) == false || 0 != WEXITSTATUS(status_ans) || 0 != WEXITSTATUS(status_std)){
print("CE", 6);
return ;
}
}
print("评测中", 7);
judge();
print("评测结束", 7);
gotoxy(cnt + 2, 1);
cout << "分数:" << mysco << "(/" << totlesco << ")" << endl;
printf("结果:");
if(totlesco == mysco){
color(2);
printf("Accept\n");
color(7);
}
else{
color(4);
printf("Unaccept\n");
color(7);
}
}
//void deletefile(){
// system("del ans.exe");
// system("del std.exe");
// system("del ans.out");
// system("del std.out");
// system("del test.in");
//}
bool initialize(){
bool back = 1;;
if(!findfile("std.cpp")){
printf("未找到std.cpp!\n");
back = 0;
}
if(!findfile("ans.cpp")){
printf("未找到源程序!\n");
back = 0;
}
if(!findfile("textpoint.txt", 0)){
printf("请创建textpoin.txt并将测试点数据存入\n");
back = 0;
}
cnt = 0;
totlesco = 0;
mysco = 0;
return back;
}
void Mypause(char to){
while(1){
if(kbhit()){
char ch = getch();
if(ch == to){
system("cls");
break;
}
}
}
}
void setup(){//1评测方式2对拍方式
}
#endif
用法嘛,其他都一样,参考c++编写评测机(1)。不同的就是要在评测及所在的文件夹里新建一个文件夹,命名为data,将输入数据(sample.in)和测试点数据(textpoint.txt)放入,就可以了。
后续透露
现在的评测机只能和std.cpp生成的答案进行比较,如果没有标程就无法评测。所以我们要加一种对拍方式。就透露这么多了~
ps:代码里有剧透。