8个成语接龙首尾相连_帮助你在成语接龙里逼死别人的工具

6090d7e3d036bee1a6a2afc40b7e2c19.png

球球各位大佬不要在评论区里霸凌我了

我已经知道开那么多线程是个很弱智的行为了呜呜呜呜

最近QQ推出了一个成语接龙红包的功能,然后有些人发现了一个顶俩这个可怕的词。看了 @张逸群 的文章后,我觉得我大概也能写出一个类似的小东西出来。

首先,我做了点资料搜集,发现清华大学有一个开放的中文词语库,果断下载下来。

下载完后是一个txt文件,里面每行是一个成语。可以看到词库里有不是四字的成语和一些我们不需要的数字,所以要在程序里去除掉不需要的数据。

fdd5a00d4ec5d5dc6638859c9e618b22.png
源数据

随后,我把所有词按照首和尾的拼音分类了一下,这部分的代码如下:

heads = {}
tails = {}

# Parse the source
with open('THUOCL_chengyu.txt', 'r', encoding='utf-8') as source:
    idioms = [i for i in map(lambda x: x.split()[0], source.readlines()) if len(i) <= 4]

# Filter by heads and tails
for idiom in idioms:
    head = getHead(idiom)
    tail = getTail(idiom)
    # 按首拼音分类
    if head not in heads:
        heads[head] = [idiom]
    else: 
        heads[head].append(idiom)
    # 按尾拼音分类
    if tail not in tails:
        tails[tail] = [idiom]
    else: 
        tails[tail].append(idiom)

这样,就可以开始生成接龙啦

首先,我设置接龙目标为‘一个顶俩’,一个顶俩的首拼音为‘yi’,于是找尾为‘yi’的成语,然后从那些成语继续往下爬,爬到一定层数的时候停止。这样的话每爬一次就是一个接龙,把爬的顺序存到输出文件里面。

如果用很无聊很无聊的技术语言来说的话:就是从根开始深度优先遍历一颗树,每遍历一个节点就把遍历的路径存到结果列表里面。

于是,现在的结果:

3efbbc9b1246b033c9fb061e1573ec34.png

显然...这种单线程遍历八千多个节点互相链接的树是很慢的...于是改成多线程吧!

开20000个线程跑起来!

(ps:没贴源代码是因为修改后这段时间的代码没备份)

847bda3fde20ce2751dc6d231b8e62cb.png
2w个线程的占用

终于,跑了差不多一个半小时后,程序跑完了。

看看结果吧!

哇,整整两亿多条,刺激嗷

等一下下...结果好像有点不对?

0e9411dfcd5d925897a958cedd369885.png
emmm

emmm....貌似有点问题,难不成我一个半小时白爬了???

然后我经过我的仔细观察后发现...

f63a8b71f1a0127e0120bbaedb3e5e0d.png

顺 序 反 了

82a409275ed8a0c2865e4d1393d42ec6.png
蓝受

emm...这个还是可以挽救的...于是我写了个脚本来修改结果的顺序。处理比较简单:除了最后一个成语之外其他顺序倒过来

以下是代码:

# 加一个winsound后在处理完可以有提示音
import winsound
# 读取
with open('results.txt', 'r', encoding='utf-8') as source:
    lines = source.readlines()
winsound.Beep(400, 300)
print('Reading done')
# 处理
result = map(lambda x: '->'.join(x.strip().split('->')[0:-1][::-1]) + '->一个顶俩', lines)
winsound.Beep(450, 300)
print('Processing done')
# 输出
with open('results.txt', 'w', encoding='utf-8') as output:
    output.write('n'.join(result))
winsound.Beep(500, 300)
print('Finished!')

这部分生成的结果在文章最结尾会打包发出来(大小差不多1.5g)

然后,作为一个(垃圾)程序员,肯定不会满意一个半小时的输出时间,所以我开始了一去不复返的优化之路。

至于怎么优化的我就不详述了(反正没人想看 我也不知道),总的来说,改成MySQL存储结果,减少需要遍历的节点blablabla

直接贴无聊的代码:

(是的我忘做注释了请各位程序员上帝原谅我呜呜呜)

# Put in initial jobs
jobs = Queue()
if TARGET in tails:
    for idiom in tails[TARGET]: jobs.put((idiom, [TARGET_IDIOM], 1))

def worker():
    db = MySQLdb.connect('localhost', 'root', 'lq369258147123')
    db.set_character_set('utf8')
    c = db.cursor()
    c.execute('USE idioms')
    while jobs.not_empty:
        idiom, path, depth = jobs.get()    
        head = getHead(idiom)
        c.execute('''INSERT INTO `connections` 
                    (`Initial`, `Head`, `Path`, `Depth`) 
                    VALUES 
                    ("{}", "{}", "{}", {})'''.format(head, idiom, '->'.join([idiom] + path), depth)
        )
        db.commit()
        jobs.task_done()
        if depth == MAX_DEPTH - 1 and head in tails:
            c.execute('''INSERT INTO `connections`
                        (`Initial`, `Head`, `Path`, `Depth`)
                        VALUES
                        {}'''.format(','.join(['("{}", "{}", "{}", {})'.format(getHead(i), i, '->'.join([i, idiom] + path), MAX_DEPTH) for i in tails[head]]))
            )
            db.commit()
        elif depth < MAX_DEPTH and head in tails:
            for i in tails[head]:
                jobs.put((i, [idiom] + path, depth + 1))
    c.close()
    db.close()

这时有个朋友告诉我还有个接不了的成语叫‘救过不给’

换目标成语,5000个线程跑起来!(2w个线程同时链接数据库会崩掉)

95dbb1467e57f54aa7f13a0120086403.png
tim崩了

9697ae4e467a99d95cc19150846cdcf4.png
悲鸣的电脑

终于在差不多十五分钟后,生成完了。

生成了差不多四百万个接龙(比一个顶俩少很多)

79e3b7585c2820b783f99f1243fd01d0.png
接龙数量

0ef1cc11d65d3bc23b3fe2d77b9c661d.png
结果

65d6a992151aa78381b9d8e10e353a75.png
结果

当然...作为一个后端,怎么会只满足于一个数据库呢,肯定要写一个接口和前端呀。

说做就做,走起!

先写了个简单的api:

bde98f383ac0b2ccbff086aa50463f0a.png

然后写了一个非常少女心(?)的前端:

6d222ac21437d4f773bec683f6863fd0.png
加了个微信骗钱码

然后不知为什么脑子一抽想用docker和nginx搞一个比较有逼格的结构,但是一个都不会用...

但是作为一个(垃圾)程序员,有什么不会的,上谷歌学咯

于是花了一天把docker和nginx入门了!

接下来就是部署啦!

花了二十块钱买了个腾讯云的学生服务器,部署了上去。

如果你想要用的话链接在这里:

成语接龙工具​49.234.224.123

(为什么没域名?因为我没钱+懒得备案)

折腾了这么久,终于把这个小工具做完了。

是时候好好在我朋友们发接龙红包的时候好好整整他们啦!

欸...我好像没朋友

rip

下载链接:https://pan.baidu.com/s/115F2-JYT-Udbdmok0foncQ

提取码:hfdu

里面有一个顶俩的txt文件和救过不给的sql文件

总结:

总体来说做这个小工具还是满有价值的,首先是半个暑假都没写代码手都生了,写这个小工具复习一下。其次就是终于学会了docker和nginx,一下完成了今年给自己定的两个小目标。

还有就是,我知道这不是什么真的大数据项目,而且我在文中做的东西可能都很弱智,但我只是个学生,所以请各位真正的程序员大佬体谅一下....

最后 谢谢你们观看 祝各位读者们 身体健康

uwu

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值