John Doe
postWin-Cpp-Judger:一个轻量级C++代码测评工具

postWin-Cpp-Judger:一个轻量级C++代码测评工具

Win-Cpp-Judger:一个轻量级C++代码测评工具

简介

Win-Cpp-Judger 是一个基于Windowsx64平台的简易 (简陋)的C++代码测评工具 (其实就是一个 cpp ),主要用于批量测试多个C++程序在不同测试数据下的表现。它能够自动完成编译、运行、输出对比的全过程,并生成清晰的测评报告。

或许可以赏我一个 Star ?

(在此更推荐强大的你谷

特点

高情商 低情商
自动化测评 一键完成编译、运行、对比全流程 unOnline Judge
批量处理 支持多个代码文件和测试点的连续测试 for 循环
详细报告 支持多个代码文件和测试点的连续测试 cout
简单配置 最小化的设置要求,开箱即用 只有 140 行的代码

环境要求

其实各位 OIer 都有罢

系统配置

  • 操作系统:Windows 10 64位(不确保其他系统的兼容性)
  • 编译器:GCC/G++(推荐MinGW或TDM-GCC)
  • 磁盘空间:至少100MB可用空间

编译器安装

  1. 下载MinGW-w64或TDM-GCC
  2. 安装时选择添加至PATH环境变量
  3. 命令行输入 g++ --version以确保安装妥当

项目结构

1
2
3
4
5
6
7
8
9
10
项目根目录/
├── judge.cpp(exe) # 测评代码(程序)
├── textpoint/ # 测试数据目录
│ ├── 1.in # 测试点1输入
│ ├── 1.out # 测试点1预期输出
│ ├── 2.in # 测试点2输入
│ └── 2.out # 测试点2预期输出
└── cpps/ # 待测评代码目录
├── 1.cpp # 代码文件1
└── 2.cpp # 代码文件2

代码

建议看完后去看看后面的核心代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <bits/stdc++.h>
#include <Windows.h>
#include <io.h>
#include <direct.h>
using namespace std;
const string TESTPOINT_DIR = "textpoint";
const string CPP_DIR = "cpps";
const string TEMP_EXE = "temp_program.exe";

// 编译C++程序
bool compileProgram(const string& cppFile) {
string command = "g++ -std=c++11 -O2 -o " + TEMP_EXE + " " + cppFile;
int result = system(command.c_str());
return result == 0;
}

// 运行程序并获取输出
string runProgram(const string& inputFile) {
string command = TEMP_EXE + " < " + inputFile + " > temp_output.txt";
system(command.c_str());

ifstream outputFile("temp_output.txt");
string output((istreambuf_iterator<char>(outputFile)),
istreambuf_iterator<char>());
outputFile.close();

// 去除末尾的换行和空格
while (!output.empty() && (output.back() == '\n' || output.back() == '\r' || output.back() == ' ')) {
output.pop_back();
}

return output;
}

// 读取文件内容
string readFile(const string& filename) {
ifstream file(filename);
if (!file.is_open()) {
return "";
}
string content((istreambuf_iterator<char>(file)),
istreambuf_iterator<char>());
file.close();

// 去除末尾的换行和空格
while (!content.empty() && (content.back() == '\n' || content.back() == '\r' || content.back() == ' ')) {
content.pop_back();
}

return content;
}

// 检查目录是否存在,不存在则创建
void checkAndCreateDir(const string& dirName) {
if (_access(dirName.c_str(), 0) == -1) {
_mkdir(dirName.c_str());
}
}

int main() {
int n, m;
cout << "请输入需测试代码数和测试点数: ";
cin >> n >> m;

// 检查并创建必要的目录
checkAndCreateDir(TESTPOINT_DIR);
checkAndCreateDir(CPP_DIR);

for (int i = 1; i <= n; i++) {
string cppFile = CPP_DIR + "/" + to_string(i) + ".cpp";

// 检查cpp文件是否存在
if (_access(cppFile.c_str(), 0) == -1) {
cout << "代码文件 " << cppFile << " 不存在,跳过测试" << endl;
continue;
}

// 编译程序
cout << "正在编译 " << cppFile << "..." << endl;
if (!compileProgram(cppFile)) {
cout << "编译失败: " << cppFile << endl;
continue;
}

vector<int> passedTests;
vector<int> failedTests;
int score = 0;

for (int j = 1; j <= m; j++) {
string inputFile = TESTPOINT_DIR + "/" + to_string(j) + ".in";
string expectedOutputFile = TESTPOINT_DIR + "/" + to_string(j) + ".out";

// 检查测试文件是否存在
if (_access(inputFile.c_str(), 0) == -1 ||
_access(expectedOutputFile.c_str(), 0) == -1) {
cout << "测试点 " << j << " 的文件不存在,跳过" << endl;
continue;
}

// 运行程序并获取输出
string actualOutput = runProgram(inputFile);
string expectedOutput = readFile(expectedOutputFile);

// 比较输出
if (actualOutput == expectedOutput) {
passedTests.push_back(j);
score += 10;
} else {
failedTests.push_back(j);
}
}

// 输出结果
cout << "\n目前测试代码名: " << cppFile << endl;

cout << "通过测试点: ";
if (passedTests.empty()) {
cout << "无";
} else {
for (int test : passedTests) {
cout << test << " ";
}
}
cout << endl;

cout << "未通过测试点: ";
if (failedTests.empty()) {
cout << "无";
} else {
for (int test : failedTests) {
cout << test << " ";
}
}
cout << endl;

cout << "得分: " << score << "/" << m * 10 << "\n\n" << endl;

// 清理临时文件
remove(TEMP_EXE.c_str());
remove("temp_output.txt");
}

return 0;
}

核心代码解析

编译模块

1
2
3
4
5
bool compileProgram(const string& cppFile) {
string command = "g++ -std=c++11 -O2 -o " + TEMP_EXE + " " + cppFile;
int result = system(command.c_str());
return result == 0;
}

使用-O2优化等级确保运行效率,-std=c++11保证代码规范。

执行模块

1
2
3
4
5
string runProgram(const string& inputFile) {
string command = TEMP_EXE + " < " + inputFile + " > temp_output.txt";
system(command.c_str());
// 读取并处理输出文件
}

通过重定向实现输入输出,确保测试环境一致性。

结果对比

1
2
3
4
5
6
if (actualOutput == expectedOutput) {
passedTests.push_back(j);
score += 10;
} else {
failedTests.push_back(j);
}

严格对比实际输出和预期输出。

使用教程

第一步:准备测试数据

textpoint目录下放置测试点文件,命名规则为:

  • 1.in, 1.out
  • 2.in, 2.out
  • …(数字从1开始连续编号)

第二步:放置待测代码

cpps目录下放置代码文件:

  • 1.cpp
  • 2.cpp
  • …(数字从1开始连续编号)

第三步:运行测评

1
2
# 通过命令行运行
judge.exe

或直接按F11

第四步:输入参数

1
请输入需测试代码数和测试点数: 2 3

表示测试2个代码文件,使用3个测试点

测评报告示例

1
2
3
4
5
6
7
8
9
10
11
12
13
正在编译 cpps/1.cpp...
正在编译 cpps/2.cpp...

目前测试代码名: cpps/1.cpp
通过测试点: 1 2 3
未通过测试点: 无
得分: 30/30


目前测试代码名: cpps/2.cpp
通过测试点: 1 3
未通过测试点: 2
得分: 20/30

细节

文件处理

1
2
3
4
5
void checkAndCreateDir(const string& dirName) {
if (_access(dirName.c_str(), 0) == -1) {
_mkdir(dirName.c_str());
}
}

自动检查并创建所需目录,避免因目录缺失导致的运行错误。

输出标准化

1
2
3
4
while (!output.empty() && 
(output.back() == '\n' || output.back() == '\r' || output.back() == ' ')) {
output.pop_back();
}

去除末尾空白字符,确保对比的准确性 (效仿某些测评机)

常见问题排查

Q1: 编译失败

现象:显示”编译失败”

解决

  1. 检查G++是否正确安装
  2. 确认代码文件语法正确

Q2: 测试点找不到

现象:显示”测试点X的文件不存在”

解决

  1. 检查文件命名是否符合规则
  2. 确认文件放置在正确目录

Q3: 输出对比错误

现象:实际输出与预期输出不一致

解决

  1. 检查文件编码(推荐UTF-8
  2. 统一换行符格式(推荐LF

扩展

你以为我会帮你拓展? (还真能)

但由于大家各自需要,不在源码中统一添加。各位大佬可以试着加些拓展,下为本蒟蒻示例。

添加时间限制

1
2
3
4
5
// 可使用Windows API添加超时检测
DWORD waitResult = WaitForSingleObject(pi.hProcess, timeout);
if (waitResult == WAIT_TIMEOUT) {
TerminateProcess(pi.hProcess, 1);
}

总结

Win-Cpp-Judger虽然功能简单 (简陋) ,但完整实现了自动化测评的基本需求。

但实质上对于大佬们而言只是一个简陋的小玩具,但是对于编程竞赛训练和算法学习来说,这是一个简单实用的工具。希望它能够帮助大家提高代码测试的效率!

(再次在此更推荐强大的你谷


相关资源

本文采用CC BY-NC-SA 4.0协议授权,转载请注明出处

Author:John Doe
Link:http://example.com/2025/09/27/postWin-Cpp-Judger:一个轻量级C-代码测评工具/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可