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

+14 -46
View File
@@ -1,50 +1,18 @@
import axios from "axios"
import { base64DecodeUtf8, base64EncodeUtf8 } from "./functions"
import type { Code, LANGUAGE } from "./types"
import type { RunnableLanguage, TrialRunRequest, TrialRunResponse } from "@oj2/contract"
import api from "./api"
import type { LANGUAGE } from "./types"
const http = axios.create({ baseURL: import.meta.env.PUBLIC_JUDGE0_URL })
// Judge0 的语言 id。Flowchart 和 SQL 不在其中 —— 前者根本不是可执行代码,
// 后者由本站自己的 SQL 沙箱判,都走不到 Judge0。
const JUDGE0_LANGUAGE_ID: Partial<Record<LANGUAGE, number>> = {
C: 50,
"C++": 54,
Java: 62,
Golang: 60,
JavaScript: 63,
Python: 71,
/**
* 试运行:走本站判题机(`POST /trial-runs`,见 apps/api/src/judge/trial.ts),不算提交。
* 和提交是同一台判题机、同一套编译命令,例子上跑出来的结果和提交一个口径。
*
* 原来走的是另一台 Judge0(C 是 GCC 9、参数也不同),2026-09 换掉了。
*/
export function trialRun(payload: TrialRunRequest) {
return api.post<TrialRunResponse>("trial-runs", payload)
}
export async function createTestSubmission(code: Code, input: string) {
const encodedCode = base64EncodeUtf8(code.value)
const id = JUDGE0_LANGUAGE_ID[code.language]
if (id === undefined) {
return { status: null, output: `${code.language} 不支持在线试运行` }
}
let compilerOptions = ""
if (id === 50) compilerOptions = "-lm" // 解决 GCC 的链接问题
const payload = {
source_code: encodedCode,
language_id: id,
stdin: base64EncodeUtf8(input),
redirect_stderr_to_stdout: true,
compiler_options: compilerOptions,
}
const response = await http.post("/submissions", payload, {
params: { base64_encoded: true, wait: true },
})
const data = response.data
const status: number | null = data.status?.id ?? null
const stdout = base64DecodeUtf8(data.stdout)
// 跑通了(3 = Accepted)就只要程序自己的输出,而且只去掉末尾的空白:
// - C 有警告(隐式声明 sqrt、用了 gets)时 Judge0 跑通了也带回 compile_output,拼进来
// 就成了「你的输出」的一部分,例子永远对不上;后台生成测试点时还会写进 .out
// - 开头的空格是输出的一部分(打印菱形、三角形),原来整体 trim() 会把它削掉,
// 对的代码被判成「只是空格不一样」
if (status === 3) return { status, output: stdout.trimEnd() }
// 没跑通:报错原文给人看,两段拼起来
return {
status,
output: [base64DecodeUtf8(data.compile_output), stdout].join("\n").trim(),
}
/** 判题机跑得了的语言。Flowchart、SQL 不是可执行代码 / 不走判题机,历史语言镜像里已经没有了 */
export function isRunnableLanguage(language: LANGUAGE): language is RunnableLanguage {
return language === "C" || language === "C++" || language === "Python"
}