配置见 pyproject.toml:
- line-length=100:贴着现有代码定。若用默认的 88 会重排 122 行,
噪音淹没真正有价值的修复。
- 启用 E/W/F/I/UP/B/C4/SIM/RET/PERF/RUF;**不**启用 PTH。因为本项目的路径
多是"字符串身份"——要塞进 subprocess 命令行、写进 JSON 存档、打印给用户,
全换 pathlib 只是包一层再拆一层,换来 70 处纯风格改动。
- 忽略 RUF001/002/003:中文全角标点是正确写法,不是"歧义字符"。
- 忽略 PERF203:剩下两处都是"逐项容错"语义(逐个牧场存档要立刻上报失败、
收获全部要跳过失败地块)。把 try 提到循环外会毁掉"一项失败不影响其它项"
这个行为,是错的优化。
自动修复 358 项:Dict/List/Optional 换成 PEP 585/604 写法、导入排序、
失效的 noqa、空占位 f-string 等。
手工修复的(这些是真问题,不是风格偏好):
- B904 x9:except 中 raise 补异常链。刻意区分——网络/IO 失败用 from exc 保留
根因;参数解析失败用 from None,因为底层 ValueError 对玩家只是噪音。
- RUF012 x2:StateView 的 plots/animals 原本是**类级共享可变列表**,
改成在 __init__ 里初始化(apply({}) 会提前返回,所以必须显式摆好)。
- F841:TUI 里一个赋值后再没用过的死变量。
- SIM105 x11:try/except/pass 统一改成 contextlib.suppress。
- SIM115:日志句柄改用 with。Popen 已把 fd 复制给子进程,父进程可安全关闭。
- E501 x7:拆超长行;main.py 那处顺手提取变量,避免超长嵌套表达式。
- E741:把 l/r 改成 left_line/right_line。
- 其余:RUF046 / PERF401 / RET504 / RUF005 / UP031 / B007。
ruff format 重排 24 个文件。
验证:97 项测试全绿。
214 lines
5.7 KiB
Python
214 lines
5.7 KiB
Python
"""游戏平衡参数与静态定义。
|
||
|
||
本模块只描述"世界是什么样的"(作物表、动物表、经济参数),
|
||
不包含任何状态或逻辑,方便单独调参。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 基础经济参数
|
||
# --------------------------------------------------------------------------
|
||
|
||
START_GOLD = 120 # 初始金币
|
||
START_LEVEL = 1 # 初始等级
|
||
START_AP = 10 # 每天行动点上限
|
||
START_FEED = 5 # 初始饲料库存
|
||
|
||
BASE_PLOTS = 6 # 初始土地数量
|
||
MAX_PLOTS = 16 # 土地数量硬上限
|
||
PLOT_BASE_PRICE = 200 # 第一块新地的价格
|
||
PLOT_PRICE_GROWTH = 1.75 # 每多买一块,价格乘以该系数
|
||
|
||
FEED_UNIT_PRICE = 6 # 主动购买饲料的单价
|
||
FEED_EMERGENCY_PRICE = 9 # 自动补货(缺饲料时喂食)的惩罚单价
|
||
FEED_BULK = 10 # 一次购买饲料的默认批量
|
||
|
||
WATER_CAPACITY = 3 # 一次浇水可支撑的天数
|
||
PLANT_INITIAL_MOISTURE = 2 # 播种后地块自带的水分
|
||
PRICE_VOLATILITY = 0.18 # 每天价格波动幅度(±18%)
|
||
LUCKY_CHANCE = 0.12 # 丰收暴击概率(产出翻倍)
|
||
MAX_LOG_ENTRIES = 300 # 内存中保留的事件条数上限
|
||
MAX_FEED_PURCHASE = 200 # 单次购买饲料的数量上限
|
||
|
||
# 每级提供的土地上限(基础 6 + 2/级,封顶 MAX_PLOTS)
|
||
PLOTS_PER_LEVEL = 2
|
||
|
||
# 行动点消耗表
|
||
AP_COST = {
|
||
"plant": 1,
|
||
"water": 1,
|
||
"harvest": 0,
|
||
"feed": 1,
|
||
"collect": 0,
|
||
"buy_animal": 0,
|
||
"buy_plot": 0,
|
||
"buy_feed": 0,
|
||
}
|
||
|
||
|
||
# 经验曲线:升到 level+1 所需经验
|
||
def exp_to_next(level: int) -> int:
|
||
"""返回从 level 升到 level+1 所需的经验值。"""
|
||
return int(80 * (max(1, level) ** 1.6))
|
||
|
||
|
||
# 升级奖励金币
|
||
def level_up_bonus(level: int) -> int:
|
||
"""升到 level 时发放的金币奖励。"""
|
||
return 80 + 40 * level
|
||
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 作物表
|
||
# --------------------------------------------------------------------------
|
||
# key : 内部标识(API 与存档使用)
|
||
# name : 中文名
|
||
# seed_cost : 种子价格
|
||
# grow_days : 成熟所需生长天数(需要水分支撑)
|
||
# base_price : 收获物的基础售价
|
||
# exp : 每次收获获得的经验
|
||
# level_req : 解锁所需等级
|
||
|
||
CROPS: dict[str, dict[str, Any]] = {
|
||
"wheat": {
|
||
"name": "小麦",
|
||
"seed_cost": 5,
|
||
"grow_days": 2,
|
||
"base_price": 14,
|
||
"exp": 3,
|
||
"level_req": 1,
|
||
},
|
||
"carrot": {
|
||
"name": "胡萝卜",
|
||
"seed_cost": 8,
|
||
"grow_days": 3,
|
||
"base_price": 26,
|
||
"exp": 5,
|
||
"level_req": 1,
|
||
},
|
||
"tomato": {
|
||
"name": "番茄",
|
||
"seed_cost": 16,
|
||
"grow_days": 4,
|
||
"base_price": 52,
|
||
"exp": 9,
|
||
"level_req": 2,
|
||
},
|
||
"corn": {
|
||
"name": "玉米",
|
||
"seed_cost": 28,
|
||
"grow_days": 6,
|
||
"base_price": 95,
|
||
"exp": 14,
|
||
"level_req": 3,
|
||
},
|
||
"pumpkin": {
|
||
"name": "南瓜",
|
||
"seed_cost": 45,
|
||
"grow_days": 8,
|
||
"base_price": 180,
|
||
"exp": 22,
|
||
"level_req": 4,
|
||
},
|
||
"strawberry": {
|
||
"name": "草莓",
|
||
"seed_cost": 70,
|
||
"grow_days": 10,
|
||
"base_price": 320,
|
||
"exp": 35,
|
||
"level_req": 5,
|
||
},
|
||
}
|
||
|
||
# 生长阶段阈值(按生长进度 0.0~1.0 划分)
|
||
GROWTH_STAGES = [
|
||
(0.00, "已播种"),
|
||
(0.30, "幼苗"),
|
||
(0.65, "生长中"),
|
||
(1.00, "已成熟"),
|
||
]
|
||
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 动物表
|
||
# --------------------------------------------------------------------------
|
||
# key : 内部标识
|
||
# name : 中文名
|
||
# cost : 购买价格
|
||
# product : 产出物标识(中文名)
|
||
# base_price : 产出物基础售价
|
||
# cycle : 产出周期(天)
|
||
# feed_per_day: 每天消耗饲料数
|
||
# exp : 每次收集产出获得的经验
|
||
# level_req : 解锁所需等级
|
||
|
||
ANIMALS: dict[str, dict[str, Any]] = {
|
||
"chicken": {
|
||
"name": "鸡",
|
||
"cost": 90,
|
||
"product": "鸡蛋",
|
||
"base_price": 15,
|
||
"cycle": 1,
|
||
"feed_per_day": 1,
|
||
"exp": 4,
|
||
"level_req": 1,
|
||
},
|
||
"sheep": {
|
||
"name": "羊",
|
||
"cost": 220,
|
||
"product": "羊毛",
|
||
"base_price": 55,
|
||
"cycle": 2,
|
||
"feed_per_day": 1,
|
||
"exp": 9,
|
||
"level_req": 2,
|
||
},
|
||
"cow": {
|
||
"name": "牛",
|
||
"cost": 480,
|
||
"product": "牛奶",
|
||
"base_price": 72,
|
||
"cycle": 1,
|
||
"feed_per_day": 2,
|
||
"exp": 15,
|
||
"level_req": 3,
|
||
},
|
||
}
|
||
|
||
MAX_ANIMALS = 8 # 牧场总容量
|
||
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 时间
|
||
# --------------------------------------------------------------------------
|
||
|
||
DEFAULT_TICK_SECONDS = 15.0 # 自动推进一天所需的真实秒数
|
||
MIN_TICK_SECONDS = 3.0
|
||
MAX_TICK_SECONDS = 600.0
|
||
SLEEP_COOLDOWN = 2.0 # 手动"休息"推进一天的冷却(秒)
|
||
|
||
|
||
# --------------------------------------------------------------------------
|
||
# 进度目标
|
||
# --------------------------------------------------------------------------
|
||
|
||
GOALS = [
|
||
(200, "起步:攒够 200 金币"),
|
||
(600, "小农:攒够 600 金币"),
|
||
(1500, "农场主:攒够 1500 金币"),
|
||
(4000, "庄园主:攒够 4000 金币"),
|
||
(10000, "农业大亨:攒够 10000 金币"),
|
||
]
|
||
|
||
|
||
def goal_index(net_worth: float) -> int:
|
||
"""返回已达成的最低目标索引(-1 表示一个都没达成)。"""
|
||
reached = -1
|
||
for i, (amount, _) in enumerate(GOALS):
|
||
if net_worth >= amount:
|
||
reached = i
|
||
return reached
|