问题
每个人都觉得自己能猜中天气。Totometeo 的想法是把这件事变成一款以联赛形式进行的游戏,风格类似足球竞猜游戏 TotoMondiale:玩家预测某个城市在某个时刻的天气,由真实数据决定谁得分。游戏必须能够自动运行:按时截止预测、获取真实天气、计算得分并更新排名,全程无需人工操作。
我做了什么
我开发了 Totometeo,一款在线天气竞猜游戏,设有公开和私人联赛,并根据真实气象数据自动计分。
- 联赛——玩家可以创建公开或私人联赛,并用 6 位邀请码邀请朋友,邀请码排除了 I、O、0、1 等容易混淆的字符。另有一个所有人都参加的总联赛。
- 轮次与预测——每一轮包含若干天气事件,各有城市、时间和截止时间。玩家要为每个事件预测天空状况、气温、是否下雨、降雨毫米数、风速,还可以选择预测一项罕见事件,例如冰雹或强风。截止前可以修改预测,之后即被锁定。
- 真实气象数据——事件结束后,应用从 Open-Meteo 读取逐小时数据;如果预报数据缺失,则改用历史档案。WMO 天气代码被映射为游戏中的 7 种天气状况,罕见事件则根据数据判定,例如风速达到或超过 50 km/h。
- 计分引擎——10 条计分规则和 2 项容差,从天气状况完全猜中得 5 分,到罕见事件奖励 10 分。每个得分都连同明细一起保存,玩家可以清楚看到每一分的来源。
- 自动化——一个定时任务每分钟关闭已过期的事件;另一个每 15 分钟获取真实天气,每轮最多为 25 个事件计分。
- 排名与管理——联赛排名、总排名和历史排名,以及一个管理面板,用于管理轮次、事件、天气数据获取、计分、规则、用户和联赛,并记录管理员的操作日志。
技术栈
Node.js 和 Express,页面由 EJS 在服务器端渲染。通过 Prisma ORM 使用 MySQL 或 MariaDB,共 10 个数据模型。会话使用 express-session,密码用 bcrypt 哈希。定时任务使用 node-cron,进程由 PM2 管理,前面是 Nginx。气象数据来自 Open-Meteo,无需 API 密钥。
为什么这样做
计分规则保存在数据库中,而不是写在代码里。游戏规格中的默认值在安装时载入一次,之后管理员可以在面板上修改分值和容差,无需发布新版本。由于每个得分都保留了明细,规则的任何调整对玩家来说都是透明的。


