# 蓝桥 卷“兔”来袭编程竞赛专场-02破解曾公亮密码 题解

## 赛题介绍

### 挑战介绍

曾公亮编撰的《武经总要》中记载了一套严谨的军事通信密码，这也是目前发现我国古代战争中最早使用的军用密码表。将战场上可能常用到的情况，用 40 个短语归纳表示，且每个短语前编有固定的数字代码，这 40 个短语及数字代码如下：

| 代码 | 短语 | 代码 | 短语 | 代码 | 短语 | 代码 | 短语 | 代码 | 短语 |
| ---- | ---- | ---- |---- | ---- | ---- | ---- | ---- | ---- | ---- |
| 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 | 战小胜 |

然后约定某一首五言古诗作为解密的钥匙，五言古诗中 40 个字正好对应密码表中 40 种情况。

例如约定唐代王勃的《送杜少府之任蜀川》为解密的钥匙。

> 城阙辅三秦，风烟望五津。

>与君离别意，同是宦游人。

>海内存知己，天涯若比邻。

>无为在歧路，儿女共沾巾。

如果军中马匹不足，需要请求马匹，那么对应密码表中的情报则是：7、请马。而《送杜少府之任蜀川》中第 7 个字是烟，将军只需要将“烟”字写到 一件普通公文书牒之中，并在字上加盖印章。朝廷收到公文书牒后通过《送杜少府之任蜀川》确认“烟”字的位置，然后查找密码表，获得相应的情报。

### 挑战目标

补充文件  `zeng_gongliang.py`  下  `zeng_gongliang_decryption(text)`  函数中的 TODO 部分，使其实现我们需要的功能：

- 输入古诗《送杜少府之任蜀川》中任意一个字，返回曾公亮密码表中对应的短语。
- 如果输入的内容在古诗《送杜少府之任蜀川》的 40 个 字中查找不到，则返回 None。
- 其它情况全部返回 None。

```python
def zeng_gongliang_decryption(text: str) -> str:
    """TODO
    """
    key_dict = {'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':'战小胜'} 
    decryption_text : str = ''

    return decryption_text
```

### 挑战要求

- 题目需使用 Python3 完成，不能使用标准库和第三方库。
- 函数传入 text 为字符串类型，可能为空、`None` 等值。
- 不得修改文件路径、文件名 `zeng_gongliang.py` 以及函数名 `zeng_gongliang_decryption(text)`。
- 请只保留文件 `zeng_gongliang.py` 及文件中函数，不要添加测试或执行代码，避免检测时出错。
- 线上环境调试代码时，请使用 `python3 zeng_gongliang.py` 命令调用 Python3。

### 参考样例

```python
# 样例 1
text = "烟"; decryption_text = "请马"
# 样例 2
text = "城"; decryption_text = "请弓"
# 样例 3
text = "请弓"; decryption_text = None
# 样例 4
text = "城 "; decryption_text = None
# 样例 5
text = None; decryption_text = None
```

注意：最终实现效果以完全满足要求为准，而不是仅满足如上样例。

---

## 题解

### 解题思路

主要考察字典`dict`结构及方法的运用

1. 要注意对传入参数类型的检查，包括空字符串等情形。
2. 构造索引字符串。
3. 利用`index()`方法寻找某个字符的索引.
4. 过滤不存在的键值，返回`None`。
5. 最后使用`get`方法从字典找到对应的字符串值返回即可。

```python
def zeng_gongliang_decryption(text: str) -> str:
    """TODO
    """
    # 过滤非str类型输入
    if not isinstance(text, str) or text == "":
        return None
    # 仅一个字符输入限制
    if len(text) > 1:
        return None
    # 构造数据字典
    key_dict = {'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': '战小胜'}
    poem = "城阙辅三秦风烟望五津与君离别意同是宦游人海内存知己天涯若比邻无为在歧路儿女共沾巾"

    if text in poem:
        num = poem.index(text) + 1
        if key_dict.get(str(num)) == None:
            return None
    else:
        return None
    decryption_text: str = key_dict.get(str(num))
    return decryption_text
```

---

题目来源：[破解曾公亮密码](https://www.lanqiao.cn/problems/2396/learning/?contest_id=83)
