# skill_tree_c

`网络技能树`是[技能森林](https://gitcode.net/csdn/skill_tree)的一部分。

## 初始化

```
pip install -r requirement.txt
```

## 目录结构说明

* 技能树`骨架文件`：
  * 位置：`data/tree.json`
  * 说明：该文件是执行 `python main.py` 生成的，请勿人工编辑
* 技能树`根节点`配置文件：
  * 位置：`data/config.json`
  * 说明：可编辑配置关键词等字段，其中 `node_id` 字段是生成的，请勿编辑
* 技能树`难度节点`：
    * 位置：`data/xxx`，例如: `data/1.C语言初阶`
    * 说明：
        * 每个技能树有 3 个等级，目录前的序号是必要的，用来保持文件夹目录的顺序
        * 每个目录下有一个 `config.json` 可配置关键词信息，其中 `node_id` 字段是生成的，请勿编辑
* 技能树`章节点`：
    * 位置：`data/xxx/xxx`，例如：`data/1.C语言初阶/1.C语言概述`
    * 说明：
        * 每个技能树的每个难度等级有 n 个章节，目录前的序号是必要的，用来保持文件夹目录的顺序
        * 每个目录下有一个 `config.json` 可配置关键词信息，其中 `node_id` 字段是生成的，请勿编辑
* 技能树`知识节点`：
    * 位置：`data/xxx/xxx`，例如：`data/1.C语言初阶/1.C语言概述`
    * 说明：
        * 每个技能树的每章有 n 个知识节点，目录前的序号是必要的，用来保持文件夹目录的顺序
        * 每个目录下有一个 `config.json`
            * 其中 `node_id` 字段是生成的，请勿编辑
            * 其中 `keywords` 可配置关键字字段
            * 其中 `children` 可配置该`知识节点`下的子树结构信息，参考后面描述
            * 其中 `export` 可配置该`知识节点`下的导出习题信息，参考后面描述


## `知识节点` 子树信息结构

例如 `data/1.C语言初阶/1.C语言概述/1.C语言发展史/config.json` 里配置对该知识节点子树信息结构：
```json
{
    // ...

    "children": [
        {
        "C语言的起源": {
            "keywords": [
            "C语言的起源",
            "起源",
            "C语言"
            ],
            "children": []
        }
        },
        {
        "C语言的发展与应用": {
            "keywords": [
            "C语言的发展",
            "C语言的应用",
            "发展",
            "应用",
            "C语言"
            ],
            "children": []
        }
        }
    ],
}
```



## `知识节点` 的导出习题编辑

例如 `data/1.C语言初阶/1.C语言概述/1.C语言发展史/config.json` 里配置对该知识节点导出的习题

```json
{
    // ...
    "export": [
        {
            "file": "helloworld.c",
            "variants": "helloworld.json",
            "depends": []
        },
        // ...
    ]
}
```

格式说明：
* `file`: 指定该目录下的习题源文件
* `variants`： 指定习题同名的json选项配置文件，参考下一节
* `depends`: 如果习题依赖同目录下的其他习题源代码，则在此字段里配置依赖的其他习题源文件名

## `知识节点` 的导出习题选项配置编辑

目前我们支持使用 markdown 语法直接编辑习题和各选项。

首先，编辑知识节点的配置，导出习题：


```json
{
    // ...
    "export": [
        "hellowworld.json"
    ]
}
```


然后在 `data/1.C语言初阶/1.C语言概述/1.C语言发展史/` 下增加一个`helloworld.json`定义文件：


```json
{
    "type": "code_options",
    "author": "ccat",
    "source": "helloworld.md",
    "notebook_enable": true
}
```

其中 type 字段目前都固定是 `code_options`，notebook_enable 字段决定这个习题是否生成对应的 notebook 。根据具体情况写好其它字段，注意这里 source 的文件名，我们指定了一个 markdwon 文件。现在我们新建一个 HelloWorld.md 并编辑为：


````mardown
# Hello World

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

## 答案

```c
#include <stdio.h>
int main(int argc, char** argv){
    printf("Hello,Wrold!");
    return 0;
}
```

## 选项

### main 函数定义错误

```c
#include <stdio.h>
void main(){
    printf("Hello,Wrold!");
    return 0;
}
```

### Print 函数调用错误

```c
#include <stdio.h>
int main(int argc, char** argv){
    printf("Hello,Wrold!");
    return 0;
}
```

### Java 风格的导入

```c
import stdio;

int main(int argc, char** argv){
    stdio.printf("Hello,Wrold!");
    return 0;
}
```

### 函数错误

```c
#include <stdio.h>
int main(int argc, char** argv){
    print("Hello,Wrold!");
    return 0;
}
```
````

### 增强信息

为了编写习题和生成 notebook 的需要，markdown 解释器支持两种模板能力，如果我们在答案之前，有一个名为 aop 的二级标题：

````markdown

## aop

### before

```c
print("hello world");
```

### after

```c
main(0, NULL);
```
````

那么在创建notebook的时候，before 会插入到源代码前一个单元，after 则会插入到源代码后。aop 章节可以只包含 before 或 after 中的某一个，也可以两个都有。

另一些情况下，我们可能需要把各个选项中重复的代码提取出来，建立一个模板，此时可以在答案之前建立一个名为 template 的二级标题，例如：

````markdwon

## template

```c
```c
#include <stdio.h>
int main(int argc, char** argv){
    $code
    return 0;
}

```

````

注意这里的代码中，有一个 `$code` 占位符，它在管道程序处理过程中，会替换成答案和个选项内容中的代码

## 技能树合成

在根目录下执行 `python main.py` 会合成技能树文件，合成的技能树文件: `data/tree.json`
* 合成过程中，会自动检查每个目录下 `config.json` 里的 `node_id` 是否存在，不存在则生成
* 合成过程中，会自动检查每个知识点目录下 `config.json` 里的 `export` 里导出的习题配置，检查是否存在`exercise_id` 字段，如果不存在则生成
