逛微博看到了一些有意思的东西:山东卫视《国学小名士》第三季的节目,进行了一场 π(圆周率) 的飞花令。
节目里选手们接到了小数点后 204 位,那,能不能更长一点?
数据储备
首先需要有足够多的古诗词储备,不然程序生成的时候耗光弹药就显得非常尴尬了。
非常感谢chinese-poetry这样的开源项目,积累了大量的已经结构化的古诗词数据。
这里只用宋词部分的数据。
算法逻辑
逻辑很简单粗暴:找出所有包含中文数字的词句进行汇总,然后按小数点后位数迭代 π 值随机取对应的诗词就行。
整理诗词数据:
import json
import re
import os
filelist = [
file for file in os.listdir('./json') if re.search(r'poet.song', file)
]
files = [
json.load(open('./json/' + file, 'r', encoding='utf-8-sig'))
for file in filelist
]
result = {
'一': [],
'二': [],
'三': [],
'四': [],
'五': [],
'六': [],
'七': [],
'八': [],
'九': [],
'零': []
}
for file in files:
for x in file:
for y in x['paragraphs']:
for z in ['一', '二', '三', '四', '五', '六', '七', '八', '九', '零']:
if re.search(z, y):
result[z] = result.get(z) + [
'{}\n\t\t\t\t{}/{}'.format(y, x['author'], x['title'])
]
with open('step.json', 'w', encoding='utf-8-sig') as f:
f.write(json.dumps(result, ensure_ascii=False))
π 值计算
无脑套用了一下别人的代码:http://z-rui.github.io/post/2015/06/pi-digits/
def pidigits():
q, r, t, u, i = 1, 180, 60, 168, 2
while True:
y = r // t
yield y
q, r, t, u, i = 10 * q * i * (2 * i - 1), 10 * u * (
q * (5 * i - 2) + r - y * t), t * u, u + 54 * (i + 1), i + 1
不停迭代 pidigits() 就能得到后一位小数数值。
开始飞花令
测试一下迭代圆周率 1000 位
import json
import sys
from random import randint
poets = json.load(open('step.json', 'r', encoding='utf-8-sig'))
number = {
1: '一',
2: '二',
3: '三',
4: '四',
5: '五',
6: '六',
7: '七',
8: '八',
9: '九',
0: '零'
}
n = 0
def pidigits():
q, r, t, u, i = 1, 180, 60, 168, 2
while True:
y = r // t
yield y
q, r, t, u, i = 10 * q * i * (2 * i - 1), 10 * u * (
q * (5 * i - 2) + r - y * t), t * u, u + 54 * (i + 1), i + 1
while True:
f = open('result.md', 'w', encoding='utf-8-sig')
for num in pidigits():
used = []
new = poets[number[num]].pop(randint(0, len(poets[number[num]])))
while new in used:
new = poets[number[num]].pop(randint(0, len(poets[number[num]])))
print(num, number[num], new)
f.write('{}\t{}\t{}\n'.format(
num, number[num],
new.replace(number[num], '`{}`'.format(number[num]))))
used = used.append(new)
n += 1
if n > 1000:
f.close()
sys.exit()