# CES-Alpha 題目 JSON 檔案格式 — 版本 1.0

本文件說明存放 CES-Alpha 自動評分題目（一題或多題）的 JSON 檔案格式。無論是手動撰寫、用程式產生，或交給 AI 代理產生這種檔案，都請依照本文件。

- 本文件的網頁版：<https://document.ces-alpha.jp/manual/auto_grade_question_format.html>
- 本文件的 Markdown 版：<https://document.ces-alpha.jp/manual/auto_grade_question_format.zh-Hant.md>
- 範例檔案：第 9 節

## 1. 檔案的使用場合

在教師的題目編輯頁面中：

- **下載**：頁面底部的「題目 JSON 檔案」區塊（「下載 JSON 檔案」）可將題目下載為本格式的檔案。
- **載入一個檔案**：「載入題目」→「從本機 JSON 檔案」會把一道題目填入表單。在按下儲存按鈕之前，不會儲存任何內容。
- **載入多道題目**：如果選擇多個檔案、一個 `.zip` 檔案，或一個包含題目清單的檔案，其中所有題目都會以新題目的形式加入頁面上所選的群組。

系統有兩個網站，一個檔案只適用於其中一個：

| 網站 | `site` | 題目 |
|---|---|---|
| 程式網站（`code.ces-alpha.org` 及其子網站） | `"code"` | 程式設計題，以及簡短的文字作答題 |
| 數學網站（`math.ces-alpha.org`） | `"math"` | 以符號運算評分的數學題 |

## 2. 檔案基本規則

- 編碼：**UTF-8**。格式：JSON（[RFC 8259](https://www.rfc-editor.org/rfc/rfc8259)）。副檔名：`.json`。
- 一道題目是一個 JSON **物件**（object）。若有多道題目，可使用下列任一方式：
    - 在一個檔案中放入由題目物件組成的 JSON **陣列**（array），
    - 同時選擇多個 `.json` 檔案，
    - 由 `.json` 檔案組成的 `.zip` 檔案（內部可以有資料夾；以 `.` 開頭的檔案及 `__MACOSX` 資料夾會被略過）。
- 所有文字值都是 JSON 字串。換行寫成 `\n`。反斜線寫成 `\\`，因此 LaTeX 的 `\frac{1}{2}` 在檔案中寫成 `"\\frac{1}{2}"`。
- 本文件未列出的鍵（key）會被忽略。
- 空字串 `""` 與沒有該鍵的意思相同。

## 3. 標頭（必要）

格式 1.0 的每個題目物件都以下列兩個鍵開頭：

| 鍵 | 型別 | 值 |
|---|---|---|
| `ces_question_format` | 字串 | `"1.0"`：格式版本，形式為 `"major.minor"`（主版本.次版本）。 |
| `site` | 字串 | `"code"` 或 `"math"`：題目所屬的網站。 |

讀取檔案時的規則：

- **主版本相同，次版本不限**（`"1.0"`、`"1.2"`、…）：檔案會被讀取；較新的次版本所新增的鍵會被忽略。
- **主版本不同**（`"2.0"`、…）：檔案會被拒絕。
- **`site` 與目前頁面的網站不同**：檔案會被拒絕。數學題無法在程式網站載入，反之亦然。
- **沒有 `ces_question_format` 鍵**：視為 1.0 之前的檔案（見第 8 節），依照以往的方式讀取。

## 4. 兩個網站共用的欄位

| 鍵 | 型別 | 必要 | 預設值 | 意義 |
|---|---|---|---|---|
| `question_type` | 字串 | 是 | — | 題目種類。可用的值：見第 5 節（數學）及第 6 節（程式）。 |
| `question_title` | 字串 | 是\* | `""` | 顯示在題目清單中的標題。 |
| `question_content` | 字串 | 是\* | `""` | 顯示給學生的題目內容（第 7 節）。 |
| `score` | 整數 | 否 | `1` | 題目的配分（表單中的「分數設定」）。 |
| `evaluation_method` | 整數 | 否 | 數學 `0`，程式 `1` | 作答的評分方式。可用的值：見第 5 節及第 6 節。 |
| `question_hint` | 字串 | 否 | `""` | 學生可以開啟查看的「提示」。 |
| `q_solution_explanation` | 字串 | 否 | `""` | 「解答說明」，與正確答案一起顯示給學生。 |
| `note` | 字串 | 否 | `""` | 給教師看的「備註」。學生永遠看不到。 |

\* `question_title` 與 `question_content` 至少要設定其中一個。建議兩者都設定。

## 5. 數學網站（`"site": "math"`）

### 5.1 題目種類

| `question_type` | 學生要… | 使用的欄位 |
|---|---|---|
| `"text"`（「在文字方塊中作答」） | 輸入一個或多個算式 | `question_answer`、`question_variable`、`answer_const` |
| `"select"`（「選擇題」） | 從清單中選擇一項 | `answer_candidate`、`question_answer` |
| `"matrix"`（「以矩陣作答」） | 輸入向量或矩陣 | `question_answer`、`question_variable` |

### 5.2 欄位

| 鍵 | 型別 | 必要 | 意義 |
|---|---|---|---|
| `question_variable` | 字串 | 否 | 「參數」：隨機值，讓每位學生的題目都不同（5.3）。 |
| `question_answer` | 字串 | 是 | 正確答案。寫法依 `question_type` 而定（5.4）。 |
| `answer_candidate` | 字串陣列 | 僅 `select` | 選項，依顯示順序排列。 |
| `answer_const` | 布林值 | 否（僅 `text`） | `true`：與 `question_answer` 相差一個常數的答案也視為正確（不定積分）。對應表單中的「允許相差一個常數（例如不定積分）」。預設為 `false`。 |

### 5.3 參數（`question_variable`）

每行一個參數（行與行之間以 `\n` 分隔），寫成 `名稱=值`：

```text
a=1,2,5
b_1=-3,...,-1,1,...,5
alpha=1,...,5
beta=a+b_1
```

- 以逗號分隔的數字清單：為每位學生隨機抽取其中一個值。`m,...,n` 代表從 `m` 到 `n` 的所有整數。
- 算式（含有字母，例如 `beta=a+b_1`）：由其他參數計算得出。
- 名稱：一個字母（`a`、`b`、`x`、…）或希臘字母名稱（`alpha`、`beta`、…；不可使用 `lambda`、`pi` 或 `e`），可加上一位數的下標（`b_1`、`beta_9`）。
- `E`（或 `e`）、`pi` 與 `I`（虛數單位）為數學常數。
- 在 `question_content` 中，寫在 `$...$` 裡的參數會被替換成它的值。在那裡希臘字母要加反斜線（`$\\alpha$`）；在 `question_variable` 中則不加（`alpha`）。

### 5.4 答案（`question_answer`）

**`text`**：每個答案方塊一行，寫成 `名稱=算式`：

```text
A=2*a*x+b
B=2*a+b
```

- 名稱（`A`、`B`）是答案方塊的標籤。在題目內容中用 `\ans{A}` 標示方塊的位置（第 7 節）。
- 算式的寫法如同計算機，採用 SymPy 語法：乘法用 `*`，次方用 `^` 或 `**`，以及 `sqrt(x)`、`sin(x)`、`exp(x)`、`log(x)`、`pi`、`E`、`I`、`oo`（無限大）。可以使用參數。
- 一個方塊有多個正確答案時：以 `;` 分隔（`x=2;-2`）。
- 只對某一行指定評分方式：在該行末尾加上 `# mode:1`、`# mode:2` 或 `# mode:3`（`A=x+1 # mode:3`）。數字對應 5.5 的編號。

**`matrix`**：每行一列，元素之間以逗號分隔。行向量（column vector）則每行一個元素。

```text
a+2, 2
1, 1
```

**`select`**：正確選項的文字，必須與 `answer_candidate` 中的寫法完全相同。

### 5.5 評分方式（`evaluation_method`）

| 值 | 表單中的名稱 | 判定為正確的條件 |
|---|---|---|
| `0` | [mode:1] 等價性判定 (Equivalence check) | 數學意義相同：`(x-1)^2` = `x^2-2x+1`。 |
| `1` | [mode:2] 形式判定 (Formal check) | 形式相同（不計順序）：`(x-3)(x-1)` = `(x-1)(x-3)`，但 `3x` ≠ `x+2x`。 |
| `2` | [mode:3] 嚴格判定 (Strict check) | 字串完全相同：`2x` ≠ `2*x`。 |

`select` 不使用此設定，一律比對所選的文字。

## 6. 程式網站（`"site": "code"`）

### 6.1 題目種類

| `question_type` | 學生要… | 評分方式 |
|---|---|---|
| `"code"`（「撰寫程式」） | 撰寫程式 | 以相同輸入執行 `sample_code` 與學生的程式碼，並比對結果 |
| `"text"`（「在文字方塊中作答」） | 輸入簡短答案 | 與 `question_answer` 比對 |

### 6.2 `code` 題目的欄位

| 鍵 | 型別 | 必要 | 意義 |
|---|---|---|---|
| `code_language` | 字串 | 是 | `"Python"`（Python 3）、`"R"` 或 `"MATLAB"`（以 Octave 執行）。預設為 `"Python"`。 |
| `answer_template` | 字串 | 否 | 學生編輯器中的初始程式碼。 |
| `sample_code` | 字串 | 是 | 參考解答。在評分伺服器上執行；學生看不到。 |
| `object_for_grade` | 字串 | 是 | 比對的對象（6.3）。 |
| `input_argument` | 字串 | 否 | 函式呼叫的輸入，每行一個測試案例（6.3）。 |
| `evaluation_method` | 整數 | 否 | `1`：執行程式並比對結果（「檢查程式執行結果」，預設值）。 |

### 6.3 比對的對象（`object_for_grade`、`input_argument`）

有兩種方式。

**函式。** `object_for_grade` 是一個呼叫，例如 `add(a, b)`。`input_argument` 的每一行是一個測試案例：以逗號分隔的各個值，依序代入引數的位置。對每個測試案例，分別在 `sample_code` 與學生的程式碼中呼叫該函式，兩者的回傳值必須一致。

```json
"object_for_grade": "add(a, b)",
"input_argument": "1, 2\n-3, 5\n0.5, 0.25"
```

- 值可以是清單或巢狀呼叫：`[1,2], 5` 與 `c(1,2,3), 1000` 各自是兩個值。
- 也可以使用預留位置 `var1`、`var2`、…（只有一個值時用 `var`），在算式中也能使用：`solve(var1, np.array([var2, var3]))`。
- 若沒有 `input_argument`，則不帶引數呼叫函式一次（`f()`）。

**變數。** `object_for_grade` 是以逗號分隔的變數名稱清單，例如 `m, mx`。兩個程式都會被執行，執行結束時這些變數的值必須一致。不使用 `input_argument`。

### 6.4 程式網站上的 `text` 題目

`question_answer` 每個答案方塊一行，寫成 `名稱=值`，與 5.4 相同。多個正確答案以 `;` 分隔（`PrimeNumber=3;13;23`）。若答案本身含有分號，寫成 `\;`（在 JSON 檔案中為 `"\\;"`）。

## 7. 題目內容、提示與解答說明的文字

- `question_content`、`question_hint` 與 `q_solution_explanation` 採用 **Markdown**。空一行即開始新段落。程式碼可用反引號（backtick）標示。
- 在數學網站上可以使用 LaTeX 公式：行內用 `$...$`，獨立區塊用 `$$...$$`。
- `\ans{name}` 會在文字中、答案 `name` 的位置畫出一個答案方塊。

## 8. 1.0 之前的檔案

沒有 `ces_question_format` 的檔案依照以往的方式讀取。僅為了相容性，在這類檔案中也接受下列其他名稱。新檔案請勿使用。

| 1.0 的鍵 | 同樣接受的其他名稱 |
|---|---|
| `question_type` | `exercise_type`、`q_type` |
| `question_title` | `title` |
| `question_content` | `q_content` |
| `question_variable` | `q_variable` |
| `question_answer` | `answer` |
| `answer_candidate` | `answer_choices` |
| `question_hint` | `hint` |
| `q_solution_explanation` | `solution_explanation` |
| `answer_template` | `code_template` |
| `object_for_grade` | `code_output` |

在 1.0 之前的檔案中，若缺少題目種類，或其值不是該網站的種類，系統會自動推測：在程式網站上，含有 `answer_template` 或 `object_for_grade` 的題目視為 `code`；否則視為 `text`。

## 9. 範例

| 檔案 | 網站 | 種類 |
|---|---|---|
| [code_python_function.json](https://document.ces-alpha.jp/manual/question_format_examples/code_python_function.json) | code | `code`，含測試案例的函式 |
| [code_python_variables.json](https://document.ces-alpha.jp/manual/question_format_examples/code_python_variables.json) | code | `code`，變數 |
| [code_text.json](https://document.ces-alpha.jp/manual/question_format_examples/code_text.json) | code | `text` |
| [math_text.json](https://document.ces-alpha.jp/manual/question_format_examples/math_text.json) | math | `text`，含參數，兩個答案 |
| [math_text_integral.json](https://document.ces-alpha.jp/manual/question_format_examples/math_text_integral.json) | math | `text`，含 `answer_const` |
| [math_select.json](https://document.ces-alpha.jp/manual/question_format_examples/math_select.json) | math | `select` |
| [math_matrix.json](https://document.ces-alpha.jp/manual/question_format_examples/math_matrix.json) | math | `matrix` |
| [math_several_questions.json](https://document.ces-alpha.jp/manual/question_format_examples/math_several_questions.json) | math | 包含兩道題目的陣列 |

程式設計題範例：

```json
{
  "ces_question_format": "1.0",
  "site": "code",
  "question_type": "code",
  "question_title": "Sum of two numbers",
  "question_content": "Write a function `add(a, b)` that returns the sum of `a` and `b`.",
  "score": 1,
  "evaluation_method": 1,
  "code_language": "Python",
  "answer_template": "def add(a, b):\n    # Write your code here.\n    return None\n",
  "sample_code": "def add(a, b):\n    return a + b\n",
  "object_for_grade": "add(a, b)",
  "input_argument": "1, 2\n-3, 5\n0.5, 0.25",
  "question_hint": "Use the + operator.",
  "q_solution_explanation": "Return `a + b`.",
  "note": "Week 1"
}
```

數學題範例：

```json
{
  "ces_question_format": "1.0",
  "site": "math",
  "question_type": "text",
  "question_title": "Derivative of a polynomial",
  "question_content": "Let $f(x) = a x^2 + b x$. Find $f'(x)$ and $f'(1)$.\n\n$f'(x) = $ \\ans{A}, $f'(1) = $ \\ans{B}",
  "question_variable": "a=1,...,5\nb=-3,-2,-1,1,2,3",
  "question_answer": "A=2*a*x+b\nB=2*a+b",
  "evaluation_method": 0,
  "score": 2,
  "question_hint": "$(x^n)' = n x^{n-1}$",
  "q_solution_explanation": "$f'(x) = 2ax + b$, so $f'(1) = 2a + b$."
}
```

## 10. 給 AI 代理的指示

請將本節（或整份文件）提供給負責撰寫題目檔案的 AI 代理。

```text
你要依照「CES-Alpha 題目 JSON 檔案格式 1.0」撰寫 CES-Alpha 的題目檔案。
- 只輸出有效的 JSON，使用 UTF-8，不加註解，前後不加任何文字。
- 每道題目是一個物件，開頭為 "ces_question_format": "1.0" 以及 "site": "code" 或 "math"。
- 若有多道題目，輸出由這些物件組成的 JSON 陣列。
- 只使用本格式定義的鍵。絕對不要使用第 8 節的舊名稱。
- 一律設定 question_type、question_title、question_content 與 question_answer
  （程式設計的 "code" 題目則改為設定 code_language、sample_code 與 object_for_grade，而非 question_answer）。
- 數學網站：question_type 為 "text"、"select" 或 "matrix"；算式使用 SymPy 語法（2*x、x^2、sqrt(x)、pi、E）。
  "text" 的答案每個答案方塊一行 "name=expression"；在題目內容中以 \ans{name} 標示每個方塊。
  "select" 的答案必須與 answer_candidate 中的某一項完全相同。
- 程式網站：question_type 為 "code" 或 "text"；code_language 為 "Python"、"R" 或 "MATLAB"。
  sample_code 必須能無錯誤地執行，並定義 object_for_grade 所指名的對象。
  若比對函式，請在 input_argument 中提供多個測試案例，每行一個。
- JSON 字串內的跳脫：換行寫成 \n，反斜線寫成 \\（LaTeX 的 \frac 寫成 \\frac），雙引號寫成 \"。
- 寫出答案之前，先確認答案正確。
```

## 11. 變更紀錄

| 版本 | 日期 | 變更內容 |
|---|---|---|
| 1.0 | 2026-10 | 第一版：標頭 `ces_question_format` 與 `site`；`answer_const`；第 8 節的舊名稱僅為相容性而保留。 |
