From 4ed53651cedb43f0854c05483aa413aa2460cbb1 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sat, 24 Oct 2026 19:45:59 +0800 Subject: [PATCH] =?UTF-8?q?test(=E8=BF=AD=E4=BB=A335=E5=8D=A1=E2=91=A1T3?= =?UTF-8?q?=20V3=20=E8=A1=A5=E5=8F=A3=EF=BC=8B=E6=8A=A5=E5=91=8A=E5=AF=B9?= =?UTF-8?q?=E7=85=A7=E8=A1=A8):=20=E5=A4=A7=E5=B2=94=E5=8F=A3=E5=88=86?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F=E5=85=91=E4=BB=98=E6=96=AD=E8=A8=80=E7=BB=84?= =?UTF-8?q?=E8=90=BD=E5=9C=B0=EF=BC=88=E5=8D=A1=E7=89=87=20V3=20=E6=98=AF?= =?UTF-8?q?=E6=9C=AC=E5=8D=A1=20=C2=A78=20=E5=94=AF=E4=B8=80=E6=97=A0?= =?UTF-8?q?=E6=9C=BA=E6=A3=80=E6=96=AD=E8=A8=80=E7=9A=84=E9=AA=8C=E6=94=B6?= =?UTF-8?q?=E7=82=B9=EF=BC=8C=E5=89=8D=E5=8F=A3=E6=BC=8F=E6=8C=82=E2=80=94?= =?UTF-8?q?=E2=80=94=E6=9C=AC=E8=BD=AE=E8=A1=A5=EF=BC=89=E2=80=94=E2=80=94?= =?UTF-8?q?level=5Fshop=5Feconomy=20=E6=96=B0=E5=A2=9E=20=5Fsmoke=5Fmulti?= =?UTF-8?q?=5Fterminal=5Fsettlement=20=E4=BA=94=E6=9D=A1=EF=BC=9AL2=20?= =?UTF-8?q?=E7=8E=B0=E8=A1=8C=E5=9B=BE=20Boss=20=E7=BB=88=E7=82=B9?= =?UTF-8?q?=E4=B8=A4=E9=A2=97=E4=BB=A5=E4=B8=8A=E3=80=81min/max=20?= =?UTF-8?q?=E4=B8=A4=E8=BD=B4=E5=90=84=E8=87=AA=E6=94=B6=E5=9C=A8=E6=9C=AC?= =?UTF-8?q?=E8=B7=AF=E7=BB=88=E7=82=B9=20Boss=EF=BC=88=E6=9C=AB=E5=8F=A5?= =?UTF-8?q?=E6=9F=84=206/11=20=E4=BA=92=E5=BC=82=E4=B8=94=E9=83=BD?= =?UTF-8?q?=E5=B1=9E=E5=9B=BE=20Boss=20=E9=9B=86=EF=BC=8Cresult=3Dvictory?= =?UTF-8?q?=EF=BC=89=E3=80=81=E5=8C=BA=E5=9F=9F=E9=9A=94=E7=A6=BB=EF=BC=88?= =?UTF-8?q?min=20=E8=B7=AF=E4=B8=8D=E5=90=AB=20max=20=E7=BB=88=E7=82=B9?= =?UTF-8?q?=E3=80=81=E5=8F=8D=E4=B9=8B=E4=BA=A6=E7=84=B6=EF=BC=89=E3=80=81?= =?UTF-8?q?=E4=BB=BB=E4=B8=80=20Boss=20=E8=83=9C=E5=8D=B3=E6=9C=AC?= =?UTF-8?q?=E5=85=B3=E6=94=B6=E6=9D=9F=20level=5Ffinished=20=E6=81=B0?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=E4=B8=94=E8=BD=BD=E8=8D=B7=20result=3Dvictor?= =?UTF-8?q?y=C2=B7node=5Fid=EF=BC=9D=E8=AF=A5=E7=BB=88=E7=82=B9=E5=8F=A5?= =?UTF-8?q?=E6=9F=84=EF=BC=88=E7=9C=9F=E5=AE=9E=20runner.start=5Flevel+pic?= =?UTF-8?q?k=5Fnext=5Fnode+=5Fautoplay=5Fbattle=20=E5=85=A8=E7=A8=8B?= =?UTF-8?q?=E9=A9=B1=E5=8A=A8=EF=BC=8C=E5=85=91=E4=BB=98=E5=81=9C=E7=82=B9?= =?UTF-8?q?=E8=B5=B0=20continue=5Fafter=5Fnode=20=E4=B8=8E=20=5Fdrive=5Fle?= =?UTF-8?q?vel=20=E5=90=8C=E5=8F=A3=E5=BE=84=EF=BC=89=EF=BC=9B=E5=AE=BF?= =?UTF-8?q?=E4=B8=BB=20176=E2=86=92181=20=E6=9D=A1=E5=85=A8=E7=BB=BF?= =?UTF-8?q?=E3=80=82=E5=AE=9E=E7=8E=B0=E6=8A=A5=E5=91=8A=E8=A1=A5=20=C2=A7?= =?UTF-8?q?=E4=BA=8C=C2=B7=E5=8D=81=E4=B8=89=20=E5=AE=9E=E9=99=85=E5=AF=B9?= =?UTF-8?q?=E7=85=A7=E8=A1=A8=EF=BC=88=E5=8D=A1=E7=89=87=20=C2=A78.2=20?= =?UTF-8?q?=E5=85=AB=E8=A1=8C=E9=80=90=E8=A1=8C=E7=BB=99=E6=96=87=E4=BB=B6?= =?UTF-8?q?:=E8=A1=8C=EF=BC=8F=E7=9C=9F=E5=AE=9E=E5=85=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8F=E6=92=A4=E9=94=80=E8=AF=81=E6=98=8E=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=20M1-M7=20=E4=B8=8E=20T1/=E8=A6=86=E7=9B=96=E6=89=B9=E5=8F=98?= =?UTF-8?q?=E5=BC=82=EF=BC=89=E4=B8=8E=E7=BB=88=E7=89=88=E5=AE=BF=E4=B8=BB?= =?UTF-8?q?=E8=AF=BB=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unit/core/level_shop_economy_test.gd | 55 +++++++++++++++++++ reports/iter35-卡②-实现报告-2026-10-24.md | 15 +++++ 2 files changed, 70 insertions(+) diff --git a/game/tests/unit/core/level_shop_economy_test.gd b/game/tests/unit/core/level_shop_economy_test.gd index ecdba9bf..9f4049e7 100644 --- a/game/tests/unit/core/level_shop_economy_test.gd +++ b/game/tests/unit/core/level_shop_economy_test.gd @@ -248,6 +248,7 @@ func _init() -> void: _smoke_gp_escrow() _smoke_shop_room() _smoke_shop_graph() + _smoke_multi_terminal_settlement() _smoke_shop_pool() _smoke_generated_coverage() quit(Kit.finish("level_shop_economy_test")) @@ -1151,6 +1152,60 @@ func _smoke_shop_graph() -> void: Kit.check("L1 现行图跨表覆盖(战斗/Boss 节点 %d 颗非空·敌侧违例 %d·板侧违例 %d)" % [int(l1_cov["nodes"]), int(l1_cov["enemy_bad"]), int(l1_cov["board_bad"])], int(l1_cov["nodes"]) >= 1 and int(l1_cov["enemy_bad"]) == 0 and int(l1_cov["board_bad"]) == 0) +# ---- ⑥ 大岔口分区域兑付(V3——多终点图走哪条路决定打谁,任一 Boss 胜即收束恰一次)---- +func _smoke_multi_terminal_settlement() -> void: + print("--- 大岔口分区域兑付(L2 两轴各打各的终点)---") + var autoplay = load("res://sim/level_autoplay.gd") + var nodes: Array = _generated_graph(2, 42).get("nodes", []) + var boss_ids := _ids_of_type(nodes, "boss") + Kit.check("L2 现行图为多终点(Boss 终点 %s 两颗以上——大岔口承载面)" % str(boss_ids), boss_ids.size() >= 2) + var run_min: Dictionary = autoplay.run_level(_db, 42, 2, 400, 300, false, null, "normal", "min") + var run_max: Dictionary = autoplay.run_level(_db, 42, 2, 400, 300, false, null, "normal", "max") + var min_vis: Array = run_min.get("visited_ids", []) as Array + var max_vis: Array = run_max.get("visited_ids", []) as Array + var min_last := -1 + var max_last := -1 + if not min_vis.is_empty(): + min_last = int(min_vis[min_vis.size() - 1]) + if not max_vis.is_empty(): + max_last = int(max_vis[max_vis.size() - 1]) + # 走哪条路决定打谁:两路各自收在本路终点 Boss 上且互不相同;本关收束 result=victory + Kit.check("L2 min/max 两路各打进各自终点 Boss(末句柄 %d / %d 互异且都在图 Boss 集 %s 内;两路 result=%s/%s)" % [min_last, max_last, str(boss_ids), String(run_min.get("result", "")), String(run_max.get("result", ""))], + String(run_min.get("result", "")) == "victory" and String(run_max.get("result", "")) == "victory" + and boss_ids.has(min_last) and boss_ids.has(max_last) and min_last != max_last) + # 不误兑付:另一颗 Boss 不在本路已到序里(走 A 区不误兑付 B 区 Boss) + Kit.check("min 路未到 max 终点 %d、max 路未到 min 终点 %d(区域隔离——走 A 区不误兑付 B 区 Boss)" % [max_last, min_last], + not min_vis.has(max_last) and not max_vis.has(min_last)) + # 任一 Boss 胜=本关收束恰一次(level_finished 一次·载荷 result=victory 且 node_id=该终点句柄) + var fin := {"count": 0, "payload": {}} + var runner = load("res://core/level_runner.gd").new(_db, _fresh_rng(42)) + runner.set_hero_override(400, 300) # 满配档——全程驱动须打到 Boss 才收束 + runner.level_finished.connect(func(p): fin["count"] = int(fin["count"]) + 1; fin["payload"] = p) + Kit.check("L2 全程驱动启动受理", runner.start_level(2, 42)) + var st_drive := _battle_st("normal") + var guard := 40 + while guard > 0 and int(fin["count"]) == 0: + guard -= 1 + if runner.awaiting_choice(): + var ids: Array = runner.next_candidate_ids() + if ids.is_empty(): + break + runner.pick_next_node(int(ids[ids.size() - 1])) + continue + var b = runner.current_battle() + if b == null: + # 兑付停点(休整/商店/奖励直通)——先确认继续再回到选路,与 _drive_level 同口径 + if not runner.continue_after_node(): + break + continue + var inner := 40 + while inner > 0 and runner.current_battle() == b: + inner -= 1 + autoplay._autoplay_battle(runner, b, st_drive, null) + var payload: Dictionary = fin["payload"] + Kit.check("任一 Boss 胜即本关收束恰一次(count=%d·载荷 result=%s·node_id=%s 在图 Boss 集 %s 内)" % [int(fin["count"]), String(payload.get("result", "")), str(payload.get("node_id", -1)), str(boss_ids)], + int(fin["count"]) == 1 and String(payload.get("result", "")) == "victory" + and boss_ids.has(int(payload.get("node_id", -1)))) # 现行图全路径穿店恰一(性质③在单图上的整体读数) func _paths_all_one_shop(nodes: Array) -> bool: diff --git a/reports/iter35-卡②-实现报告-2026-10-24.md b/reports/iter35-卡②-实现报告-2026-10-24.md index 26145873..4165eead 100644 --- a/reports/iter35-卡②-实现报告-2026-10-24.md +++ b/reports/iter35-卡②-实现报告-2026-10-24.md @@ -140,6 +140,21 @@ 卡片 §8 变异清单九条的落位:V1 两条(T1 已录)、V11 两条(覆盖批已录)、V2/V5×2/V6/V7/V8/V9 共六条(本表 M1–M7,V5 拆两条)。 +## 二·十三 实际对照表(卡片 §8.2 八行的落地坐标;审计第 1 件按此逐行核) + +| 需求点 | 测试落点(文件:行/尾缀) | 真实入口 | 撤销或变异证明 | +|---|---|---|---| +| 加载校验四检+良构 | `game/tests/unit/core/level_table_validate_test.gd`(17 条,〔v1〕)+起关拒绝段 `game/core/level_runner.gd:308-312` | `LevelRunner.start_level_external`(违规图返回 false) | T1 四条注入见红(§二·五):终点恒 Boss 判据注释、无环判据短路等 | +| 行进语义(多入口/大岔口/多 Boss/单链) | `node_map_templates_test.gd:60-66`〔v2〕;`level_shop_economy_test.gd:1157-1216`(V3 段:多终点图、两路各收本路 Boss、区域隔离、收束恰一次);`level_shop_economy_test.gd:339`〔v4〕(L1 终点恰一)+`:632`(L3 入口数=`entry_count`、终点数=`exit_count`) | `LevelRunner.start_level_external`/`start_level`+`pick_next_node`/`sim/level_autoplay.run_level`(route=min/max 两轴全程驱动) | M1(候选写死单入口)→〔v2〕红 | +| 商店编排三条性质 | `level_shop_economy_test.gd:1129-1133`〔v5〕(扫描面非空+性质①②③,60 图/1413 路径读数)+`:1000-1010` 行进面 | 生成图逐节点解析+`runner` 行进到店 | M2(终点前驱非店)→性质①红;M3(加第二家店)→性质②③红 | +| 生成图覆盖+多终点 Boss 带互异 | `level_shop_economy_test.gd:259-306`〔v11〕+`adventure_feats_test.gd:111-131`〔fv24〕 | `ConfigDB.resolve_enemy_rowset`/`resolve_board_gen` 真实消费链 | 覆盖批两条注入已录(Boss 带并单带、删顶带);〔fv24〕判据与〔v11〕同源单点 | +| 定位信息两样(关卡序号+节点深度) | `adventure_feats_test.gd:159-166`〔v6〕(读 `BattleOrchestrator.encounter`) | 真实进战入口 `_drive_to_pref`→`pick_next_node`→`begin_battle` | M4(enc `node_depth` 取句柄)→〔v6〕红 | +| 确定性承载+旧断点代差 | `node_map_templates_test.gd:44-95`〔v7〕〔v8〕;`breakpoint_resume_test.gd:157-183`〔v7〕〔v8〕〔v9〕 | `NodeMapGenerator.generate`/`AdventureRunner.start_adventure`/`resume_adventure`(真实快照写手 `SaveManager`) | M5(产图改计数器流)→〔v7〕红;M6(缺代差键放行)→〔v8〕红 | +| 15 张模板清理 | `node_map_templates_test.gd:91-96`〔v9〕+件核 grep(全仓零 `templates`/`first_script`/`template_pick`/`active_template`) | `ConfigDB.level_row` 表读面 | M7(表内偷留 `templates` 键)→〔v9〕红 | +| 反哺点清单(非行为改动) | `reports/iter35-卡②-反哺点-2026-10-24.md` 十条落点 | T4 产出物件核 | 缺任一落点=V10 件核红(本文件 §三·一 目检两条同批登记) | + +宿主读数(终版):`level_shop_economy_test` 181 条、`node_map_templates_test` 21 条、`adventure_feats_test` 138 条、`breakpoint_resume_test` 56 条、`level_table_validate_test` 17 条。 + ## 三·一 实机目检总清单(真人判断项,登记即完成义务,不作为合回前置) | # | 观测项 | 真实入口 | 期望看到什么 | 本批机检已覆盖的部分 |