Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 61 additions & 9 deletions docs/contests/RL9/pve/game/actions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# 动作空间

PVE 使用 **8 个离散动作**:
PVE 使用 **28 个离散动作**(`N_ACTIONS = 28`),分为基础操作、商品交易、生产链、科技四大类。

## 基础动作(0–5)

| 编号 | 动作 | 含义 | 有效性条件 |
|:----:|:----:|------|------------|
Expand All @@ -9,18 +11,68 @@ PVE 使用 **8 个离散动作**:
| 2 | `MOVE_DOWN` | 向下移动 (x+1) | 同上 |
| 3 | `MOVE_LEFT` | 向左移动 (y−1) | 同上 |
| 4 | `MOVE_RIGHT` | 向右移动 (y+1) | 同上 |
| 5 | `BUY` | 在相邻市场买最便宜的可负担商品 | Manhattan ≤1 有市场,背包有空间,现金充足 |
| 6 | `SELL` | 在相邻市场卖出背包内所有商品 | Manhattan ≤1 有市场,背包有商品 |
| 7 | `HARVEST` | 从附近资源点采集原材料 | Manhattan ≤2 有未耗尽资源,背包有空间 |
| 5 | `BUY` | 在相邻市场购买利润最高的可负担商品 | Manhattan ≤1 有市场,背包有空间,现金充足 |

## 卖出动作(6–10,按商品类型)

| 编号 | 动作 | 含义 | 有效性条件 |
|:----:|:----:|------|------------|
| 6 | `SELL_0` | 卖出背包内所有**半导体** | Manhattan ≤1 有市场,背包有该商品 |
| 7 | `SELL_1` | 卖出背包内所有**药品** | 同上 |
| 8 | `SELL_2` | 卖出背包内所有**小商品** | 同上 |
| 9 | `SELL_3` | 卖出背包内所有**服饰** | 同上 |
| 10 | `SELL_4` | 卖出背包内所有**食品** | 同上 |

- **SELL_pid**:卖出指定类型的所有商品,获得当前市场价
- 卖出成功时:`score += revenue × score_factor`(默认 ×10),`money += revenue`

## 生产链动作(11–18)

| 编号 | 动作 | 含义 | 有效性条件 |
|:----:|:----:|------|------------|
| 11 | `HARVEST` | 从附近资源点采集原材料 | Manhattan ≤2 有未耗尽资源,背包有空间 |
| 12 | `DEPOSIT` | 将背包原材料存入工厂 | 在工厂格,背包 raw_inv > 0 |
| 13 | `PRODUCE_0` | 工厂开始生产**半导体**(消耗 5 原材料) | 在工厂格,工厂 raw_stock ≥ 5,生产队列未满 |
| 14 | `PRODUCE_1` | 工厂开始生产**药品**(消耗 3 原材料) | 在工厂格,工厂 raw_stock ≥ 3,生产队列未满 |
| 15 | `PRODUCE_2` | 工厂开始生产**小商品**(消耗 1 原材料) | 在工厂格,工厂 raw_stock ≥ 1,生产队列未满 |
| 16 | `PRODUCE_3` | 工厂开始生产**服饰**(消耗 4 原材料) | 在工厂格,工厂 raw_stock ≥ 4,生产队列未满 |
| 17 | `PRODUCE_4` | 工厂开始生产**食品**(消耗 2 原材料) | 在工厂格,工厂 raw_stock ≥ 2,生产队列未满 |
| 18 | `LOAD` | 从工厂仓库装载已完成成品到背包 | 在工厂格,工厂有成品,背包有空间 |

- **HARVEST**:采集范围 2 格(Manhattan 距离),每次采集 `unit_harvest_rate × time_step` 单位
- **DEPOSIT**:将背包中原材料存入工厂仓库,供后续生产使用
- **PRODUCE_pid**:将工厂原材料转换为产品,加入生产队列
- **LOAD**:从工厂仓库取出已完成的成品装入背包

## 算力与科技动作(19–27)

| 编号 | 动作 | 含义 | 消耗 | 前置 |
|:----:|:----:|------|:----:|:----:|
| 19 | `OCCUPY` | 推进相邻算力中心的占领进度 | — | — |
| 20 | `TECH_0` | **降低成本**:商品购买成本 −2 | 50 算力 | — |
| 21 | `TECH_1` | **效率提升**:生产时间 ×0.5 | 40 算力 | — |
| 22 | `TECH_2` | **市场营销**:卖价 ×1.1 | 80 算力 | — |
| 23 | `TECH_3` | **耐久强化**:单位 max HP +50% | 30 算力 | — |
| 24 | `TECH_4` | **多产线**:工厂 +1 生产线 | 60 算力 | — |
| 25 | `TECH_5` | **路径优化**:移动不再产生 busy tick | 50 算力 | TECH_1 |
| 26 | `TECH_6` | **市场分析**:观测中标记已购买(可重复) | 40 算力 | — |
| 27 | `TECH_7` | **算力扩张**:算力积累速率 +30% | 70 算力 | — |

- **OCCUPY**:需相邻有未开放的算力中心,每次 tick 推进 `time_step` 秒进度
- **TECH_0~5, TECH_7**:持久科技,每种只能购买一次,在工厂格执行
- **TECH_6**:非持久科技,可重复购买
- 科技动作需要在工厂格、算力足够、前置科技满足时才有效

## 通用规则

- **BUY**:自动购买当前市场价格最低的可负担商品
- **SELL**:一次性卖出背包中所有商品,获得当前市场价
- **HARVEST**:采集范围 2 格(Manhattan 距离
- 执行无效动作不会报错,但受到 **-0.05 分惩罚**并浪费步数
- `busy_ticks > 0` 时单位忙碌,**仅 WAIT 有效**,其他动作均被掩码屏蔽
- 移动默认消耗 1 busy_tick(购买 TECH_5 后变为 0)
- BUY/SELL/LOAD 消耗 busy_ticks(`0.25 / time_step` 个 tick
- 执行无效动作不会报错,但受到 **0.05 奖励惩罚**并浪费步数

## 动作掩码

环境提供 `action_masks()` 方法,返回 `(8,)` 布尔数组,`True` 表示该动作当前有效。使用 `MaskablePPO` 可以自动过滤无效动作:
环境提供 `action_masks()` 方法,返回 `(28,)` 布尔数组,`True` 表示该动作当前有效。使用 `MaskablePPO` 可以自动过滤无效动作:

```python
from sb3_contrib import MaskablePPO
Expand Down
92 changes: 86 additions & 6 deletions docs/contests/RL9/pve/game/state.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# 游戏状态

## 时间系统

| 参数 | 值 |
|:----:|:--:|
| 每 tick 时长 | 0.25s |
| easy/medium 总时长 | 300s(1200 ticks) |
| hard 总时长 | 500s(2000 ticks) |

## 单位属性

| 属性 | 值 |
Expand All @@ -9,8 +17,10 @@
| 采集速率 | 10/s |
| 算力中心占领时间 | 10s |

- 背包分为**原材料**和**成品**两部分
- `busy_ticks > 0` 时单位忙碌,忽略新指令
- 背包分为**原材料**(`raw_inv`)和**成品**(`prod_inv[pid]`)两部分
- `busy_ticks > 0` 时单位忙碌,仅 WAIT 有效
- 移动默认消耗 1 busy_tick(购买 path_optimization 科技后变为 0)
- BUY/SELL/LOAD 消耗 `int(0.25 / time_step)` 个 busy_tick

## 工厂

Expand All @@ -20,10 +30,72 @@
| 仓储上限 | 300 |
| 初始生产线数 | 3 |

## 算力产出
### 生产系统

工厂将原材料加工为成品。生产队列最大长度 = `生产线数 × 5`。

生产流程:
1. 采集原材料(HARVEST)
2. 存入工厂(DEPOSIT)
3. 排队生产(PRODUCE_pid)——消耗原材料,加入生产队列
4. 等待工厂 tick 推进完成
5. 装载成品(LOAD)

生产时间受 efficiency 科技影响(×0.5)。

- 每个已占领算力中心:**1 算力/秒**
- 可花费算力招募新单位(Phase 2)
## 商品

| ID | 名称 | 购买成本 | 原材料消耗 | 市场价格范围 | 生产时间 |
|:--:|:----:|:--------:|:----------:|:------------:|:--------:|
| 0 | 半导体 | 10 | 5 | 40–120 | 5.0s |
| 1 | 药品 | 5 | 3 | 20–60 | 4.0s |
| 2 | 小商品 | 1 | 1 | 4–12 | 2.0s |
| 3 | 服饰 | 8 | 4 | 32–96 | 6.0s |
| 4 | 食品 | 3 | 2 | 12–24 | 1.0s |

- 购买成本受 cost_reduction 科技影响(−2,最低为 0)
- 生产时间受 efficiency 科技影响(×0.5)

## 市场定价

每个市场对每种商品有独立的正弦价格函数:

```
price(t) = base + amplitude × (1 + sin(2π·t / period + phase)) / 2
```

- 不同市场的价格**相位随机不同步**,套利窗口随时间移动
- `price_volatility` 控制波动幅度(easy=0.3, medium=1.0, hard=2.0)
- 卖价受 marketing 科技影响(×1.1)

## 算力系统

- **基础产出**:每个已开放算力中心产出 **1 算力/秒**
- 购买 compute_expansion 科技后:+30% 算力速率
- 可消耗算力招募新单位(40 算力/个,最多 5 个单位)——Phase 2

### 算力中心

- 占领方式:在相邻格执行 OCCUPY,每次 tick 推进 0.25s 进度
- 进度达到 `unit_occupy_time`(10s)后开放
- 开放后持续产出算力

## 科技树

| 键名 | 效果 | 消耗 | 前置 | 持久 |
|:-----|------|:----:|:----:|:----:|
| cost_reduction | 商品购买成本 −2 | 50 | — | ✓ |
| efficiency | 生产时间 ×0.5 | 40 | — | ✓ |
| marketing | 卖价 ×1.1 | 80 | — | ✓ |
| durability | 单位 max HP +50% | 30 | — | ✓ |
| multi_line | 工厂 +1 生产线 | 60 | — | ✓ |
| path_optimization | 移动不产生 busy_tick | 50 | efficiency | ✓ |
| market_analysis | 观测中标记已购买 | 40 | — | ✗ |
| compute_expansion | 算力速率 +30% | 70 | — | ✓ |

- 持久科技每种只能购买一次
- market_analysis 可重复购买
- 科技在工厂格执行

## 资源再生

Expand All @@ -34,4 +106,12 @@ regen(t) = rate × (1 + sin(2π·t / period)) / 2
```

- 再生倍率:easy=2.0, medium=1.0, hard=0.5
- 资源耗尽(`depleted=True`)后停止再生
- 资源耗尽(累计采集量 ≥ max_stock)后停止再生
- 最大库存为初始库存的 2 倍

## 得分与终止

- **得分**:`score += revenue × score_factor`(默认 ×10),仅在 SELL 成功时增加
- **terminated**:`money < 0`(破产)
- **truncated**:`step >= max_steps`(时间耗尽)
- 最终排名以多 seed 下的 `info["score"]` 平均为准
112 changes: 88 additions & 24 deletions docs/contests/RL9/pve/interface/gym.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ obs, info = env.reset(seed=0)

```python
obs, reward, terminated, truncated, info = env.step(action)
# action: int, 0-7
# obs: np.ndarray, shape (32,), dtype float32
# action: int, 0-27
# obs: np.ndarray, shape (58,), dtype float32
# reward: float
# terminated: bool (money < 0,破产)
# truncated: bool (步数耗尽,正常结束)
Expand All @@ -44,36 +44,100 @@ obs, reward, terminated, truncated, info = env.step(action)
### `action_masks()`

```python
mask = env.action_masks() # np.ndarray[bool], shape (8,)
mask = env.action_masks() # np.ndarray[bool], shape (28,)
```

返回当前有效的动作掩码。

## 观测向量(32 维 float32)
## 观测向量(58 维 float32)

### 单位状态([0–9])

| 索引 | 含义 | 归一化 |
|:----:|------|--------|
| 0–1 | 单位位置 (x, y) | / (H, W) |
| 2 | 单位 HP | / max_hp |
| 3 | 原材料背包占比 | raw_inv / capacity |
| 4 | 成品背包占比 | prod_inv / capacity |
| 5 | busy 倒计时 | / 10,截断到 1 |
| 6 | 现金 | log10(money+1) / 5 |
| 7 | 算力 | / 100,截断到 2 |
| 8 | 游戏进度 | time / max_time |
| 9 | 价格相位 sin | sin(2π·t / period) |
| 10 | 价格相位 cos | cos(2π·t / period) |
| 11 | 工厂原料库存 | / storage_cap |
| 12 | 工厂成品库存 | / storage_cap |
| 13 | 生产队列长度 | / 10,截断到 1 |
| 14–16 | 资源点 0 | 相对位置 (dx/H, dy/W) + 库存比 |
| 17–19 | 资源点 1 | 同上 |
| 20–22 | 算力中心 0 | 相对位置 (dx/H, dy/W) + is_open |
| 23–25 | 算力中心 1 | 同上 |
| 26–28 | 市场 0 | 相对位置 (dx/H, dy/W) + best_price |
| 29–31 | 市场 1 | 同上 |

> 如果实体数量不足(如只有 2 个市场),多余索引保持 0。
| 3 | 原材料背包 | raw_inv / capacity |
| 4 | 半导体背包 | prod_inv[0] / capacity |
| 5 | 药品背包 | prod_inv[1] / capacity |
| 6 | 小商品背包 | prod_inv[2] / capacity |
| 7 | 服饰背包 | prod_inv[3] / capacity |
| 8 | 食品背包 | prod_inv[4] / capacity |
| 9 | busy 倒计时 | / 10,截断到 1 |

### 经济状态([10–14])

| 索引 | 含义 | 归一化 |
|:----:|------|--------|
| 10 | 现金(对数) | log10(money+1) / 5 |
| 11 | 算力 | / 100,截断到 2 |
| 12 | 游戏进度 | time / max_game_time |
| 13 | 价格相位 sin | sin(2π·t / market_period) |
| 14 | 价格相位 cos | cos(2π·t / market_period) |

### 工厂状态([15–21])

| 索引 | 含义 | 归一化 |
|:----:|------|--------|
| 15 | 工厂原材料库存 | / storage_cap |
| 16 | 工厂半导体库存 | / storage_cap |
| 17 | 工厂药品库存 | / storage_cap |
| 18 | 工厂小商品库存 | / storage_cap |
| 19 | 工厂服饰库存 | / storage_cap |
| 20 | 工厂食品库存 | / storage_cap |
| 21 | 生产队列长度 | / 10,截断到 1 |

### 资源点([22–27])

| 索引 | 含义 | 归一化 |
|:----:|------|--------|
| 22–23 | 资源点 0 相对位置 (dx, dy) | / (H, W) |
| 24 | 资源点 0 库存比例 | stock / max_stock |
| 25–26 | 资源点 1 相对位置 (dx, dy) | / (H, W) |
| 27 | 资源点 1 库存比例 | stock / max_stock |

### 算力中心([28–35])

| 索引 | 含义 | 归一化 |
|:----:|------|--------|
| 28–29 | 算力中心 0 相对位置 (dx, dy) | / (H, W) |
| 30 | 算力中心 0 是否开放 | 0 或 1 |
| 31 | 算力中心 0 占领进度 | / unit_occupy_time |
| 32–33 | 算力中心 1 相对位置 (dx, dy) | / (H, W) |
| 34 | 算力中心 1 是否开放 | 0 或 1 |
| 35 | 算力中心 1 占领进度 | / unit_occupy_time |

### 市场([36–49])

| 索引 | 含义 | 归一化 |
|:----:|------|--------|
| 36–37 | 市场 0 相对位置 (dx, dy) | / (H, W) |
| 38 | 市场 0 半导体价格 | 按 val_range 归一化 |
| 39 | 市场 0 药品价格 | 同上 |
| 40 | 市场 0 小商品价格 | 同上 |
| 41 | 市场 0 服饰价格 | 同上 |
| 42 | 市场 0 食品价格 | 同上 |
| 43–44 | 市场 1 相对位置 (dx, dy) | / (H, W) |
| 45 | 市场 1 半导体价格 | 按 val_range 归一化 |
| 46 | 市场 1 药品价格 | 同上 |
| 47 | 市场 1 小商品价格 | 同上 |
| 48 | 市场 1 服饰价格 | 同上 |
| 49 | 市场 1 食品价格 | 同上 |

### 科技状态([50–57])

| 索引 | 含义 |
|:----:|------|
| 50 | 是否已购买 cost_reduction |
| 51 | 是否已购买 efficiency |
| 52 | 是否已购买 marketing |
| 53 | 是否已购买 durability |
| 54 | 是否已购买 multi_line |
| 55 | 是否已购买 path_optimization |
| 56 | 是否已购买 market_analysis(可重复) |
| 57 | 是否已购买 compute_expansion |

> 如果实体数量不足(如只有 1 个市场),多余索引保持 0。

## 禁止访问的对象

Expand All @@ -99,7 +163,7 @@ while True:
if info["money"] > 50:
action = 5 # BUY
else:
action = 7 # HARVEST
action = 11 # HARVEST
obs, reward, terminated, truncated, info = env.step(action)
if terminated or truncated:
break
Expand Down
8 changes: 4 additions & 4 deletions docs/contests/THUAI9/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ AI 工厂模拟(THUAI9)
| 编程语言 | C++ | Python |
| 交互方式 | gRPC 连接服务器 | Gymnasium 本地环境 |
| 控制对象 | 1 Team + 3 Character | 1 个单位 |
| 动作 | 连续移动 + 多种操作 | 8 个离散动作 |
| 得分机制 | 售卖 + 战斗 + 摧毁工厂 | 售卖 × 10 |
| 动作 | 连续移动 + 多种操作 | 28 个离散动作 |
| 得分机制 | 售卖 + 战斗 + 摧毁工厂 | 售卖 × 10(SELL成功时) |
| 文档入口 | [`pvp/`](pvp/intro/rule.md) | [`pve/`](pve/intro/rule.md) |

## PVP 概要

2~4 支队伍在同一地图对抗。每队拥有 1 座工厂和最多 3 个角色(Drone / Robot / AutonomousCar),通过采集资源、生产产品、占领算力中心、市场售卖、攻击敌方来获取分数。游戏时长 2 分钟,得分高者获胜。
2~4 支队伍在同一地图对抗。每队拥有 1 座工厂和最多 3 个角色(Drone / Robot / AutonomousCar),通过采集资源、生产产品、占领算力中心、市场售卖、攻击敌方来获取分数。游戏时长 10 分钟,得分高者获胜。

## PVE 概要

Expand All @@ -38,7 +38,7 @@ AI 工厂模拟(THUAI9)

### PVE 赛道(Python)

不熟悉强化学习的可以访问https://github.com/konpoku/THUAI9-RL,在小项目中学习一下
不熟悉强化学习的可以访问https://github.com/konpoku/THUAI9-RL ,在小项目中学习一下

详细的使用说明参照选手包里的logic\pve\docs\CONTESTANT_GUIDE.md

Expand Down
Loading