quiz.json 与六种题型
quiz.json 是一道题的配置中枢:题型、标题、星级、提示、判题数据全在这一个文件里。它也是构建期查得最严的文件,配置不对,构建直接失败。这一篇把六个题型各自的必填项和容易写错的地方讲全,报错原文也附在最后,您对着排错就省得翻源码。
先看全六种题型
| type | 题卡标签 | 学员做什么 | 额外必填 |
|---|---|---|---|
judge-assert | 实现 · 函数式 | 在线写函数,提交判题 | tests 断言数组 |
judge-io | 实现 · 程序式 | 在线写完整程序,按输入输出判 | tests 输入输出对 |
fill | 口答 · 填写 | 填一段期望文本 | answerText |
choice | 口答 · 选择 | 从选项里勾出正确的 | options + answer |
find-bug | 找 bug · 开放思考 | 在代码里标出 bug 行 | bugLines |
reveal | 思考 · 展开 | 先想,再展开看答案 | 无 |
咱们选型的直觉:judge-assert 适合"实现一个函数",judge-io 适合"写一个完整程序",两个口答类适合考概念辨析,find-bug 适合拿一段真实易错代码考眼力,reveal 适合开放讨论、没有唯一答案的题。每道题的 src 目录、判题行为和示范配置,code/volumn_codes/weekly-problems/examples/ 下一种题型一个目录,写之前翻同题型那个照着对,是最不容易错的路子。
通用字段
type 从上表六选一,写错构建期第一个报的就是它。title 非空,显示在题卡上,建议短,六字上下,长标题在卡片上会被截。stars 填 1 到 3 表示难度,这里有个值得记住的行为:stars 不是数字、或者超出 1 到 3 时,不报错,静默按 3 处理——您以为标了个简单题,学员看到的是三星。填完扫一眼。
hints 是字符串数组,学员点一下解锁一条,支持行内 markdown。写提示的分寸:第一条给方向,最后一条可以给到接近答案的强提示,但别直接放答案。reveal 之外的题型都建议给,您给一两条就好。
judge-assert:断言怎么写
tests 是字符串数组,咱们每条写一行"表达式 == 期望值":
"tests": [
"count_coins(0) == 1",
"count_coins(100) == 242"
]它藏着一条隐性契约,咱们拆开看。其一,每行按最后一个 == 切分成"调用"和"期望值",从右往左找切分点,所以表达式自身含 == 也不会切错。空行会被忽略,但数组至少要有一条,不然报 tests 至少要有一条断言。
其二,表达式里调用的函数,签名必须和 starter.cpp 里给的骨架完全一致。判题器把学员的代码和生成的调用代码拼在一起编译,函数名或参数对不上,编译期就炸,学员看到的是编译错误而不是判题结果,体验很差。您写完 tests,拿 starter 的函数名逐条核对一遍。
judge-io:输入输出对怎么写
tests 换成对象数组,咱们每组这么写:in 是标准输入的完整内容,out 是期望的标准输出,都必须是字符串:
"tests": [
{ "in": "2 3", "out": "5" },
{ "in": "-7 4", "out": "-3" }
]比对时忽略行尾空白与末尾空行,所以期望输出末尾要不要换行都算对,这点您大可以放心。in 里要模拟多行输入就直接在字符串里带 \n。同样至少一组,in 或 out 忘了加引号(写成数字)会报 tests 第 N 组的 in/out 都必须是字符串。
三个口答类和找 bug
fill 填 answerText,学员提交的文本和它比对,期望值要写得没有歧义——多个词序不同的同义表述没法都算对,咱们出题时把答案的形态在题面里框死,比如"输出两个数,空格分隔"。
choice 填 options(至少两项)和 answer。answer 是 1-based 行号数组, [1, 3] 表示第一项和第三项正确,支持多选。行号超出 options 数量会报错,报错消息里会带上当前共几项,方便咱们定位。
find-bug 填 bugLines,1-based 行号数组,数的是 code.cpp 的行。咱们写这题的顺序,建议是写好带 bug 的 code.cpp,再回头数行号,改了代码必须重数,行号对不上学员就永远标不对。
reveal 没有额外必填字段,答案就放在题解 solution/*/answer.md 里,学员点展开之前,题面就是咱们给的全部引导。
报错对照表
构建期和页面运行时用的是同一套校验,咱们把报错原文列在下面,您在构建日志或题卡错误提示里直接搜左列就能定位:
| 报错原文 | 修法 |
|---|---|
type 必须是 judge-assert / judge-io / fill / choice / find-bug / reveal 之一,现在的是:… | type 字段拼错了,对照上表六选一 |
title 必须是非空字符串 | title 忘了写或写成了空串 |
【题名】判题类必须有 tests 数组 | judge 类题型缺 tests 或它不是数组 |
tests 断言语法应为"表达式 == 期望值",这行不合法:… | 那行断言里 == 位置不对:开头就是 ==、或结尾没有期望值 |
tests 至少要有一条断言 / tests 至少要有一组 {"in": …, "out": …} | tests 是空数组 |
tests 第 N 组的 in/out 都必须是字符串 | judge-io 的某组忘了给 in 或 out,或值不是字符串 |
【题名】choice 必须有 options(至少两项) | options 缺失或少于两项 |
【题名】answer 应是 options 的 1-based 行号数组,当前 options 共 N 项 | answer 缺失、不是 1 到 N 之间的整数 |
【题名】fill 必须有 answerText(期望文本) | fill 缺期望文本 |
【题名】find-bug 必须有 bugLines(1-based 行号数组,行数由 code.cpp 决定) | bugLines 缺失或不是正整数数组 |
填完怎么自查
您最快的自查是 pnpm dev 起服务刷新页面:配置能被解析,题卡正常渲染;配置有问题,坏卡提示或页面报错立刻可见,改动即时生效不用重启。要跑完整构建校验就用 pnpm build,manifest 生成阶段会把每个 quiz.json 都过一遍上面的校验,一个都躲不掉。提交前的完整自检清单在第五篇。