选项移动后仍正确判断答案

PythonBeginner
立即练习

介绍

制作一款可玩的本地问答程序,让选项移动后仍能正确判断答案。你需要了解 Python 函数、列表、字典、条件和循环。本实验会解释 JSON、随机抽取和输入校验。预备的终端引擎负责展示与反馈,你在 logic.py 中实现三条规则。

打开 WebIDE 的 Terminal 菜单,再选择 New Terminal(窄窗口中位于 More 下)。所有命令都在该终端执行。保持 engine.py、quiz.py、demo.py 和 bank.json 不变,只编辑 logic.py。预计阅读与练习共 40 分钟;这不是实测的初学者用时。

抽取题目并整体移动选项

本步骤先玩两道已知顺序的题,再加入随机抽取,同时保留身份关系。在 WebIDE 终端中,cd 切换工作目录,python3 运行 Python 文件。

cd /home/labex/project
python3 demo.py

先输入 1 选择 Sun,再输入 2 选择 Moon。两题都显示 Correct!。这个固定顺序的示范已准备好;你制作的可复用问答还会移动选项。

cat 显示文本文件:

cat bank.json

JSON 用 [] 表示列表、{} 表示字典,字符串使用双引号。每题包含 question_id、prompt、options 和 correct_option_id。每个选项将 option_id 与 text 配对。ID 稳定不变,屏幕序号只是位置。sky 和 tide 都提供 Sun/Moon,但 Sun 只在 sky 题中正确。选项 ID 仅在一道题内唯一,所以身份是题目与选项的组合。这些预备题库中的题目 ID,以及每题内部的选项文字,都是唯一的。

rng 是传入的随机生成器对象。它的 sample(items, count) 返回一个不重复抽取元素的新列表,但不会修复重复的题目 ID。shuffle(items) 会原地移动列表,所以先复制选项。整体移动字典,才能让每个 ID 始终跟随其文字。请求的题数为正数;用 min(count, len(questions)) 将其限制在题库大小以内。这里的随机性用于变化玩法,不提供安全保证。可以采用等价的抽样或打乱方法,不要求固定种子或顺序。

下面的 here-document 写入 Python 文本:> 替换 logic.py,带引号的 <<'PY' 让内容按原样写入,直到最后的 PY。请运行整个代码块,包括最后一行。它把 starter 替换为这两个函数,下一步再加入输入函数。

cat > logic.py <<'PY'
def choose_questions(questions, count, rng):
    return rng.sample(questions, min(count, len(questions)))


def move_options(question, rng):
    options = question["options"].copy()
    rng.shuffle(options)
    return options
PY

现在 choose_questions 返回有上限的题目集合,move_options 返回重排的选项对象而不修改题库。如果终端显示续行提示,请在单独一行输入最后的 PY。

将有效序号映射回选项 ID

本步骤把屏幕上的选择转换为稳定选项 ID。预备引擎传入 ask(输入)和 tell(输出)函数。ask 返回文本,strip() 去除两端空白,enumerate(..., start=1) 将对象与从 1 开始的显示序号配对。与 str(position) 比较文本,可阻止 oops、-1、0 和越界序号提交。只接受屏幕显示的写法:1,而不是 01。q 在提交前退出。有效答案只返回一次,否则 while 循环继续询问。

在同一终端中,>> 追加这个函数,不替换已有的两个函数:

cat >> logic.py <<'PY'
def read_answer(options, ask, tell):
    while True:
        text = ask("Answer (number or q): ").strip()
        if text.lower() == "q":
            return None
        for position, option in enumerate(options, start=1):
            if text == str(position):
                return option["option_id"]
        tell("Enter one displayed number, or q to stop.")
PY

游玩全部可用题目。--count 指定正数上限;100 仍然只会抽取题库中的三题。不带 --ordered 时,题目和选项的位置会变化。

python3 quiz.py bank.json --count 100

在第一个提示处依次尝试 oops、-1、0 和 99。每次都会显示 Enter one displayed number, or q to stop.,并重新询问同一道题。然后按文字回答所有题:恒星选 Sun,潮汐选 Moon,从土壤吸水选 Root。每次都读取当前显示的序号。反馈应与你的选择一致,最终结果为:

Score: 3/3 answered

再开始一个较短的回合,立即输入 q:

python3 quiz.py bank.json --count 2
Score: 0/0 answered

未答题不会写入答案,也不算答错。预备引擎只提交一次,根据当前题目与选项的关系给出反馈并计分,不保存屏幕序号。如果文件名输错,Quiz error: ... 和非零退出表示没有成功完成游戏;用 ls 查看文件名,再运行上面的准确命令。如果 Python 报语法错误,重新执行对应的完整 here-document,无需重置环境。

总结

你制作了可复用、可游玩的问答程序,实现了有限随机抽题和稳定的答案映射。本单元不保存记录。