有这样一个需求:使用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 functools
app = 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 wrapper
def admin_required(func):
"""需要管理员权限,否则跳转到登录。此示例简单地将用户名为 'admin' 视为管理员。"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
if session.get('username') != 'admin':
return "只有管理员能访问此页面。", 403
return func(*args, **kwargs)
return wrapper
def 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_addr
if 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'] = username
return 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_open
global answers_revealed
username = 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_answers
return "提交成功!等待管理员公布结果。"
# 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_open
global 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_score
for 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'] += score
answers_revealed = True
answer_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 0
answers = 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_str
return 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 = True
answers_revealed = False
return "新一轮答题已开启!"
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 等部署在正式服务器上,提高并发能力。
这个示例主要演示了核心逻辑流程和数据结构,大家可以根据实际需求进行拓展和改进。祝你开发顺利!