python项目之猫咪藏在哪个房间

猫咪藏在哪个房间

程序说明

本项目我们将用Python语言设计一个计算机程序来模拟“猫咪藏在哪个房间”游戏,该程序中,计算机代替你朋友的角色,而你的角色不变。你将通过一个输入框和几个按钮来操作你的程序,在该项目中,计算机的回应将显示在专用的输出控制台,先不要关心画布的反应。其实,构造每个项目的初始版本时,把一些有用的信息输出到控制台是一种行之有效的开发策略,也就是说,先集中精力实现正确的程序逻辑,然后设法在画布上让信息以某种优美的形式展示出来,因为调试图形输出的逻辑错误有时候极具挑战。程序的文件名称为GuessRoomNumber.py,程序除了要用到前一个项目“杠子老虎鸡虫”已经熟悉的Python语言功能之外,还要使用SimpleGUITk来创建窗口、画布、输入框、按钮等。

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

了解二分查找(折半查找)的秘密
理解计算机程序的运行是如何受事件驱动的
增强逻辑思维能力
培养解决问题的能力

编码步骤

我们已经为该小项目提供了一个基本模板,我们建议基础版的“猫咪藏在哪个房间”开发策略为:

1、确定一组存储游戏状态的全局变量。显而易见,你需要一个全局变量来保存程序产生的秘密房间号码,建议该变量的名称为secret_number。为了扩展基础版,你还需要其它一些全局变量。

2、弄清楚如何在给定的low(下限)至high(上限)范围内产生一个随机秘密数字,及秘密房间号。在谈及范围时,我们遵循Python的标准,即包含下限,排除上限,数学上表示为[low, high)。例如[0, 3)意味着该范围包含0、1、2三个数字。我们建议在开始编码时将范围设置为[0,25),即25个房间。

提示:查看random模块包中的函数,你会发现产生这样的随机数非常容易,建议在Python控制台先测试要使用的函数,弄明白它的作用后再往你的项目里添加代码。

3、搞清楚如何利用simpleguitk模块包创建一个文本输入框。你将使用该文本输入框来获取游戏玩家输入的猜测数字。

4、编写事件处理函数guess_room_number(input),参数input保存着玩家输入的猜测值,将该值与秘密房间号进行比较并输出恰当的回应。注意,input为字符串类型,因此在比较之前,你必须将其转化为整型数字。如果玩家猜中了房间号,除了输出恰当的信息之外,请补充输出“请点击房间按钮重新开始游戏”,之后玩家再猜,均输出“请点击房间按钮重新开始游戏”。

提示:课程视频中我们介绍过字符串转化为整型数字的方法。

5、至此,玩家可以无限制的猜测下去,直到猜对为止,猜中后如果希望继续玩一把,必须关闭程序,然后重新运行程序。

6、编写new_game()函数,将产生秘密房间号的代码移到该函数中,也就是说,调用new_game()函数将会计算秘密房间号并将其赋值给一个全局变量,该函数也应当输出一些恰当的信息提示玩家。完成该函数后,你就可以在启动窗口的代码之前调用new_game()。

以上为“猫咪藏在哪个房间”游戏的最初级版本,下面为你的项目添加额外的功能,为了获得满分,你必须完成2个增强的功能:

第1个增强功能:使用simpleguitk模块包添加重新启动游戏的按钮,这样你就无需在玩家猜中后先关闭程序,然后重新运行程序。你必须添加三个按钮:“25个房间”、“36个房间”、“100个房间”,从而允许玩家选择秘密房间号的范围。玩家在游戏运行的任何时刻点击任何一个按钮将重新开始一轮游戏并输出恰当的信息。每个按钮的事件处理函数要为秘密房间号的上限范围(应当是一个全局变量)设置对应的值,然后调用new_game()在新的范围内重新设置秘密房间号,最后设置标志新一轮游戏已经开始的全局变量为True。

在玩该游戏时,可能你已经注意到,如果猫咪藏在25个房间中的某一个,即猜测的范围为[0,25),首先猜12是一个好注意,如果计算机的回应为“太小了”,秘密房间号一定在[13,25)范围内,然后最好猜19,以此类推。这种每次缩小一半猜测范围的技术就是计算机科学领域中著名的二分查找算法。

第2个增强功能:为游戏程序添加限制玩家猜测次数的功能,每次猜测后,你的程序应当补充输出剩余的猜测机会,一旦玩家用完了规定的猜测机会,玩家失败,游戏程序输出相应的提示信息,玩家如果想继续游戏,必须点击房间按钮。

如果玩家按照二分查找策略来猜测,在[low, high)范围内,要保证玩家在n次之内猜中,n必须为满足2 ** n >= high - low + 1的最小整数。因此,对于范围[0,25),n为5,[0,36),n为6,[0,100),n为7,我们可以在三个按钮的事件处理函数中为表示剩余猜测机会的全局变量赋予相应的值(5、6、7),当然我们也可以利用math.log and math.ceil函数通过low和high计算n。

游戏程序初次启动时,猜测的范围应当为[0,25),一轮游戏结束后(玩家猜中后或玩家用完了猜测机会),应提示玩家点击房间按钮开始新一轮游戏,如果玩家此时没有点击按钮继续进行猜测(直接按回车,或输入新的数字再按回车),应当提示玩家点击房间按钮开始新一轮游戏。只要玩家点击房间按钮,当前一轮游戏无条件结束,在按钮载明的范围立即开始新一轮游戏。

项目模板

# "猫咪藏在哪个房间"小项目程序模板
# 程序的输入来自按钮和输入框

import simpleguitk as gui  # 简单用户图形界面接口
import random              # 用random.randrange(range_high)随机生成猫咪要藏的房间号
import math                # 用math.log(x, base)计算猜中所需的最少次数

# 初始化全局变量
secret_number = None                         # 每个回合计算机随机产生的秘密数字
range_high = 25                              # 房间号的上限

new_game_started = True                      # 新一轮游戏是否开始
remaining_guesses = 0                        # 一个回合剩余的猜测次数


canvas_height = 500                          # 画布高度,单位为像素
canvas_width = 500                           # 画布宽度,单位为像素

room_list = []                               # 所有房间的状态
cat_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project2/cat.png")  # 猫咪图片


def new_game():
    """启动或重新启动游戏的辅助函数"""
    # 添加你自己的代码后删除pass
    pass

    # 初始化所有房间,请不要修改以下3行代码
    room_list.clear()
    for i in range(range_high):
        room_list.append(False)


# 为控制面板的控件定义事件处理函数
def range25():
    # 设置房间号的范围为[0,25)并重新开始游戏

    # 添加你自己的代码后删除pass
    pass


def range36():
    # 设置房间号的范围为[0,36)并重新开始游戏

    # 添加你自己的代码后删除pass
    pass


def range100():
    # 设置房间号的范围为[0,100)并重新开始游戏

    # 添加你自己的代码后删除pass
    pass

secret_number = random.randrange(25)


def guess_room_number(user_input):
    """文本输入框控件的处理函数,也是游戏的主要逻辑实现的函数"""

    # 添加你自己的代码后删除pass
    pass
    update_room(int(user_input))      # 更新房间状态,请不要修改这行代码

# 创建窗口
frame = gui.create_frame("猫咪藏在哪个房间", canvas_width, canvas_height)


# 注册控件事件
# 添加你自己的代码后删除pass
pass

# 调用new_game初始化一些全局变量并向终端输出新一轮游戏开始的相关信息
new_game()


# 请别忘记对照评分标准核对你最终完成的程序
# 请不要修改这行之后的所有代码
def draw(canvas):
    """画布显示刷新事件的处理函数"""
    # 请不要修改该函数
    root = int(math.sqrt(range_high))
    length = canvas_width // root
    for row in range(root):
        for col in range(root):
            index = root * row + col
            text_width = frame.get_canvas_textwidth(str(index), 12, 'sans-serif')
            top_left = [length * col,length * row]
            top_right = [length * (col + 1),length * row]
            bottom_right = [length * (col + 1),length * (row + 1)]
            bottom_left = [length * col,length * (row + 1)]
            if not room_list[index]:
                canvas.draw_polygon([top_left, top_right, bottom_right, bottom_left], 1, 'Red', 'Green')
                canvas.draw_text(str(index), (top_left[0] + (length - text_width) / 2, top_left[1] + length - 2), 12, 'White', 'sans-serif')
            else:
                canvas.draw_polygon([top_left, top_right, bottom_right, bottom_left], 1, 'Red', 'Blue')
                canvas.draw_text(str(index), (top_left[0] + (length - text_width) / 2, top_left[1] + length - 2), 12, 'White', 'sans-serif')
                if index != secret_number:
                    no_cat = frame.get_canvas_textwidth('没有猫', 12, 'sans-serif')
                    canvas.draw_text('没有猫', (top_left[0] + (length - no_cat) / 2, top_left[1] + length / 2), 12, 'White', 'sans-serif')
                else:
                    canvas.draw_image(cat_image, [256,256], [512,512],[top_left[0] + length//2,top_left[1]+length//2 ],[length, length])


def update_room(guess):
    """更新房间的状态"""
    # 请不要修改该函数
    if guess == secret_number:
        for i in range(range_high):
            room_list[i] = True
    elif guess < secret_number:

        if remaining_guesses == 0:
            for i in range(range_high):
                room_list[i] = True
        else:
            for i in range(0,guess + 1):
                room_list[i] = True
    else:
        if remaining_guesses == 0:
            for i in range(range_high):
                room_list[i] = True
        else:
            for i in range(guess, range_high):
                room_list[i] = True

frame.set_draw_handler(draw)      # 注册显示刷新处理事件,每秒调用draw函数60次
frame.start()                     # 启动窗口框架

以下为完整代码

# "猫咪藏在哪个房间"小项目程序模板
# 程序的输入来自按钮和输入框

import simpleguitk as gui  # 简单用户图形界面接口
import random              # 用random.randrange(range_high)随机生成猫咪要藏的房间号
import math                # 用math.log(x, base)计算猜中所需的最少次数

# 初始化全局变量
secret_number = None                         # 每个回合计算机随机产生的秘密数字
range_high = 25                              # 房间号的上限
new_game_started = True                      # 新一轮游戏是否开始
remaining_guesses = 0                        # 一个回合剩余的猜测次数
canvas_height = 500                          # 画布高度,单位为像素
canvas_width = 500                           # 画布宽度,单位为像素
room_list = []                               # 所有房间的状态
cat_image = gui.load_image("http://202.201.225.74/video/PythonResoure/ProjectResource/images/project2/cat.png")  # 猫咪图片

def new_game():
    """启动或重新启动游戏的辅助函数"""
    # 添加你自己的代码后删除pass
    global secret_number, new_game_started
    if new_game_started == True:
        new_game_started = False
        range25()
    else:
        secret_number = random.randrange(range_high)
    # 初始化所有房间,请不要修改以下3行代码
    room_list.clear()
    for i in range(range_high):
        room_list.append(False)

# 为控制面板的控件定义事件处理函数
def range25():
    # 设置房间号的范围为[0,25)并重新开始游戏
    global range_high, remaining_guesses
    print('新的一轮游戏开始')
    print('您应当在0和24之间猜一个数字')
    print('您拥有5次机会')
    range_high = 25
    remaining_guesses = int(math.log(25, 2)) + 1
    new_game()

def range36():
    # 设置房间号的范围为[0,36)并重新开始游戏
    global range_high, remaining_guesses
    print('新的一轮游戏开始')
    print('您应当在0和36之间猜一个数字')
    print('您拥有6次机会')
    range_high = 36
    remaining_guesses = int(math.log(36, 2)) + 1
    new_game()

def range100():
    # 设置房间号的范围为[0,100)并重新开始游戏
    global range_high, remaining_guesses
    print('新的一轮游戏开始')
    print('您应当在0和100之间猜一个数字')
    print('您拥有7次机会')
    range_high = 100
    remaining_guesses = int(math.log(100, 2)) + 1
    new_game()
    secret_number = random.randrange(25)

secret_number = random.randrange(25)

def guess_room_number(user_input):
    """文本输入框控件的处理函数,也是游戏的主要逻辑实现的函数"""

    global remaining_guesses
    user_input = int(user_input)
    if remaining_guesses == 0:
        print("机会已用完,请点击房间号重新开始")
    else:
        if user_input == secret_number:
            print("正确,请点击房间号重新开始")
        elif user_input > secret_number:
            print("太大了")
            remaining_guesses -= 1
            print('您还有' + str(remaining_guesses) + '机会')
        elif user_input < secret_number:
            print("太小了")
            remaining_guesses -= 1
            print('您还有' + str(remaining_guesses) + '机会')
    update_room(int(user_input))      # 更新房间状态,请不要修改这行代码

# 创建窗口
frame = gui.create_frame("猫咪藏在哪个房间", canvas_width, canvas_height)

# 注册控件事件
# 添加你自己的代码后删除pass
frame.add_button("25个房间", range25, 100)
frame.add_button("36个房间", range36, 100)
frame.add_button("100个房间", range100, 100)
frame.add_input("猜测房间", guess_room_number, 100)

# 调用new_game初始化一些全局变量并向终端输出新一轮游戏开始的相关信息
new_game()

def draw(canvas):
    """画布显示刷新事件的处理函数"""
    root = int(math.sqrt(range_high))
    length = canvas_width // root
    for row in range(root):
        for col in range(root):
            index = root * row + col
            text_width = frame.get_canvas_textwidth(str(index), 12, 'sans-serif')
            top_left = [length * col,length * row]
            top_right = [length * (col + 1),length * row]
            bottom_right = [length * (col + 1),length * (row + 1)]
            bottom_left = [length * col,length * (row + 1)]
            if not room_list[index]:
                canvas.draw_polygon([top_left, top_right, bottom_right, bottom_left], 1, 'Red', 'Green')
                canvas.draw_text(str(index), (top_left[0] + (length - text_width) / 2, top_left[1] + length - 2), 12, 'White', 'sans-serif')
            else:
                canvas.draw_polygon([top_left, top_right, bottom_right, bottom_left], 1, 'Red', 'Blue')
                canvas.draw_text(str(index), (top_left[0] + (length - text_width) / 2, top_left[1] + length - 2), 12, 'White', 'sans-serif')
                if index != secret_number:
                    no_cat = frame.get_canvas_textwidth('没有猫', 12, 'sans-serif')
                    canvas.draw_text('没有猫', (top_left[0] + (length - no_cat) / 2, top_left[1] + length / 2), 12, 'White', 'sans-serif')
                else:
                    canvas.draw_image(cat_image, [256,256], [512,512],[top_left[0] + length//2,top_left[1]+length//2 ],[length, length])

def update_room(guess):
    """更新房间的状态"""
    if guess == secret_number:
        for i in range(range_high):
            room_list[i] = True
    elif guess < secret_number:

        if remaining_guesses == 0:
            for i in range(range_high):
                room_list[i] = True
        else:
            for i in range(0,guess + 1):
                room_list[i] = True
    else:
        if remaining_guesses == 0:
            for i in range(range_high):
                room_list[i] = True
        else:
            for i in range(guess, range_high):
                room_list[i] = True

frame.set_draw_handler(draw)      # 注册显示刷新处理事件,每秒调用draw函数60次
frame.start()                     # 启动窗口框架
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值