Windows系统对拍程序,其中包含c++11用法,请使用c++11标准编译。此对拍程序会在发现错误时显示错误行号以及对应内容,方便比对。
此对拍程序自动使用g++对源代码进行编译。如果出现找不到g++的错误,请将g++所在目录添加至系统的环境变量列表中;
也可直接注释掉主函数前5行不用自动编译,并将编译好的pai_data.exe(生成数据)、pai_user.exe(用户程序)、pai_std.exe(标准解答程序)放至与本程序所在同目录下。
准备就绪后编译并运行本程序即可。
2019-04-10:添加了对标程的计时。
2019-04-18:修复当文件尾没有换行时会导致错误判断的问题。
1 #include <cerrno> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <ctime> 6 7 // 设置区 8 namespace Settings { 9 const int MAX_LEN = 20; // 发现错误时,显示错误行数据的最大长度 10 const int CASE_CNT = 200; // 对拍测试次数 11 const int BUFFER_SIZE = 1 << 10; // 每行的缓冲区大小 12 const char *const dataFile = "data.cpp"; // 随机生成数据的源代码文件名 13 const char *const userFile = "user.cpp"; // 需要测试的源代码文件名 14 const char *const stdFile = "std.cpp"; // 标准答案的源代码文件名 15 const char *const dataExeName = "pai_data.exe"; 16 const char *const userExeName = "pai_user.exe"; 17 const char *const stdExeName = "pai_std.exe"; 18 const char *const dataOutputName = "pai_data.txt"; 19 const char *const userOutputName = "pai_user.txt"; 20 const char *const stdOutputName = "pai_std.txt"; 21 } // namespace Settings 22 23 using namespace Settings; 24 using namespace std; 25 26 char cmd[BUFFER_SIZE], info[BUFFER_SIZE * 3]; 27 char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE]; 28 29 template <typename... T> 30 int run(const char *str, T... args) { 31 sprintf(cmd, str, args...); 32 return system(cmd); 33 } 34 35 bool fileCompare(const char *stdOutput, const char *userOutput) { 36 FILE *fp_std = fopen(stdOutput, "r"), *fp_user = fopen(userOutput, "r"); 37 if (fp_std == nullptr || fp_user == nullptr) { 38 sprintf(info, "Open file failed: %s\n", strerror(errno)); 39 return false; 40 } 41 bool flag = true; 42 for (int i = 1; !feof(fp_std) && !feof(fp_user); ++i) { 43 char *p1 = fgets(buf1, BUFFER_SIZE, fp_std); 44 char *p2 = fgets(buf2, BUFFER_SIZE, fp_user); 45 if (p1 == nullptr && p2 == nullptr) { 46 flag = true; 47 break; 48 } else { 49 int len1 = p1 ? strlen(p1) : -1, len2 = p2 ? strlen(p2) : -1; 50 if (p1 && p1[len1 - 1] == '\n') p1[len1 - 1] = 0, --len1; 51 if (p2 && p2[len2 - 1] == '\n') p2[len2 - 1] = 0, --len2; 52 if (p1 == nullptr || p2 == nullptr || len1 != len2 || 53 strcmp(p1, p2)) { 54 if (len1 > MAX_LEN) 55 sprintf(p1 + MAX_LEN, "... (%d characters omitted)", 56 len1 - MAX_LEN); 57 if (len2 > MAX_LEN) 58 sprintf(p2 + MAX_LEN, "... (%d characters omitted)", 59 len2 - MAX_LEN); 60 sprintf(info, 61 "Difference found in line %d:\n std: %s\n user: %s\n", 62 i, p1 ? p1 : "(EOF Detected)", 63 p2 ? p2 : "(EOF Detected)"); 64 flag = false; 65 break; 66 } 67 } 68 } 69 fclose(fp_std), fclose(fp_user); 70 return flag; 71 } 72 73 int main() { 74 int totaltimeCnt = 0; 75 printf("Compiling... "); 76 if (run("g++ %s -o %s", userFile, userExeName) || 77 run("g++ %s -o %s", stdFile, stdExeName) || 78 run("g++ %s -o %s", dataFile, dataExeName)) { 79 puts("Compile failed."); 80 printf("Press ENTER to exit.\n"); 81 getchar(); 82 return 0; 83 } 84 85 puts("Finished."); 86 clock_t stUser, edUser, stStd, edStd; 87 bool Accepted = true; 88 for (int i = 1, ret; i <= CASE_CNT; ++i) { 89 printf("Case %03d: ", i); 90 run("%s >%s", dataExeName, dataOutputName); 91 92 // run std solution 93 stStd = clock(); 94 ret = run("%s <%s >%s", stdExeName, dataOutputName, stdOutputName); 95 edStd = clock(); 96 if (ret) { 97 printf("Non Zero Exit Code: Std solution returned value %d\n", ret); 98 Accepted = false; 99 break; 100 } 101 102 // run user's solution 103 stUser = clock(); 104 ret = run("%s <%s >%s", userExeName, dataOutputName, userOutputName); 105 edUser = clock(); 106 if (ret) { 107 printf("Non Zero Exit Code: User's solution returned value %d\n", 108 ret); 109 Accepted = false; 110 break; 111 } 112 113 if (!fileCompare(stdOutputName, userOutputName)) { 114 printf("Wrong answer.\n------------------------------\n"); 115 printf("%s", info); 116 printf("------------------------------\n"); 117 Accepted = false; 118 break; 119 } 120 121 printf("Accepted. StdTime:%4d ms, UserTime:%4d ms\n", 122 int(edStd - stStd), int(edUser - stUser)); 123 totaltimeCnt += int(edUser - stUser); 124 } 125 if (Accepted) { 126 printf("\nUser's solution got accepted after %d tests.\n", CASE_CNT); 127 printf("Average time spent: %.2f ms.\n", 128 double(totaltimeCnt) / CASE_CNT); 129 } 130 printf("Press ENTER to exit.\n"); 131 getchar(); 132 return 0; 133 }