feat: add two-human AI autochess mode
check / local-gate (push) Failing after 50s

This commit is contained in:
JWeBot Contributors
2026-10-15 16:08:59 +08:00
parent e713ff369a
commit 9fff57134f
18 changed files with 228 additions and 41 deletions
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-official-extensions"
version = "0.6.4a0+1015"
version = "0.6.5a0+1015"
description = "Reviewed local command adapters and broker implementation for JWeBot"
requires-python = ">=3.9"
dependencies = [
"jwebot-sdk==0.6.4a0+1015",
"jwebot-sdk==0.6.5a0+1015",
]
[tool.setuptools.packages.find]
@@ -84,4 +84,4 @@ __all__ = [
"render_feature_list",
]
__version__ = "0.6.4a0+1015"
__version__ = "0.6.5a0+1015"
@@ -11,6 +11,8 @@ MIN_PLAYERS = 2
MAX_PLAYERS = 8
AI_PERSON_KEY = "__local_ai_team__"
AI_DISPLAY_NAME = "AI 战队"
AI_SECOND_PERSON_KEY = "__local_ai_team_2__"
AI_SECOND_DISPLAY_NAME = "AI 战队 B"
HOST_NAME = "Taffy"
STARTING_GOLD = 10
STARTING_HP = 100
@@ -325,6 +327,11 @@ def _preparation_prompt(state: dict[str, Any]) -> str:
def _format_description(state: dict[str, Any]) -> str:
team_count = len(state["join_order"])
if state.get("ai_test_variant") == "two_plus_two":
return (
"本届采用 2 人+2 AI 测试赛:报名种子 1v4、2v3 进行 BO5 "
"半决赛,胜者进入 BO5 总决赛"
)
if state.get("ai_test_mode"):
return (
"本届采用 3 人+1 AI 测试赛:报名种子 1v4、2v3 进行 BO5 "
@@ -844,7 +851,7 @@ def _auto_manage_ai(
+ CARD_BY_ID[str(incoming["card_id"])]["name"]
)
text = (
f"{AI_DISPLAY_NAME} 自动运营:{'、'.join(actions)};"
f"{player['display_name']} 自动运营:{'、'.join(actions)};"
f"金币 {player['gold']},五人首发战力 "
f"{lineup_power(player)['power']:.1f}。"
)
@@ -1573,7 +1580,8 @@ class CsMajorAutochess:
def rules() -> str:
return (
"CS自走棋:/自走棋开始 创建报名;/自走棋报名;主持人 /自走棋开赛。\n"
"三名真人报名后,主持人可用 /自走棋加AI战队 开启 3 人+1 AI 测试模式。\n"
"两名或三名真人报名后,主持人可用 /自走棋加AI战队,"
"分别开启 2 人+2 AI 或 3 人+1 AI 测试模式。\n"
"每人固定 5 名首发 + 1 名教练,开赛即发完整首发;每轮公开 6 人商店。"
"/选1~/选6 购买;/阵容;/上阵 备战编号 [首发位];/出售 备战编号。\n"
"教练只提供全队 +2%~+10% 加成;/升级教练;/刷新;/锁定。"
@@ -1664,6 +1672,7 @@ class CsMajorAutochess:
"round_plan": [],
"group_results": [],
"ai_test_mode": False,
"ai_test_variant": "",
"preparation_order": [],
"preparation_cursor": 0,
"qualifiers": [],
@@ -1694,7 +1703,7 @@ class CsMajorAutochess:
return _result(
state,
_host_text(
"3 人+1 AI 测试模式已经锁定参赛名单,不能再加入真人。"
"AI 测试模式已经锁定参赛名单,不能再加入真人。"
),
)
if person_key in state["players"]:
@@ -1724,27 +1733,47 @@ class CsMajorAutochess:
state,
f"只有主持人 {state['host_display_name']} 可以加入 AI 战队",
)
if AI_PERSON_KEY in state["players"]:
return _result(state, "3 人+1 AI 测试战队已经加入")
if any(
player.get("is_ai")
for player in state["players"].values()
):
return _result(state, "AI 测试战队已经加入")
human_keys = [
key
for key in state["join_order"]
if not state["players"][key].get("is_ai")
]
if len(human_keys) != 3:
if len(human_keys) not in {2, 3}:
return _result(
state,
"3 人+1 AI 测试模式要求先有且仅有 3 名真人报名",
"AI 测试模式要求先有且仅有 2 名或 3 名真人报名",
)
state["players"][AI_PERSON_KEY] = _participant(
AI_PERSON_KEY,
AI_DISPLAY_NAME,
is_ai=True,
)
state["join_order"].append(AI_PERSON_KEY)
if len(human_keys) == 2:
ai_teams = (
(AI_PERSON_KEY, "AI 战队 A"),
(AI_SECOND_PERSON_KEY, AI_SECOND_DISPLAY_NAME),
)
variant = "two_plus_two"
mode_label = "2 人+2 AI"
join_text = (
"AI 战队 A、AI 战队 B 已作为第 3、4 种子加入测试赛;"
)
else:
ai_teams = ((AI_PERSON_KEY, AI_DISPLAY_NAME),)
variant = "three_plus_one"
mode_label = "3 人+1 AI"
join_text = "AI 战队已作为第 4 种子加入测试赛;"
for ai_key, ai_name in ai_teams:
state["players"][ai_key] = _participant(
ai_key,
ai_name,
is_ai=True,
)
state["join_order"].append(ai_key)
state["ai_test_mode"] = True
state["ai_test_variant"] = variant
text = _host_text(
"AI 战队已作为第 4 种子加入测试赛;"
f"{join_text}{mode_label} 编制已锁定;"
"开赛后固定进行 1v4、2v3 半决赛,AI 将自动运营。"
)
story = _story(
@@ -1752,8 +1781,16 @@ class CsMajorAutochess:
"ai_team_joined",
text,
{
"person_key": AI_PERSON_KEY,
"seed": 4,
"person_keys": [
ai_key for ai_key, _ in ai_teams
],
"seeds": list(
range(
len(human_keys) + 1,
len(human_keys) + len(ai_teams) + 1,
)
),
"variant": variant,
"test_mode": True,
},
)