目录
前言
第三版已经很完善了,本版本主要是完善细节以及把上次代码里的剧透完善。完善后评测机就基本上可以完成日常的评测了。不过以后肯定还会有后续,而且后续的评测机会越来越趋近完善,最终目标是做成一个评测软件。看着评测机一点点完善,我觉得最终目标也不远了。
好了,废话不多说进入今天正题吧。
首先,v1.0.2版本中可以优化的有以下几个地方
- 只能与std.cpp输出的答案进行比较,若没有std.cpp就无法进行比较。
- 到现在评测机都没有一个名字~(现在看起来不是个问题,但到了以后做软件肯定得有个名字吧)。
- 加点有意思的东西。
完善
1.我们想想,怎么才能直接和文件进行比较呢?其实实现非常简单,我们只需要增加一个“与cpp比较”的选项,选中后就与cpp比较,否则就与目标文件中存放的答案进行比较。与答案进行比较时,就把编译std.cpp的过程跳过,依旧将答案存入std.out文件中。由于原来就是将ans.out和std.out进行比较,所以将答案存入std.out后可以直接用后面的代码进行比较。
while(1){
system("cls");
printf("0:返回\n1:与cpp比较");
if(std_judge){
printf("√\n");
}else{
printf("-\n");
}
char std_choose = getch();
if(std_choose == '1') std_judge = !std_judge;
else if(std_choose == '0'){
system("cls");
break;
}
}
其中std_judge是爬满断是否与std.cpp进行比较,否则就直接与答案进行比较。
知道了是否与答案直接进行比较,那么如何与答案进行直接比较呢?
if(!std_judge){
string std_toname = samplename + temp + ".out";
const char *std_name2 = std_toname.c_str();
if(!findfile(std_name2, 0)){
cout << "未找到" << std_name2 << "!\n";
continue;
}
printsample(std_name2, stdname);
start = clock();
outcheck_ans = system("ans.exe");
end = clock();
elapsed_secs = static_cast<double>(end - start);
if(outcheck_ans == -1 || WIFEXITED(outcheck_ans) == false || 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(!ifcontinue) continue;
enter_deal("ans.out", ifblank, ifenter);
enter_deal("std.out", ifblank, ifenter);
int count_ans = 0;
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";
}
}
可以发现,相较于和std.cpp进行比较,直接与答案进行比较只不过是把编译std.cpp的代码去掉了,并且把sample.out中的答案存入std.out中,后面依旧是将ans.out和std.out进行比较。
2.评测及到现在还没有个名字呢,我们取个什么名字呢?还是让你们投票决定吧!(个人认为叫水滴比较好)。
3.我们给评测及加点有意思的东西吧,不然太单调了。加点什么呢?比方说打卡。我们可以统计连续打卡天数,并规定有一天段开就从零开始重新计数(太残忍了qwq)。
void daka(){
FILE *fp = fopen("daka.sdsys", "r+");
if (fp == NULL) {
createFile("daka.sdsys");
}
time_t now = time(NULL);
struct tm *tm_now = localtime(&now);
int today = tm_now->tm_yday;
int last_day = 0, streak = 1;
fscanf(fp, "%d%d", &last_day, &streak);
if (last_day == today) {
printf("今天已经打卡了!连续打卡%d天!\n", streak);
}else{
fseek(fp, 0, SEEK_SET);
fprintf(fp, "%d", today);
fflush(fp);
if(last_day == today - 1) {
streak++;
}else{
streak = 1;
}
printf("打卡成功!连续打卡 %d 天!\n", streak);
fprintf(fp, " %d", streak);
}
fclose(fp);
}
把打卡天数存入daka.sddays文件中,文件的后缀名其实是我自己编的,为的是不让用户自己改动打卡天数。这样就能实现打卡了!
我们的v1.0.3版本就完善好了。
完整代码
tools.h
//v1.0.3
#ifndef TOOLS_H
#define TOOLS_H
#include<bits/stdc++.h>
#include<dirent.h>
#include<windows.h>
#include<conio.h>
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
#define WIFEXITED(status) ((status & 0x7f) == 0)
using namespace std;
namespace My_Space{
char textpoint[10005];
char buf[10000];
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";
const char *stdname = "std.out";
string samplename = "sample";
bool ifblank = 1, ifenter = 1, std_judge = 1;
struct SAMPLE{
int time_limit, point;
}sample[1005];
}
using namespace My_Space;
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);
}
void createFile(char* fileName) {
FILE* fp;
fp = fopen(fileName, "w");
if(fp == NULL) {
printf("Error: cannot create file!\n");
} else {
printf("File created successfully!\n");
fclose(fp);
}
}
void daka(){
FILE *fp = fopen("daka.sdsys", "r+");
if (fp == NULL) {
createFile("daka.sdsys");
}
time_t now = time(NULL);
struct tm *tm_now = localtime(&now);
int today = tm_now->tm_yday;
int last_day = 0, streak = 1;
fscanf(fp, "%d%d", &last_day, &streak);
if (last_day == today) {
printf("今天已经打卡了!连续打卡%d天!\n", streak);
}else{
fseek(fp, 0, SEEK_SET);
fprintf(fp, "%d", today);
fflush(fp);
if(last_day == today - 1) {
streak++;
}else{
streak = 1;
}
printf("打卡成功!连续打卡 %d 天!\n", streak);
fprintf(fp, " %d", streak);
}
fclose(fp);
}
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){
const char* filename = str_filename.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(string str_name){
system("ans.exe");
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);
if(std_judge){
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";
}
}else{
string std_toname = samplename + temp + ".out";
const char *std_name2 = std_toname.c_str();
if(!findfile(std_name2, 0)){
cout << "未找到" << std_name2 << "!\n";
continue;
}
printsample(std_name2, stdname);
start = clock();
outcheck_ans = system("ans.exe");
end = clock();
elapsed_secs = static_cast<double>(end - start);
if(outcheck_ans == -1 || WIFEXITED(outcheck_ans) == false || 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(!ifcontinue) continue;
enter_deal("ans.out", ifblank, ifenter);
enter_deal("std.out", ifblank, ifenter);
int count_ans = 0;
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";
}
}
}
}
void start_judge(){
string tool = "\\data\\";
string name = "textpoint.txt";
string file_name = buf + tool + name;
getpoint(file_name);
if(findfile("ans.out")) system("del ans.out");
if(findfile("std.out")) system("del std.out");
if(findfile("ans.exe")) system("del ans.exe");
if(findfile("std.exe")) system("del std.exe");
if(findfile("test.in")) system("del test.in");
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("ans.cpp");
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);
}
}
bool initialize(){
bool back = 1;;
if(std_judge && !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;
}
}
}
}
#endif
评测机.cpp
//v1.0.3
#include"tools.h"
int main(){
system("title 水滴评测机");
color(7);
GetCurrentDirectory(1000, buf);
Clear_Qiuckedit();
while(1){
hide();
gotoxy(1, 1);
printf("1:评测 2:设置 3:刷新 4:打卡\n");
char choose = getch();
if(choose == '1'){
system("cls");
if(!initialize()){
printf("0:返回\n");
Mypause('0');
continue;
}
start_judge();
if(findfile("ans.out")) system("del ans.out");
if(findfile("std.out")) system("del std.out");
if(findfile("ans.exe")) system("del ans.exe");
if(findfile("std.exe")) system("del std.exe");
if(findfile("test.in")) system("del test.in");
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'){
while(1){
system("cls");
printf("0:返回\n1:与cpp比较");
if(std_judge){
printf("√\n");
}else{
printf("-\n");
}
char std_choose = getch();
if(std_choose == '1') std_judge = !std_judge;
else if(std_choose == '0'){
system("cls");
break;
}
}
}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();
}else if(choose == '4'){
bool ifbreak = 0;
system("cls");
daka();
printf("按任意键返回。\n");
while(1){
if(kbhit()){
ifbreak = 1;
system("cls");
break;
}
if(ifbreak) break;
}
}
}
return 0;
}
使用方法和v1.0.2相同,参考c++编写评测机(3)。
后续透露
下一个版本可以说是最重磅的了,因为自从下一个版本开始,我们就像软件的方向完善了,实用性也更高一个档次。
最后,请给个三连把~期待下一版哦!