实现成语接龙(Python)
目录
前言
要实现的规则如下:
根据接龙的成语的第一个字与前一个成语结尾的字的比较,分一下三种模式
- 模式1:字相同拼音也要相同
- 模式2:字相同拼音不要求相同
- 模式3:字不要相同拼音要求相同,即谐音就可以
- 接龙的成语必须是四字成语
- 已使用过的成语双方均不得再次使用
- 一方不按照规则接龙或接不下去时判定失败
数据获取和清洗
本文语料来自于Bookdown图书下载网,抓下来之后,经过乱码处理、脏数据去除、分章数据合并、结构化提取等操作,得到了一份结构化好的json类型数据。我已经把它放在了github上,下载地址为github。
本成语库总共包含成3万个成语,其中四字成语大概2.9万个。每条数据包含以下字段:
字段 | 说明 | 字段 | 说明 |
---|---|---|---|
idiom | 成语本身 | pinyin | 拼音 |
source | 成语出处 | explanation | 成语释义 |
sample | 示例 |
代码实现
代码也已经放到了GitHub上,这里就不再贴出。源码地址为https://github.com/lukeplus/Idiom。下面主要讲讲如何使用。
示例1:
from solitaire import IdiomSolitaire
game = IdiomSolitaire()
game.forward("一心一意") # 输出:(True, '意气飞扬')
game.forward("扬眉吐气") # 输出:(True, '气壮山河')
game.forward("呵呵呵呵") # 输出:(False, None)
示例2:
xxxxxxxxxx
game = IdiomSolitaire()
game.get_next_idiom("人山人海") # 输出:海市蜃楼
game.get_next_idiom("人山人海") # 输出:海阔天空
game.get_next_idiom("战战兢兢") # 输出:兢兢乾乾
示例3:
xxxxxxxxxx
from solitaire import IdiomSolitaire
game = IdiomSolitaire()
# bot_first系统先开始
idiom = game.bot_first() # 输出:一心一意
game.forward("意气飞扬") # 输出:(True, '扬长避短')
IdiomSolitaire类
IdiomSolitaire类负责成语接龙流程,以及游戏状态维护。支持三种模式,如下:
xxxxxxxxxx
game= IdiomSolitaire(mode="pw") # pw表示字和拼音都要保持一致
game= IdiomSolitaire(mode="p") # p表示拼音一致即可
game= IdiomSolitaire(mode="w") # w表示字一样即可
xxxxxxxxxx
game = IdiomSolitaire(mode="p")
game.get_next_idiom("不三不四") # 输出:肆意横行
forward方法
推进游戏运行的主要方法,当第一次调用时,允许输入参数为空,表示由系统起头开始游戏。第一次调用不为空时,表示由客户端开始游戏。forward既要检验输入成语对上一个成语的承接(这是与get_next_idiom
的主要区别),也要计算下一个成语。
返回二元组,第一个元素代表输入的成语是否准确,是否能承接上一个成语,第二个元素是下一个待接龙的成语。
- 当返回
(False, None)
,表示输入的成语不能连接上一个成语。用户输掉比赛。 - 当返回
(True, None)
, 表示机器找不到一个成语能接上用户输入的成语。机器输掉比赛。
get_next_idiom
不考虑上下文,单纯返回能承接输入词的词语。
总结与改进
总的来说,简单需求的成语接龙的实现几乎没什么难点,没有牵涉到复杂的算法。而实现它的目的,是觉得可以拿这份成语语料做其他NLP相关的更酷的事情。比如说,给定一段话,通过语义分析之后,得到与这段话意思最相近的一个成语。
当然,要把成语接龙做得更人性化,还是得花很多心思的,也没有那么简单,需要改进的地方很多。比如系统选词不应该是简单的随机选,而是应该考虑成语的难易程度、普及程度,毕竟如果老是随机选一些冷门词,那游戏就不好玩了。