
本文讲解如何在 flask 中通过 http 请求-响应循环与 session 协作,替代传统 while 循环,实现分步、可中断、状态持久的交互式游戏逻辑(如法语单词猜测),特别适用于面向听障儿童的教育类 web 应用。
本文讲解如何在 flask 中通过 http 请求-响应循环与 session 协作,替代传统 while 循环,实现分步、可中断、状态持久的交互式游戏逻辑(如法语单词猜测),特别适用于面向听障儿童的教育类 web 应用。
在 Flask 这类基于请求/响应模型的 Web 框架中,无法直接在服务端“暂停”一个 while 循环并等待用户点击“是/否”后再继续执行下一次迭代——因为 Python 进程在完成一次 HTTP 响应后即释放上下文,而浏览器端的用户操作(如点击按钮)必须触发全新的 HTTP 请求才能再次激活服务端逻辑。因此,将游戏流程“拆解为多个独立请求步骤”,并利用 session 在请求间安全地保存中间状态(如当前猜测字母、已猜对位置、尝试次数、目标单词等),才是符合 Web 架构的正确设计范式。
✅ 核心思路:用“请求跳转”模拟循环迭代
每一轮猜测(发送一个字母或单词 → 等待用户反馈 → 更新状态 → 进入下一轮)对应一个独立的 Flask 路由处理函数。该函数:
- 从 session 中读取当前游戏状态;
- 根据业务规则生成本次要展示的字母或单词(复用你原有算法逻辑);
- 渲染 HTML 页面,显示当前猜测项 + “是/否”按钮;
- 用户点击后,表单提交到同一或新路由,携带反馈结果(如 answer=yes),服务端据此更新 session 并决定下一步跳转(继续猜、切换为猜词、判定胜利/失败)。
? 关键实践:状态初始化与分步路由设计
以下是一个精简但生产就绪的结构示例,无缝衔接你已有的 liste_mots() 和难度选择逻辑:
# main.py(关键片段)
from flask import Flask, render_template, request, redirect, url_for, session
import random
import math
app = Flask(__name__)
app.secret_key = 'your_secret_key' # 生产环境请使用 secrets.token_hex()
def liste_mots(path_file):
# 保持你原有的词典解析逻辑(略)
@app.route('/commencer_partie/<difficulte>/<word>')
def commencer_partie(difficulte, word):
"""初始化游戏会话并跳转至首步猜测"""
dico = liste_mots("mots.txt")
mots = dico[difficulte]
if word not in mots:
return "Invalid word!", 400
# 初始化完整游戏状态
letters = list(word)
word_length = len(letters)
letter_limit = math.floor(0.6 * word_length)
session.update({
'target_word': word,
'guessed_letters': ['_'] * word_length,
'current_turn': 0,
'letter_limit': letter_limit,
'common_letters': list("eastirnulodmcpévhgfb"),
'uncommon_letters': list("qjàxèêzykôûwâîüùëœçï"),
'alphabet': list("eastirnulodmcpévhgfbqjàxèêzykôûwâîüùëœçï"),
'difficulty': difficulte,
'step': 'letter' # 初始阶段:猜字母
})
return redirect(url_for('display_step'))
@app.route('/step', methods=['GET', 'POST'])
def display_step():
"""统一入口:根据 session 状态渲染当前步骤,并处理用户反馈"""
# 必要的状态校验
required_keys = ['target_word', 'guessed_letters', 'current_turn', 'letter_limit']
if not all(k in session for k in required_keys):
return redirect(url_for('menu'))
word = session['target_word']
guessed = session['guessed_letters']
turn = session['current_turn']
limit = session['letter_limit']
step = session.get('step', 'letter')
# ✨ 核心:复用你原有的智能猜测逻辑(重构为纯函数)
if step == 'letter':
# 调用你的字母选择算法(传入当前状态,返回 chosen_letter)
current_letter = select_next_letter(
word=word,
guessed=guessed,
turn=turn,
common_letters=session['common_letters'],
uncommon_letters=session['uncommon_letters'],
alphabet=session['alphabet']
)
session['current_letter'] = current_letter
template = 'display_letter.html'
context = {'letter': current_letter}
else: # step == 'word'
# 生成可能单词列表(同你原逻辑)
possible_words = [w for w in liste_mots("mots.txt")[session['difficulty']]
if len(w) == len(word) and all(c in w or c == '_' for c in guessed)]
if possible_words:
current_word = random.choice(possible_words)
session['current_word'] = current_word
template = 'display_word.html'
context = {'word': current_word}
else:
# 无候选词,强制结束
session['game_result'] = 'exhausted'
return redirect(url_for('game_over'))
if request.method == 'POST':
answer = request.form.get('answer') # 'yes' or 'no'
# ✅ 更新状态(关键!)
if step == 'letter':
if answer == 'yes':
# 更新 guessed_letters
indices = [i for i, c in enumerate(word) if c == current_letter]
for i in indices:
guessed[i] = current_letter
session['guessed_letters'] = guessed
# 移除已用字母
if current_letter in session['common_letters']:
session['common_letters'].remove(current_letter)
if current_letter in session['uncommon_letters']:
session['uncommon_letters'].remove(current_letter)
if current_letter in session['alphabet']:
session['alphabet'].remove(current_letter)
else:
session['current_turn'] += 1
# 判定是否切换阶段或结束
true_guessed = len(guessed) - guessed.count('_')
if true_guessed >= limit or session['current_turn'] >= 8:
session['step'] = 'word'
elif session['current_turn'] >= 10:
session['game_result'] = 'lost'
return redirect(url_for('game_over'))
else: # word step
if answer == 'yes':
session['game_result'] = 'won'
return redirect(url_for('game_over'))
else:
session['current_turn'] += 1
if session['current_turn'] >= 10:
session['game_result'] = 'lost'
return redirect(url_for('game_over'))
return redirect(url_for('display_step')) # 进入下一轮
return render_template(template, **context)? 对应前端模板(display_letter.html)
<!-- templates/display_letter.html -->
<h2>Étape {{ session.current_turn + 1 }} : Devine une lettre !</h2>
<p>La lettre proposée est : <strong>{{ letter }}</strong></p>
<p>Votre mot : {{ session.guessed_letters | join(' ') }}</p>
<form method="post">
<button type="submit" name="answer" value="yes">✅ Oui, elle est dans le mot !</button>
<button type="submit" name="answer" value="no">❌ Non, elle n'est pas dedans.</button>
</form>
{% if session.current_turn >= 8 %}
<p><em>⚠️ À partir du prochain tour, l'ordinateur devinera des mots entiers.</em></p>
{% endif %}⚠️ 重要注意事项
- Session 安全性:session 数据默认签名存储于客户端 Cookie,敏感信息(如目标单词)不应明文存入。生产环境建议改用服务器端 session(如 Flask-Session + Redis),或仅存哈希/索引,单词本身从数据库按需加载。
- 状态一致性:每次请求都应做 session 键存在性检查,缺失则重定向至起始页,避免因刷新/后退导致状态错乱。
- 并发与超时:单用户会话天然串行,但需设置 session.permanent = True 并配置 PERMANENT_SESSION_LIFETIME 防止长时间闲置失效。
- 可访问性优化:针对听障儿童,确保所有按钮有清晰文字标签、足够对比度、键盘可导航,并为每个猜测步骤提供视觉反馈(如高亮已猜对位置)。
✅ 总结
你无需“运行一个长 while 循环”,而是将游戏逻辑声明式地映射到 HTTP 生命周期上:每个 request → response 是一次原子操作,session 是跨越它们的共享内存。这种模式不仅解决了你当前的值为空问题,更赋予应用天然的容错性(用户可随时刷新)、可追踪性(每步 URL 可记录)和可扩展性(未来可轻松加入计时、成就、多玩家等特性)。现在,只需将你的核心算法封装为 select_next_letter() 和 generate_candidate_words() 等无副作用函数,并在 display_step 中按需调用,即可构建出流畅、健壮、符合教育场景需求的 Flask 游戏。


















