开心!先来个成果图记录一下,之前一直觉得很神奇,自动生成题目的算法是怎样的,好奇着好奇着就去试试,其实好像也不涉及到啥算法,摸索着总算弄出来啦,大神莫笑小白之欢喜。
代码还没整理好,如果有人感兴趣的话,我再把源码贴出来分享分享~
===============================================
2020.04.07补一下源码
不常上没留意到留言,嘻嘻嘻,当时偷懒没有上传。我是写java的,本身不是写python的,所以代码里面可能有些不太优雅的地方,目标只是实现功能,见谅哈。另外有些代码可能是过程中为了调试写的,也懒得删了,记录了最原始的创作过程。(对了,我实现的这个,也是有参考别人的文章的,但是不记得是哪一篇了,看了好多篇,如果觉得有相同的地方,抱歉啊,欢迎原文作者们联系,一定把您大名署上)
可以调整目标成语数量target参数,改成你想要一次输出的成语数量。当然,你也可以优化将它变成传入参数,那会更加优雅一些,交给你自己啦。
在terminal里面运行时,要注意窗口大小,尤其是x轴方向的长度,要符合代码里的设定,不然的话出来的是对不齐的,正常应该是这样:
如果大小不注意错位的话就会这样了:
import random
import pymysql
from enum import Enum
#
conn = pymysql.connect(host="localhost", user="root", password="123456", database="idiom", charset="utf8")
cursor = conn.cursor()
class Coordinate(Enum):
X = "x"
Y = "y"
# 选中的成语列表,[‘一心一意’,’掩耳盗铃’]
idioms = []
# 选中的成员的拆分列表,含坐标,[[0,0,’一’],[1,0,’心’],[2,0,’一’],[3,0,’意’]]
splitIdioms = []
# 关键字拆分列表,含坐标,[[0,0,’一’],[1,0,’意’]]
splitKeys = []
# 已使用过的坐标
usedSeats = []
# 目标成语数量(!!!!这里可以修改参数!!!!)
target = 5
# 已经用过的坐标(后续避免重复)
def add_used_seats(idiom_split):
for en in idiom_split:
usedSeats.append((en[0], en[1]))
# 检查坐标是否已被使用
def check_not_in_used_seats(idiom_split, exclude_index):
for i in range(len(idiom_split)):
if usedSeats.__contains__((idiom_split[i][0], idiom_split[i][1])):
if i != exclude_index:
return False
return True
# 获取一个切分好的成语
def get_one(x, y, keyword):
idiom = get_random_idiom(keyword)
idioms.append(idiom)
# 第单数个成语:横放; 第双数个成语:竖放
if len(idioms) % 2 == 0:
direction = Coordinate.Y
else:
direction = Coordinate.X
# 找出这个成语中和上个成语的重用字的索引
last_used_index = idiom.find(keyword) if len(idioms) > 1 else -1
# print("last_used_index is: %s" % last_used_index)
# 切分,添加坐标
idiom_split = split_idiom(x, y, last_used_index, idiom, direction)
# 检查坐标是否已被使用
if not check_not_in_used_seats(idiom_split, last_used_index):
idioms.pop(-1)
return False, None
return True, idiom_split
# 将使用的成语加入到列表中
def add_one(idiom_split):
splitIdioms.extend(idiom_split)
add_used_seats(idiom_split)
def main():
x, y, keyword, last_used_index = 0, 0, '', -1
for i in range(target):
# 获取一个切分好的成语
ret, idiom_split = get_one(x, y, keyword)
# 如果不成功,重新获取,直到成功为止
while not ret:
ret, idiom_split = get_one(x, y, keyword)
# print("succeed to get one idiom: %s" % idiom_split)
# 将获取到的成语加入到列表中
add_one(idiom_split)
# 确定下个成语的关键字
last_used_index = -1 if len(idioms) <= 1 else idioms[-1].find(splitKeys[-1][2])
key_index = random.randint(0, len(idioms[-1]) - 1)
while last_used_index == key_index:
key_index = random.randint(0, len(idioms[-1]) - 1)
splitKeys.append(idiom_split[key_index])
# print("next keyword is: %s" % idiom_split[key_index])
# 准备下一个成语的基础
x = splitKeys[-1][0]
y = splitKeys[-1][1]
keyword = splitKeys[-1][2]
# 调整坐标
# print("usedIdioms: %s" % idioms)
# print("beforeList: %s" % splitIdioms)
fix_border()
# print("finalList: %s" % splitIdioms)
printOnScreen(splitIdioms)
def get_random_idiom(keyword):
if len(keyword) > 0:
keyword = '%' + keyword + '%'
sql = "SELECT chengyu FROM XUEBIJUN AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM XUEBIJUN)) AS id) AS t2 WHERE not locate(',',t1.chengyu) %s and t1.id >= t2.id ORDER BY t1.id ASC LIMIT 1" % "and chengyu like '%s'" % keyword
else:
sql = "SELECT chengyu FROM XUEBIJUN AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM XUEBIJUN)) AS id) AS t2 WHERE not locate(',',t1.chengyu) and t1.id >= t2.id ORDER BY t1.id ASC LIMIT 1"
cursor.execute(sql)
ret = cursor.fetchone()
while ret is None or idioms.__contains__(ret[0]):
ret = get_random_idiom(keyword)
# print("random idiom: %s" % ret)
return ret[0]
# 切分,添加坐标
def split_idiom(x, y, key_index, idiom, direction):
ret = []
key_index = key_index if key_index > 0 else 0
if direction == Coordinate.X:
for index in range(len(idiom)):
ret.append([x + index - key_index, y, idiom[index]])
else:
for index in range(len(idiom)):
ret.append([x, y + index - key_index, idiom[index]])
return ret
def fix_border():
min_x, min_y = 0, 0
for p in usedSeats:
min_x = p[0] if p[0] < min_x else min_x
min_y = p[1] if p[1] < min_y else min_y
for p in splitIdioms:
p[0] = p[0] + abs(min_x)
p[1] = p[1] + abs(min_y)
def printOnScreen(info):
newStr = ' ' * (40 * 40)
# 注意上面的空格是个中文空格!!
newList = list(newStr)
# 把字符串编程list以方便下面的直接索引操作
# 如果输入值对某个坐标位置有定义,则将该位置的空格换成对应字符
for pinfo in info:
index = 40 * pinfo[1] + pinfo[0]
newList[index] = pinfo[2]
# 再把list变回字符串,以方便输出
finalStr = ''.join(newList)
print(finalStr)
# info = [(0, 0, '天'), (1, 0, '地'), (3, 0, '人'), (2, 1, '日'), (2, 2, '月'), (2, 3, '风')]
# printOnScreen(info)
main()