有这样一个需求:使用python实现一个游戏,一共有10个问题,依次回答每个问题,每个用户可以输入问题的答案,但是互相不能看到,有一个管理员可以看到所有人的答案,并且当所有人都填写完成后可以公布所有人的答案,并且打分。在回答的下面有一个得分表,每打完一轮问题的得分则实时计算总得分和排名。限制一个IP只能登录一个用户。
下面给出一个基于 Flask 的简化示例,演示如何用 Python 实现这样一个游戏的核心功能,主要包括:
- 10 个问题的答题流程。
- 用户只能看到自己的答案,管理员可以看到所有人的答案。
- 当所有人都填写完成后,管理员可以公布所有人的答案并进行打分。
- 显示得分表,每轮更新后实时计算总得分和排名。
- 限制同一个 IP 地址只能登录一个用户。
为演示方便,以下示例仅做最小可行的流程说明,使用字典存储用户和答案信息;在实际生产环境中,可以结合数据库、认证机制、前端模板等进行更完善的开发。
主要功能说明
-
注册/登录:
- 用户首次进入时,需要填写用户名进行注册并登录。
- 同一个 IP 地址只允许注册一个用户,后续从同一 IP 再访问则直接视为该用户登录或禁止二次注册。
-
答题:
- 一共 10 个问题,这里演示时以简单的问卷形式呈现。
- 每个用户在提交完所有答案后,才能等待管理员公布结果。
-
管理员查看与公布答案:
- 管理员可以查看所有用户答案。
- 管理员可进行打分,并将所有用户答案与分数公示。
- 每完成一轮题目即可查看实时总得分并进行排名。
-
得分统计与排名:
- 每一轮提交答案后,管理员打分并把分数汇总到用户总分中。
- 根据所有用户的总分动态计算排名并显示。
代码示例
下面的示例使用 Flask 进行演示,提供了若干路由(URL)以完成相应功能。请先安装 Flask:
pip install flask
然后创建一个脚本文件(如 quiz_game.py
),内容如下:
from flask import Flask, request, session, redirect, url_for, render_template_string
import functoolsapp = Flask(__name__)
app.secret_key = "your_secret_key" # 用于 session 加密# 记录哪些 IP 已经注册过用户
ip_to_user = {}# 存储用户信息,包括用户名、答案、分数等
# 结构示例:
# users_data = {
# 'alice': {
# 'answers': ["ans1", "ans2", ...], # 当前轮次的答案
# 'scores': [5, ...], # 历史每一轮的得分
# 'total_score': 5
# },
# 'bob': {...},
# ...
# }
users_data = {}# 定义题目,这里示例 10 个问题
QUESTIONS = ["问题1:你最喜欢的颜色是什么?","问题2:你最喜欢的动物是什么?","问题3:你的故乡在哪里?","问题4:你最喜欢吃什么?","问题5:你最喜欢哪个季节?","问题6:你最喜欢做的运动是什么?","问题7:你最喜欢的电影类型是什么?","问题8:假期里你最想去哪里旅行?","问题9:你希望学习哪项新技能?","问题10:你最喜欢的音乐类型是什么?",
]# 标记当前答题是否开放,如果轮次结束后可以由管理员统一切换
answer_open = True
# 标记这一轮是否已经公布答案
answers_revealed = False# ========== 帮助函数 ==========def login_required(func):"""需要用户已登录,否则跳转到登录页面。"""@functools.wraps(func)def wrapper(*args, **kwargs):if 'username' not in session:return redirect(url_for('login'))return func(*args, **kwargs)return wrapperdef admin_required(func):"""需要管理员权限,否则跳转到登录。此示例简单地将用户名为 'admin' 视为管理员。"""@functools.wraps(func)def wrapper(*args, **kwargs):if session.get('username') != 'admin':return "只有管理员能访问此页面。", 403return func(*args, **kwargs)return wrapperdef get_rankings():"""根据 total_score 得到排行榜信息,返回 [(username, total_score), ...] 从高到低。"""ranking = sorted(users_data.items(), key=lambda x: x[1].get('total_score', 0), reverse=True)# 转换成列表 [(用户名, 总分), ...]return [(user, info['total_score']) for user, info in ranking]# ========== 路由视图 ==========@app.route('/')
def index():"""主页,如果已登录则跳转到答题页面;否则跳转到登录。"""if 'username' in session:return redirect(url_for('quiz'))else:return redirect(url_for('login'))@app.route('/login', methods=['GET', 'POST'])
def login():"""用户登录/注册入口。同一个IP只能注册一个用户,若该IP已注册过,则自动成为该用户或禁止再次注册。"""client_ip = request.remote_addrif request.method == 'POST':username = request.form.get('username', '').strip()if not username:return "用户名不能为空", 400# 如果该IP已经注册过其他用户,则禁止重复注册if client_ip in ip_to_user and ip_to_user[client_ip] != username:return f"该IP({client_ip})已经注册过用户 {ip_to_user[client_ip]},无法重复注册。", 403# 如果该IP没有注册用户或者与现有用户名匹配,则继续ip_to_user[client_ip] = username# 如果用户第一次注册,初始化信息if username not in users_data:users_data[username] = {"answers": [""] * len(QUESTIONS),"scores": [],"total_score": 0}session['username'] = usernamereturn redirect(url_for('quiz'))# GET 请求,返回一个简单的登录表单return render_template_string("""<h2>用户登录/注册</h2><form method="post">用户名:<input type="text" name="username"><br><input type="submit" value="登录"></form>""")@app.route('/quiz', methods=['GET', 'POST'])
@login_required
def quiz():"""答题页面。提交后保存答案。这里简单演示一次性提交 10 个问题。"""global answer_openglobal answers_revealedusername = session['username']if request.method == 'POST':if not answer_open:return "当前轮次答题已关闭,等待管理员开启下一轮或公布结果。", 403# 接收 10 个问题的答案new_answers = []for i in range(len(QUESTIONS)):ans = request.form.get(f'question_{i}', '').strip()new_answers.append(ans)# 保存新的答案users_data[username]['answers'] = new_answersreturn "提交成功!等待管理员公布结果。"# GET 请求时渲染一个简单的表单user_answers = users_data[username].get('answers', [""]*len(QUESTIONS))html_form = """<h2>答题页面</h2>{% if answer_open %}<form method="post">{% for i, question in enumerate(QUESTIONS) %}<div><label>{{ question }}</label><br><input type="text" name="question_{{ i }}" value="{{ user_answers[i] }}"></div><br>{% endfor %}<input type="submit" value="提交答案"></form>{% else %}<p>答题已关闭,请等待管理员开启下一轮或查看最终结果。</p>{% endif %}"""return render_template_string(html_form,QUESTIONS=QUESTIONS,user_answers=user_answers,answer_open=answer_open)@app.route('/admin_view')
@admin_required
def admin_view():"""管理员查看所有用户答案的页面(仅管理员可访问)。"""html = "<h2>管理员查看所有答案</h2>"for user, info in users_data.items():html += f"<h3>用户:{user}</h3>"answers = info.get('answers', [])for i, ans in enumerate(answers):html += f"问题{i+1}: {ans}<br>"return html@app.route('/admin_score', methods=['GET', 'POST'])
@admin_required
def admin_score():"""管理员对本轮答案进行打分并公布。一次性给所有用户打分,然后系统更新总分、清空当前答案。"""global answer_openglobal answers_revealed# GET:显示一个打分的页面if request.method == 'GET':html = """<h2>管理员打分</h2><form method="post">"""for user in users_data:html += f"<label>给用户 {user} 的本轮答案打分:</label>"html += f"<input type='number' name='score_{user}' value='0' min='0' max='100'><br><br>"html += "<input type='submit' value='提交分数'>"html += "</form>"return html# POST:接收管理员给每个用户的分数,更新 total_scorefor user in users_data:score_str = request.form.get(f'score_{user}', '0')try:score = int(score_str)except ValueError:score = 0# 更新每个用户的分数信息users_data[user]['scores'].append(score)users_data[user]['total_score'] += scoreanswers_revealed = Trueanswer_open = False # 关闭当前轮次答题,等待管理员手动开启下一轮(如果有的话)return redirect(url_for('results'))@app.route('/results')
@login_required
def results():"""公布所有用户本轮答案与分数(如果管理员已打分的话)。并显示当前排行榜。"""if not session.get('username'):return redirect(url_for('login'))if not users_data:return "暂无答案"html = "<h2>当前轮次结果</h2>"# 只有在管理员打完分之后才公布if not all(users_data[user]['scores'] for user in users_data):html += "<p>管理员尚未打分,无法显示分数。</p>"else:# 显示最新一轮的分数(即 scores 列表中的最后一项)for user, info in users_data.items():latest_score = info['scores'][-1] if info['scores'] else 0answers = info.get('answers', [])html += f"<h3>用户:{user}</h3>"for i, ans in enumerate(answers):html += f"问题{i+1}: {ans}<br>"html += f"<strong>本轮得分: {latest_score}</strong><br>"# 显示排行榜html += "<h2>排行榜</h2>"ranking = get_rankings()rank_str = ""for idx, (user, total_score) in enumerate(ranking, start=1):rank_str += f"{idx}. {user}:{total_score}分<br>"html += rank_strreturn html@app.route('/admin_open_new_round')
@admin_required
def admin_open_new_round():"""管理员开启新一轮答题:清空当前答案,answer_open = True, 并 answers_revealed = False。"""global answer_open, answers_revealed# 把当前答案列表清空(如果希望保留可以改成其他逻辑)for user, info in users_data.items():info['answers'] = [""] * len(QUESTIONS)answer_open = Trueanswers_revealed = Falsereturn "新一轮答题已开启!"if __name__ == '__main__':# 启动Flask服务app.run(debug=True, host='0.0.0.0', port=5000)
功能说明
ip_to_user
字典用于记录 IP → 用户名 的映射,确保同一 IP 无法注册多个账号。users_data
用于保存所有用户的状态,包括:- 当前轮的答案
answers
- 每一轮的得分列表
scores
- 总分
total_score
- 当前轮的答案
answer_open
控制当前轮次是否允许答题,answers_revealed
标记本轮答案是否已公布。- 提供了如下 路由:
/login
:用户登录/注册页面。/quiz
:用户答题页面(一次性答完 10 道题)。/admin_view
:管理员查看所有答案(仅管理员可访问)。/admin_score
:管理员对所有用户打分并公布结果(仅管理员可访问)。/results
:已打分后的结果页面,显示所有用户本轮答案、分数以及排行榜。/admin_open_new_round
:管理员开启下一轮答题,清空当前答案,重新开放答题。
使用方式
- 安装依赖并运行:
pip install flask python quiz_game.py
- 浏览器访问
http://<服务器IP>:5000
,若未登录则自动跳转到/login
。 - 管理员可以使用特殊用户名(如
admin
)登录,以访问管理员路由:http://<服务器IP>:5000/admin_view
查看所有人的答案http://<服务器IP>:5000/admin_score
给大家打分http://<服务器IP>:5000/admin_open_new_round
开启下一轮
- 普通用户只能查看自己的答案并进行答题,分数公布后可查看总榜。
后续完善建议
- 数据库:将用户数据、IP 映射等存入数据库(如 SQLite、MySQL、PostgreSQL),确保数据持久化。
- 用户认证:对登录机制进行加固,比如密码验证、单点登录、令牌校验等,防止恶意用户冒名顶替。
- 前端界面:可使用 Flask 的模板功能(或前端框架)美化页面,并提供更加友好易用的交互。
- 并发/部署:考虑使用 uWSGI、Gunicorn 等部署在正式服务器上,提高并发能力。
这个示例主要演示了核心逻辑流程和数据结构,大家可以根据实际需求进行拓展和改进。祝你开发顺利!