Files
tg-spam-guard/services/game_service.py
T
2026-07-07 10:32:57 +08:00

130 lines
4.7 KiB
Python

"""小游戏服务"""
import random
import logging
from datetime import datetime
from db.models import GameScore
logger = logging.getLogger("spam_guard")
TRIVIA_QUESTIONS = [
{"q": "收割机项目的 GitHub 地址是?", "a": "github.com/ngfchl/go-harvest", "opts": ["github.com/ngfchl/go-harvest", "github.com/ngfchl/harvest", "github.com/harvest/go-harvest"]},
{"q": "以下哪个不是 PT 站的常见等级?", "a": "Diamond", "opts": ["User", "Power User", "Diamond", "Elite"]},
{"q": "Docker 默认的日志驱动是?", "a": "json-file", "opts": ["json-file", "syslog", "journald", "fluentd"]},
]
SHOP_ITEMS = {
"1": {"name": "补签卡", "cost": 50, "desc": "预留权益:后续可用于补签"},
"2": {"name": "群内称号券", "cost": 80, "desc": "预留权益:联系管理员兑换称号"},
"3": {"name": "好运盲盒", "cost": 30, "desc": "兑换后记录一次好运盲盒"},
}
async def get_or_create_score(user_id: int, username: str, game_type: str) -> GameScore:
score, _ = await GameScore.get_or_create(
user_id=user_id, game_type=game_type,
defaults={"username": username},
)
if username and score.username != username:
score.username = username
await score.save()
return score
async def get_trivia_question() -> dict:
return random.choice(TRIVIA_QUESTIONS)
async def check_trivia_answer(user_id: int, username: str, answer: str, correct_answer: str) -> dict:
score = await get_or_create_score(user_id, username, "trivia")
score.total += 1
is_correct = answer.strip().lower() in correct_answer.strip().lower()
if is_correct:
score.score += 10
score.wins += 1
score.streak += 1
if score.streak > 1:
score.score += 5
else:
score.streak = 0
score.last_played = datetime.now()
await score.save()
return {"correct": is_correct, "score": score.score, "streak": score.streak}
async def get_leaderboard(game_type: str = "trivia", limit: int = 10) -> list:
return await GameScore.filter(game_type=game_type).order_by("-score").limit(limit).all()
async def daily_checkin(user_id: int, username: str) -> dict:
score = await get_or_create_score(user_id, username, "checkin")
today = datetime.now().strftime("%Y-%m-%d")
if score.last_played and score.last_played.strftime("%Y-%m-%d") == today:
return {"ok": False, "reason": "already_checked", "score": score.score, "streak": score.streak}
score.total += 1
base = random.randint(5, 12)
streak_bonus = min(score.streak + 1, 7)
bonus = base + streak_bonus
score.score += bonus
score.streak += 1
score.wins += 1
score.last_played = datetime.now()
await score.save()
return {"ok": True, "score": score.score, "streak": score.streak, "bonus": bonus, "base": base, "streak_bonus": streak_bonus}
async def get_scores_summary(user_id: int) -> dict:
scores = await GameScore.filter(user_id=user_id).all()
total = sum((s.score or 0) for s in scores)
by_type = {s.game_type: s for s in scores}
return {"scores": scores, "total": total, "by_type": by_type}
async def deduct_points(user_id: int, cost: int) -> bool:
summary = await get_scores_summary(user_id)
if summary["total"] < cost:
return False
remaining = cost
for score in sorted(summary["scores"], key=lambda x: x.score or 0, reverse=True):
if remaining <= 0:
break
take = min(score.score, remaining)
score.score -= take
remaining -= take
await score.save()
return True
async def lottery_draw(user_id: int, username: str) -> dict:
cost = 10
if not await deduct_points(user_id, cost):
return {"ok": False, "reason": "积分不足", "cost": cost}
roll = random.random()
reward = 0
prize = "谢谢参与"
if roll < 0.08:
reward, prize = 60, "一等奖 +60"
elif roll < 0.25:
reward, prize = 25, "二等奖 +25"
elif roll < 0.55:
reward, prize = 12, "三等奖 +12"
score = await get_or_create_score(user_id, username, "lottery")
score.total += 1
if reward:
score.wins += 1
score.score += reward
score.last_played = datetime.now()
await score.save()
summary = await get_scores_summary(user_id)
return {"ok": True, "cost": cost, "reward": reward, "prize": prize, "total": summary["total"]}
async def buy_shop_item(user_id: int, item_id: str) -> dict:
item = SHOP_ITEMS.get(item_id)
if not item:
return {"ok": False, "reason": "商品不存在"}
if not await deduct_points(user_id, item["cost"]):
return {"ok": False, "reason": "积分不足", "item": item}
summary = await get_scores_summary(user_id)
return {"ok": True, "item": item, "total": summary["total"]}