"""动作:把求解器算出的 Swap 转成屏幕滑动(ADB swipe)。 两层结构: 1. 纯函数 `swap_to_swipe(swap, grid)` —— 把交换转成 (x1,y1,x2,y2),便于离线测试。 2. `SwapAction` —— MaaFramework 自定义动作适配器(仅在装了 MaaFw 时可用)。 """ from __future__ import annotations from .config import GridConfig from .solver import Solver, Swap from .state import GameState def swap_to_swipe(swap: Swap, grid: GridConfig) -> tuple[int, int, int, int]: """把一次交换映射为屏幕滑动起止像素坐标。 返回 (x1, y1, x2, y2):从 (x1,y1) 滑到 (x2,y2)。 重要:**水平交换一律从右往左滑**(起点在右、终点在左)。因为本游戏里 从左往右滑会触发返回/退出手势。交换两格的结果与滑动方向无关,所以反向滑同样有效。 上下滑动不受影响。 """ p1 = grid.cell_center(swap.r1, swap.c1) p2 = grid.cell_center(swap.r2, swap.c2) if swap.r1 == swap.r2 and p1[0] < p2[0]: # 水平交换且当前是左->右,交换起止,强制右->左 p1, p2 = p2, p1 return p1[0], p1[1], p2[0], p2[1] # ---------------------------------------------------------------------------# # MaaFramework 自定义动作适配器 # ---------------------------------------------------------------------------# try: from maa.custom_action import CustomAction # type: ignore class SwapAction(CustomAction): """读取共享 Board -> 求最优交换 -> 通过控制器滑动。 在 pipeline 中以 Custom 动作引用本类。无可行交换时返回 False(pipeline 可据此 判定本局结束或刷新棋盘)。 """ def __init__(self, state: GameState, solver: Solver | None = None, swipe_duration_ms: int = 200) -> None: super().__init__() self.state = state self.solver = solver or Solver() self.swipe_duration_ms = swipe_duration_ms def run(self, context, argv) -> bool: board = self.state.board if board is None: return False result = self.solver.find_best_swap(board) if result is None: # 没有可行消除:交给 pipeline 处理(如洗牌/重识别) return False grid = self.state.grid_runtime or self.state.grid x1, y1, x2, y2 = swap_to_swipe(result.swap, grid) # MaaFw 控制器滑动;不同版本 API 名称可能为 post_swipe / swipe controller = context.tasker.controller controller.post_swipe(x1, y1, x2, y2, self.swipe_duration_ms).wait() return True except Exception: # pragma: no cover - 未安装 MaaFw 时跳过 SwapAction = None # type: ignore