决战《三字经》

作者 by 超米 / 2024-11-25 / 暂无评论 / 39 个足迹

import simpleguitk as gui
import random
import urllib.request

# 全局变量
has_rising_box = True  # 是否有文字块正在上升
canvas_height = 600  # 画布高度,单位为像素
canvas_width = 480  # 画布宽度,单位为像素
box_height = 30  # 文字块高度,单位为像素
box_width = 120  # 文字块宽度,单位为像素,包含3个汉字
rising_speed = -1  # 上升速度,单位为像素
game_over = False  # 游戏是否结束
rising_box = None  # 正在运动的文字块对象
stopped_box = []  # 停止移动的所有文字块列表
prime_sentence_list = []  # 三字经全文列表,3个字构成1句,每句为一个列表元素
current_section_list = []  # 当前处理的段落文字列表,每句为一个列表元素,4句为一个段落
score = 0  # 游戏得分

def read_from_file(filename):
    """从文本文件读入三字经,存储在列表中,并返回该列表"""
    # 三字经文件的格式如下:
    '''
    # rén zhī chū    xìng běn shàn    xìng xiāng jìn    xí xiāng yuǎn
    #人之初    性本善    性相近    习相远
    gǒu bú jiào    xìng nǎi qiān    jiào zhī dào    guì yǐ zhuān
    苟不教    性乃迁    教之道    贵以专
    ......
    '''
    # 奇数行为诗句拼音,偶数行为诗句文本
    # 三字经每3个汉字为1句,每1句作为列表的1个元素,四句为一行(一段),句间隔为空格
    i = 1
    new_list = []
    szj_file = urllib.request.urlopen(filename)
    for line in szj_file.readlines():
        if i % 2 == 0:
            line_list = str(line.decode("utf-8")).split()
            for sentence in line_list:
                new_list.append(sentence)
        i += 1
    szj_file.close()
    return new_list

def text_shuffle(text):
    """打乱文字的次序"""
    random_list = list(text)
    random.shuffle(random_list)
    return ''.join(random_list)

def draw_all_stopped_box(boxes, canvas):
    """绘制所有的停止块"""
    for box in boxes:
        box.draw(canvas)

def generate_current_section_list():
    """生成当前段落四句诗歌列表"""
    global prime_sentence_list
    create_list = []
    for i in range(4):
        create_str = str(i) + prime_sentence_list.pop(0)
        create_list.append(create_str)
        random.shuffle(create_list)
    return create_list

def check_collision(group, moving_box):
    """检查移动块和所有停止块是否发生碰撞"""
    for box in group:
        if box.collide(moving_box):
            return True
    return False

def delete_last_four(group):
    """消除最后4个块,字序和句序都正确时调用该函数"""
    n = len(group)
    group.pop(n - 1)
    group.pop(n - 2)
    group.pop(n - 3)
    group.pop(n - 4)

def last_four_ok(group):
    """判断最后4个块的字序和句序是否都正确"""
    n = len(group)
    if group[n - 1].proper_order and group[n - 1].sentence == group[n - 1].correct_sentence and \
            group[n - 2].proper_order and group[n - 2].sentence == group[n - 2].correct_sentence and \
            group[n - 3].proper_order and group[n - 3].sentence == group[n - 3].correct_sentence and \
            group[n - 4].proper_order and group[n - 4].sentence == group[n - 4].correct_sentence:
        return True

def stop_box(group: object, moving_box: object) -> object:
    """停止移动块"""
    global has_rising_box, game_over, score, label, last_four_box, stopped_box
    if moving_box.processed:
        return
    if moving_box.pos[1] == 0 or check_collision(group, moving_box):
        moving_box.rising = False
        has_rising_box = False
        if moving_box.sentence == moving_box.correct_sentence:
            score += 5
            label_text = "游戏得分 = " + str(score) + "分"
            label.set_text(label_text)
        if moving_box.pos[0] / box_width != moving_box.order:
            moving_box.proper_order = False

        moving_box.processed = True
        stopped_box.add(moving_box)
        last_four_box.append(moving_box)
        if len(last_four_box) == 4:
            if last_four_ok(last_four_box):
                score += 20
                label_text = "游戏得分 = " + str(score) + "分"
                label.set_text(label_text)
                for box in last_four_box:
                    stopped_box.discard(box)
            delete_last_four(last_four_box)

        line_index = (moving_box.pos[1] + 15) // box_height
        if line_index >= 10:
            game_over = True

def draw_game_over_msg(canvas, msg):
    """绘制游戏结束信息"""
    msgwidth = frame.get_canvas_textwidth(msg, 48, 'sans-serif')
    canvas.draw_text(msg, ((canvas_width - msgwidth) / 2, canvas_height / 2), 48, 'Red', 'sans-serif')

class Box:
    """Box类的定义"""

    def __init__(self, pos, width, height, sentence, correct_sentence, order):
        self.pos = [pos[0], pos[1]]  # 文字块左上角在画布的坐标位置
        self.width = width  # 文字块的宽度
        self.height = height  # 文字块的高度
        self.sentence = sentence  # 文字块实际显示的句子
        self.correct_sentence = correct_sentence  # 文字块正确字序的句子
        self.rising = True  # 文字块是否正在上升
        self.processed = False  # 反射碰撞后是否处理完毕
        self.order = order  # 该文字块在一段中的正确句序
        self.proper_order = True  # 实际句序是否正确

    def shuffle_sentence(self):
        """打乱字序"""
        self.sentence = text_shuffle(self.sentence)

    def collide(self, moving_object):
        """检查是否和移动块发生碰撞"""
        if self.pos[1] + self.height == moving_object.pos[1] and self.pos[0] == moving_object.pos[0]:
            return True
        else:
            return False

    def draw(self, canvas):
        """绘制自己"""
        text_width = frame.get_canvas_textwidth(self.sentence, 22, 'sans-serif')
        if self.sentence == self.correct_sentence and self.proper_order:
            canvas.draw_polygon([self.pos, [self.pos[0] + self.width, self.pos[1]],
                                 [self.pos[0] + self.width, self.pos[1] + self.height],
                                 [self.pos[0], self.pos[1] + self.height]], 2, 'Green', 'Green')
            canvas.draw_text(self.sentence, (self.pos[0] + (self.width - text_width) / 2, self.pos[1] + self.height), 22, 'White', 'sans-serif')
        else:
            canvas.draw_polygon([self.pos, [self.pos[0] + self.width, self.pos[1]], [self.pos[0] + self.width, self.pos[1] + self.height], [self.pos[0], self.pos[1] + self.height]], 2, 'Red', 'Red')
            canvas.draw_text(self.sentence, (self.pos[0] + (self.width - text_width) / 2, self.pos[1] + self.height), 22,  'Yellow','sans-serif')
    def update(self):
        """更新垂直位置,使其向上移动"""
        if self.rising:
            self.pos[1] += rising_speed

def box_spawner():
    """时钟事件处理函数,生产一个上升的方块"""
    global has_rising_box, rising_box, current_section_list, game_over
    if game_over:
        return
    if not has_rising_box:
        if len(current_section_list) == 0:
            current_section_list = generate_current_section_list()
        sentence = current_section_list.pop()
        random_pos = [random.randrange(4) * box_width, canvas_height]
        rising_box = Box(random_pos, box_width, box_height, text_shuffle(sentence[1:]), sentence[1:], int(sentence[0]))
    has_rising_box = True

def draw(canvas):
    """屏幕刷新事件处理函数"""
    global rising_box
    if game_over:
        draw_game_over_msg(canvas, '游戏结束!')
    else:
        rising_box.draw(canvas)
        rising_box.update()
        draw_all_stopped_box(stopped_box, canvas)
        stop_box(stopped_box, rising_box)

def key_down(key):
    """处理键盘按下事件的函数"""
    if not game_over:
        if key == gui.KEY_MAP["left"]:  #向左移动方块
            if rising_box.pos[0] - box_width >= 0:
                rising_box.pos = [rising_box.pos[0] - box_width, rising_box.pos[1]]
        elif key == gui.KEY_MAP["right"]: #向右移动方块
            if rising_box.pos[0] + box_width + box_width <= canvas_width:
                rising_box.pos = [rising_box.pos[0] + box_width, rising_box.pos[1]]
        elif key == gui.KEY_MAP["space"]: #重排文字顺序
            rising_box.shuffle_sentence()

def start_game():
    """为游戏开始或重新开始初始化全局变量,也是鼠标点击按钮的事件处理函数"""
    global prime_sentence_list, stopped_box, rising_box, current_section_list, has_rising_box, game_over, score, last_four_box
    url = 'http://202.201.225.74/video/PythonResoure/ProjectResource/other/szj.txt'
    prime_sentence_list = read_from_file(url)

    last_four_box = []
    score = 0
    label.set_text("游戏得分 = 0")
    game_over = False
    stopped_box = set([])
    current_section_list = generate_current_section_list()
    rising_sentence = current_section_list.pop()
    rising_box = Box([0, canvas_height], box_width, box_height, text_shuffle(rising_sentence[1:]), rising_sentence[1:], int(rising_sentence[0]))

    has_rising_box = True

# 创建窗口初始化画布
frame = gui.create_frame("决战《三字经》", canvas_width, canvas_height)
label = frame.add_label("游戏得分 = 0分")

# 注册事件处理函数
frame.set_keydown_handler(key_down)  # 按键处理,每次按键会调用key_down函数
frame.set_draw_handler(draw)  # 显示处理,每秒调用draw函数60次
timer = gui.create_timer(1000.0, box_spawner)  # 每秒调用box_spawner函数1次
button = frame.add_button('重新开始游戏', start_game, 100)  # 鼠标每次点击“重新开始游戏”按钮,调用start_game函数1次

# 启动游戏
start_game()  # 为游戏开始或重新开始初始化全局变量
timer.start()  # 启动定时器
frame.start()  # 显示窗口

独特见解