python实现成语填字游戏 自动生成题目

开心!先来个成果图记录一下,之前一直觉得很神奇,自动生成题目的算法是怎样的,好奇着好奇着就去试试,其实好像也不涉及到啥算法,摸索着总算弄出来啦,大神莫笑小白之欢喜。


image.png

代码还没整理好,如果有人感兴趣的话,我再把源码贴出来分享分享~

===============================================
2020.04.07补一下源码

不常上没留意到留言,嘻嘻嘻,当时偷懒没有上传。我是写java的,本身不是写python的,所以代码里面可能有些不太优雅的地方,目标只是实现功能,见谅哈。另外有些代码可能是过程中为了调试写的,也懒得删了,记录了最原始的创作过程。(对了,我实现的这个,也是有参考别人的文章的,但是不记得是哪一篇了,看了好多篇,如果觉得有相同的地方,抱歉啊,欢迎原文作者们联系,一定把您大名署上)
可以调整目标成语数量target参数,改成你想要一次输出的成语数量。当然,你也可以优化将它变成传入参数,那会更加优雅一些,交给你自己啦。
在terminal里面运行时,要注意窗口大小,尤其是x轴方向的长度,要符合代码里的设定,不然的话出来的是对不齐的,正常应该是这样:


image.png

如果大小不注意错位的话就会这样了:


image.png
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()

你可能感兴趣的:(python实现成语填字游戏 自动生成题目)