feat(题目): 「运行例子」「自己输入」改用和提交同一台判题机——例子上跑出什么样,提交在这几个例子上就是什么样
Deploy / deploy (push) Canceled after 0s

原来试运行走另一台 Judge0:C 是 GCC 9、编译参数也不一样,Python 的语法错误回来的是运行错误,
没有题目的时间内存限制和代码模板,例子上的结果常和提交对不上。现在走本站判题机
(POST /trial-runs),同一套编译命令、这道题的限制和模板,对不对也由判题机比。

- 不落库、不算提交、不进判题队列:api 进程里自己排队,全站同时 TRIAL_CONCURRENCY 批
  (服务器 2、机房 4),每人最多两批,排满或等超过 30 秒就请学生过一会儿再点
- 死循环不停打印时判题机回包会很大,超过 16MB 就掐断,告诉学生输出太多、停不下来
- Python 语法错误用和提交一样的说明:第几行、中文标点标红、一键换成英文
- 运行时错误和提交用同一个解析,说清楚第几行、为什么(下标越界、int() 转换失败、段错误……);
  比赛里照旧只给按结果码的那一句
- 语法没过、服务没跑成时,标题不再说「N 个例子没对上」
- 后台「生成测试点」一并迁过来,编译警告不会再写进 .out;Judge0 的地址和调用全部删掉

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-09-29 08:09:44 +08:00
1 parent 8834536135
commit eb32676de4
27 files changed
+691 -169

No files matched your search

+59 -1
View File
@@ -2,7 +2,7 @@ import { z } from "zod"
import { paginatedSchema } from "./common"
import { judgeStatusSchema, type JudgeStatus } from "./judge-status"
import { problemLanguageSchema } from "./language"
import { problemLanguageSchema, runnableLanguageSchema } from "./language"
/**
* 判题机原始输出(`submission.info` 的 JSONB 原文)。**只是类型,不作运行时校验。**
@@ -454,6 +454,63 @@ export const formatCodeRequestSchema = z.object({
export const formatCodeResponseSchema = z.object({ code: z.string() })
/** 试运行一次最多几组。学生那边只有「运行例子」(一般两三个)和「自己输入」(一个) */
export const TRIAL_MAX_CASES = 10
/** 后台「生成测试点」一次跑的组数上限,只有管理员能用到 */
export const TRIAL_ADMIN_MAX_CASES = 50
/**
* 试运行:「运行例子」「自己输入」、后台「生成测试点」。走本站判题机,不落库、不算提交。
*
* - 带 `problemId`:按这道题的时间 / 内存限制和代码模板跑,和提交一个口径;
* - 不带:只有管理员能这么调(后台生成测试点时题目可能还没存)。
*
* `output` 是这组的正确输出,给了就由判题机比对(和提交一样去掉末尾空白再比),
* 结果是通过 / 答案错误;不给(「自己输入」、生成测试点)就只看有没有跑出错。
*/
export const trialRunRequestSchema = z.object({
problemId: z.number().int().positive().optional(),
contestId: z.number().int().positive().optional(),
language: runnableLanguageSchema,
code: z
.string()
.min(1)
.max(1024 * 1024),
cases: z
.array(
z.object({
input: z.string().max(1024 * 1024),
output: z
.string()
.max(1024 * 1024)
.optional(),
}),
)
.min(1)
.max(TRIAL_ADMIN_MAX_CASES),
})
/**
* - `done`:每组一条,顺序和请求里的 `cases` 一致。`result` 是判题机那套码;
* 没给正确输出的组,跑完没出错就是通过。`output` 里 stdout 和 stderr 是混在一起的
* (判题机把两者写进同一个文件),Python 的报错原文就在这里。运行时错误的组另带
* `runtimeError`:和提交的 `statistic_info.runtime_error` 同一个解析(第几行、什么异常),
* 解析不出来时没有这个字段。
* - `compile-error`:编译没过(Python 是语法错误),一组都没跑。
* - `too-much-output`:程序输出多到判题机回包超过上限,多半是死循环在不停打印。
*/
export type TrialRunResponse =
| {
status: "done"
cases: {
result: JudgeStatus
output: string
runtimeError?: NonNullable<StatisticInfo["runtime_error"]>
}[]
}
| { status: "compile-error"; message: string }
| { status: "too-much-output" }
export type StatisticInfo = z.infer<typeof statisticInfoSchema>
export type SubmissionTrace = z.infer<typeof submissionTraceSchema>
export type CreateSubmissionRequest = z.infer<typeof createSubmissionRequestSchema>
@@ -473,3 +530,4 @@ export type CreateSubmissionResponse = z.infer<typeof createSubmissionResponseSc
export type FormatCodeResponse = z.infer<typeof formatCodeResponseSchema>
export type FormatCodeRequest = z.infer<typeof formatCodeRequestSchema>
export type TrialRunRequest = z.infer<typeof trialRunRequestSchema>