决战三字经

游戏说明

《三字经》与《百家姓》、《千字文》并称为三大国学启蒙读物。《三字经》是中华民族珍贵的文化遗产,它短小精悍、琅琅上口,千百年来,家喻户晓。其内容涵盖了历史、天文、地理、道德以及一些民间传说,所谓“熟读《三字经》,可知千古事”。
刻在竹简上的《三字经》
  《三字经》每三个字为一句,每四句为一段。《三字经》共1476字,492句,123段。
  决战《三字经》游戏与俄罗斯方块游戏类似,三字一句组成一个矩形方块,该方块从画布的底部出现并向顶部移动,方块到达顶部或碰到其它方块则停止运动。方块中的文字次序随机排列,游戏运行时,按空格键可以调整文字的顺序,如果方块停止移动时,文字的顺序正确,玩家将得到5分。一段中的四句出现的位置和次序也是随机变化的,游戏运行时,按左右箭头键可以改变正在上升的文字块的水平位置。一行填满后,如果行中四句诗文左右位置正确且句内文字顺序正确,玩家将得到20分,同时游戏程序会清除该行。
  当错误行数累计达到10行时,或者全部诗文播放完毕时,游戏结束,挑战者的能力用游戏得分的高低来衡量。

程序说明

点击添加Bookmark this page
  本项目我们将尝试用Python语言设计开发一个计算机程序来以游戏的形式让玩家熟悉《三字经》。程序的文件名称为ThreeCharacterPrimer.py。程序将使用到以下Python语言的功能特性:

(1)Python保留词:

import、import…as、True、False、None、def、return、global、if/elif/else、and、or、class、for/in等。

(2)导入的模块:

import simpleguitk as simplegui

import random

import copy

(3)使用到的内置函数及模块中的函数:

print()、open()、close()、readlines()、split()、join()、random.randrange()

random.shuffle()、simplegui.create_frame()、simplegui.create_timer()、add_button()

add_label()、set_keydown_handler()、set_draw_handler()、get_canvas_textwidth()、

draw_text()、set_text()、draw_polygon()、copy.deepcopy()等。

(4)使用到的数据结构:

集合(set)、列表(list)等

(5)其它知识点和概念:

类和对象、事件驱动、全局变量、数学运算表达式、逻辑条件表达式、字符串运算表达式、自定义函数、代码格式、注释等Python语言的一些特性。

通过该项目你可以获得以下能力:

进一步理解计算机的工作原理
进一步熟悉事件驱动的程序设计方法
进一步理解面向对象的程序设计方法
熟练掌握利用simpleguitk模块开发小游戏的程序框架
掌握Python集合(set)、列表(list)数据结构的使用方法
掌握游戏逻辑到Python代码的转换过程
练习解决问题的步骤
  基于simpleguitk模块的小游戏程序框架通常由全局变量的定义、辅助函数的定义、辅助类的定义、事件处理函数的定义、程序窗口的创建和初始化、事件处理函数的注册、游戏的启动等7部分组成。

编程步骤

第一步,首先编写read_from_file(filename)函数,参数filename为《三字经》文本文件的URL(Uniform Resource Locator,统一资源定位符,是对互联网资源的位置和访问方法的一种简洁表示),我们已经为你准备了该文件,URL为:http://202.201.225.74/video/PythonResoure/ProjectResource/other/szj.txt。你应当观察一下该文件的内容和格式,请使用urllib.request.urlopen()方法打开该文件,逐行处理(readlines()可以逐行读入文件,假设读入的内容保存在变量line中,可以用str(line.decode(“utf8”)).split()将一行分解为句子列表),每三个汉字为一个元素存入列表,处理完所有行之后,关闭文件,函数应当返回一个列表,可以用以下调用测试该函数是否满足要求:

print(read_from_file ('http://vquiz.xjau.edu.cn/ProjectResource/other/szj.txt ')[0])

输出应当为:人之初

print(read_from_file (' http://vquiz.xjau.edu.cn/ProjectResource/other/szj.txt ')[491])

输出应当为:宜勉力

text_list = read_from_file (' http://vquiz.xjau.edu.cn/ProjectResource/other/szj.txt')

for text in text_list:

	print(text)

输出应当为492句诗文,1行1句

第二步,编写text_shuffle(text)函数,该函数以字符串text为参数,功能为返回以次序随机的新字符串,当然新字符串中的字符或汉字必须与text参数相同,可以用以下调用测试该函数是否满足要求:

print(text_shuffle (‘人之初’))

输出可能为:人之初、人初之、之初人、之人初、初之人、初人之

第三步,编写generate_current_section_list()函数,每次调用该函数时将从prime_sentence_list列表中取出4句诗词文本并把它们添加到一个新的列表中,同时将这4句诗词文本从prime_sentence_list列表中删除。为了实现一段诗歌中的4句诗词随机从画布底部飞出,我们要用random.shuffle函数对新产生的列表进行混洗处理,请在每句诗词前面加上表示其正确位置的数字代码(0、1、2、3),函数应当返回一个包含4个元素的列表。请用以下调用测试该函数是否满足要求:

prime_sentence_list = read_from_file(’ http://vquiz.xjau.edu.cn/ProjectResource/other/szj.txt ')

print(generate_current_section_list())

print(generate_current_section_list())

print(generate_current_section_list())

输出可能为:

[‘2性相近’, ‘3习相远’, ‘1性本善’, ‘0人之初’]

[‘3贵以专’, ‘2教之道’, ‘1性乃迁’, ‘0苟不教’]

[‘2子不学’, ‘1择邻处’, ‘0昔孟母’, ‘3断机杼’]

请注意0、1、2或3代表一句诗文在一段中的正确位置。每调用一次该函数,诗文下移一段,一段中四句的位置随机变化。

第四步,完善Box类,该类是三字一句文字块的抽象,我们已经提供了该类的属性(私有变量)及其访问方法(getter、setter),你的任务为:

1、完善shuffle_sentence (self)方法,该方法实现文字的混洗功能,可以调用text_shuffle。

2、完善collide(self,moving_object)方法,该方法实现检查该文字块是否和上升的文字块发生碰撞。如果发生碰撞返回True,否则返回False。

3、完善draw(self, canvas) 方法,该方法实现在画布中绘制(显示)文字块的功能,canvas.draw_polygon方法可以会矩形,canvas.draw_text方法可以绘制文本。请注意用不同颜色组合来提示玩家块内文字次序是否正确,也要用颜色区别块间次序是否正确。

4、完善update(self) 方法,利用rising_speed变量对正在上升的文字块显示的位置(self.pos[1])进行更新。

请用以下调用测试Box类是否满足要求:

test_box = Box([120,100], box_width, box_height, ‘人之初’, ‘之人初’, 0)

print(test_box.get_pos())

print(test_box.get_sentence())

print(test_box.get_correct_sentence())

print(test_box.get_order())

print(test_box.get_processed())

test_box.shuffle_sentence()

print(test_box.get_sentence())

输出应当为:

[120, 100]

人之初

之人初

0

False

之初人

第五步,编写draw_all_stopped_box(stopped_box,canvas)函数,stopped_box参数为保存所有已经停止的文字块的集合,请用for循环遍历每个元素,调用它的draw方法完成绘制功能。

第六步,编写check_collision(group, moving_box)函数,group代表所有已经停止的文字块,而moving_box代表正在上升的文字块,请用for循环遍历group集合每个元素, 调用它的collide方法检测是否和moving_box发生碰撞,只要有一个元素和moving_box发生碰撞就返回True,否则返回False。

第七步,完善stop_box(group, moving_box)函数,该函数是游戏逻辑实现的重要函数。

如果moving_box到达顶部或与其它停止的文字块发生碰撞,首先将moving_box的rising属性设置为False,将has_rising_box全局变量设置为False。

检查文字顺序,如果正确,游戏得分增加5分。

将该文字块添加到代表静止块的stopped_box集合中。

如果是四句中的最后一句,检查一行四句的位置,如果正确,游戏得分增加20分,并且从stopped_box删除最后4个文字块完成一行的消解。

如果该块停止使得停止的行数超过10行,设置game_over为True。

第八步,编写draw_game_over_msg(canvas, msg)函数,游戏结束时会调用该函数,在画布的正中间用红色48号字体显示msg代表的信息。

第九步,编写box_spawner()函数,调用该函数会创建一个上升的文字块,请注意事件处理函数注册部分我们有timer = simplegui.create_timer(1000.0, box_spawner)语句,这表明游戏程序每1秒会调用box_spawner()函数1次。

任何时候游戏界面中最多只有一个上升的文字块,因此首先要判断全局变量has_rising_box值,如果为True,表明游戏中有一个正在上升的文字块,因此该函数无需再做什么,否则:

若current_section_list空,调用generate_current_section_list()为其赋值,从current_section_list弹出一个,计算随机位置,调用Box类的构造方法创建一个新的文字块并赋值到全局变量rising_box,最后别忘了正确设置has_rising_box的值。

第十步,编写draw(canvas) 函数,该函数负责屏幕刷新,如果game_over为True,请用draw_game_over_msg函数显示游戏结束画面,否则:

依次调用rising_box的draw方法和update方法实现对上升文字块绘制和位置更新。

然后调用draw_all_stopped_box绘制所有的静止文字块。

最后调用stop_box对发生接触或到达顶部的上升文字块进行处理并更新游戏得分。

第十一步,编写keydown(key)函数,当玩家按下左箭头键时,rising_box的位置左移一个文字块距离,当玩家按下右箭头键时,rising_box的位置右移一个文字块距离,当玩家按下空格键时,rising_box的文字次序随机变换一次。

第十二步,完善start_game()函数,为游戏开始或重新开始初始化全局变量。

一切都搞定后,提交项目之前请注释掉你添加的所有测试代码,保存并运行确认后再提交你的代码。

项目模板

# “决战三字经”游戏

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个元素,四句为一行(一段),句间隔为空格
    pass


def text_shuffle(text):
    """打乱文字的次序"""
    pass


def draw_all_stopped_box(boxes, canvas):
    """绘制所有的停止块"""
    pass


def generate_current_section_list():
    """生成当前段落四句诗歌列表"""
    pass


def check_collision(group, moving_box):
    """检查移动块和所有停止块是否发生碰撞"""
    pass


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, moving_box):
    """停止移动块"""
    global has_rising_box, game_over, score, label
    pass
    

def draw_game_over_msg(canvas, msg):
    """绘制游戏结束信息"""
    pass


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):
        """打乱字序"""
        pass

    def collide(self, moving_object):
        """检查是否和移动块发生碰撞"""
        pass

    def draw(self, canvas):
        """绘制自己"""
        pass

    def update(self):
        """更新垂直位置,使其向上移动"""
        pass
        

def box_spawner():
    """时钟事件处理函数,生产一个上升的方块"""
    global has_rising_box, rising_box, current_section_list, game_over
    pass


def draw(canvas):
    """屏幕刷新事件处理函数"""
    pass


def key_down(key):
    """处理键盘按下事件的函数"""
    pass


def start_game():
    """为游戏开始或重新开始初始化全局变量,也是鼠标点击按钮的事件处理函数"""
    global prime_sentence_list, stopped_box, rising_box, current_section_list, has_rising_box, game_over, score
    pass
    

# 创建窗口初始化画布
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()  # 显示窗口
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐