rfc_002.md 4.9 KB
Newer Older
M
Mars Liu 已提交
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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
# 习题和相关工具


技能树习题使用 markdown 定义。工具脚本会根据习题的结构生成对应的元信息。

## 习题的格式

习题是一个 markdown 文本,当前仅支持单选题,习题文本需要描述题干、习题答案、选项。对于设计为生成 notebook 的习题,还可以携带用于填充 
notebook 的模板或 aop 章节。

### 题干

一个典型的习题结构如下:

````markdown
# Hello World

以下 `Hello World` 程序中,能够正确输出内容的是:

## 答案

```java

public class App {
    public static void main(String[] args){
        System.out.println("Hello World");
    }
}
```

## 选项

### A

```java
public class App {
    public int main(){
        System.out.printf("Hello World");
        return 0;
    }
}
```

### B

```java
public class App {
    public static void main(String[] args){
        println("Hello World");
    }
}
```

### C

```java
import stdout

public class App {
    public int main(){
        print("Hello World\n");
        return 0;
    }
}

```

````

这个习题文件分为几个部分。

首先是一级标题,这个标题会出现在最终的习题页面。作为题目的标题。

然后是习题的描述,习题的描述可以有多段,除了文本,也可以是有序号或无序号的列表,也可以是代码段等合法的 markdown 格式。

目前题干不支持内部的子结构,这是出于简化设计的考虑。与下面介绍的习题章节结构设计有关。

### 习题的答案

习题答案是一个二级标题为 `答案` 的章节

```markdown
## 答案

答案内容
```

这个内容应紧跟着习题描述,在这之前可能有可选的模板或 aop 定义,但是不会再有其它内容,关于用来生成notebook的模板或aop结构,我们放在后面讨论。

答案的标题一定是 `答案`,这个二级标题不会出现在问题页。如果习题没有包含答案,后续处理时会报错。

### 习题的选项

在答案只有,应该有一个二级标题,名为 `选项` ,它列举了除正确答案之外的所有被选项。后续的技能树服务会在生成习题页面时,随机选择三个选项,与答案
一起展示给用户。因此,至少需要三个备选项。选项章节的形态如下:

````markdown
## 选项

### 带有代码段的选项

```java
,,,
```

### 文本选项

这段内容会成为问题页面上的选项

### 文本选项

选项也可以包含多个段落

````

原则上,我们鼓励尽可能多的选项,给学习者提供更好的体验。每个选项的三级标题不会出现在题目页,我们可以利用它叙述一些简短的信息。

### 习题代码和 notebook

每个习题的markdown文件,对应一个同名的json文件,例如 `hello.md` ,仓库的维护者会通过工具脚本或钩子生成一个对应的 `hello.json`
它的内容如下:

```json
{
  "type": "code_options",
  "author": "ccat",
  "source": "hello.md",
  "notebook_enable": false,
  "exercise_id": "ee4d10ae488b4900835e52d184822962"
}
```

这些配置信息可以由程序自动生成,但是有时可能我们需要做一些调整。例如当我们设置 `notebook_enable``true` 时,技能树服务会为其生成对应的
notebook 页,这些 notebook 页可以为学习者提供可执行的程序环境。

目前 CSDN 的 notebook 服务支持 c、python、java 三种语言,对于一些程序示例,特别是 C 或 Java 代码,可能整个可执行代码放进题目中过于冗长,
因此我们允许将题目中的代码嵌入到预先定义的模板中,组合成完整的可执行代码,再组装成 notebook 单元。而这些代码不需要出现在题目页。

为此我们支持两种代码包装形式:模板或 AOP 。

如果我们在题干之后,答案之前,插入一个名为 `template` 的章节,那么它的正文中定义的代码会当作模板处理:

````markdown
## template

```c
#inlcude <stdio.h>

int main(int argc, char** argv){
  $code
}
```
````

组装 notebook 页时,$code 占位符会被替换成 `答案` 中的代码段。这个占位符形式遵循 python 标准库 `string.Template` 类型的模板语法。

一些代码示例,可能需要更复杂的代码"外壳",把它分成在 `code`  之前和之后两部分更合适,此时我们可以使用 `aop` 章节。

````markdown
## aop

### before

```java
package app;
public class Main{
  public static void main(String[] argv){
```

### after

```java
    System.out.println("hello");
  }
}

```

````

章节标题 aop 来自 Java 的`面向方面编程(AOP)`。这里的三级标题 before 和 after 如果存在,它们的正文内容会在组装 notebook 页时出现在答案
的前面和后面。

AOP 章节可以只包含 before 和 after 中的某一个,并不需要两部分都齐全。

AOP 或模板章节,需要放在题干之后,答案之前。未来可能会调整位置,允许写到习题文本的最后。