/** * pin_pull.aigameplay — reducer 接口模板 * * Agent 生成实际 reducer 时,必须导出以下函数。 * 此文件是接口约束模板,不是可执行代码。 * * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ * ⚠️ 重要:渲染层(GameScene)不应直接调用 dispatch() * * dispatch() 是一体化接口,内部完成销钉拔出 + 液体流动模拟后只返回最终状态, * 中间过程(哪些通道开放、液体流向路径、容器填充顺序)全部丢失。 * * 渲染层需要分步动画(销钉拔出 → 通道开放 → 液体流动 → 容器填满), * 因此必须使用下方的「分步函数」逐步驱动,每步之间插入粒子/流体动画。 * * dispatch() 的用途:无头测试、AI 模拟、快速跳过动画等场景。 * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */ // ─── 配置类型 ───────────────────────────────────────────────────────────────── export type LiquidType = 'water' | 'blood' | 'acid' | 'lava'; export type ContainerRole = 'target' | 'danger' | 'neutral'; export type PinStateValue = 'inserted' | 'removed'; export type ChannelStateValue = 'open' | 'blocked'; export type PinPullConfig = { pins: Array<{ id: string; position: { x: number; y: number }; blockedChannelIds: string[]; }>; liquidSources: Array<{ id: string; type: LiquidType; capacity: number; position: { x: number; y: number }; }>; containers: Array<{ id: string; role: ContainerRole; acceptedLiquid: LiquidType | 'any'; capacity: number; position: { x: number; y: number }; }>; channels: Array<{ id: string; from: string; to: string; blockingPinIds: string[]; }>; }; // ─── 动作类型 ───────────────────────────────────────────────────────────────── export type PinPullAction = | { type: 'pull_pin'; pinId: string } | { type: 'reset' }; // ─── 状态类型 ───────────────────────────────────────────────────────────────── export type PinRecord = { id: string; state: PinStateValue; blockedChannelIds: string[]; position: { x: number; y: number }; }; export type LiquidSource = { id: string; type: LiquidType; capacity: number; remaining: number; position: { x: number; y: number }; }; export type ContainerRecord = { id: string; role: ContainerRole; acceptedLiquid: LiquidType | 'any'; capacity: number; filled: number; position: { x: number; y: number }; }; export type ChannelRecord = { id: string; from: string; to: string; state: ChannelStateValue; blockingPinIds: string[]; }; export type PinPullState = { pins: Record; liquidSources: Record; containers: Record; channels: Record; /** 游戏是否结束 */ gameOver: boolean; /** 是否胜利 */ win: boolean; /** 失败/胜利原因 */ reason?: 'all_targets_filled' | 'danger_zone_reached'; }; // ─── 分步操作返回类型 ───────────────────────────────────────────────────────── /** 通道开放信息(用于驱动开关动画) */ export type OpenedChannel = { channelId: string; from: string; to: string; }; /** 液体流动路径(一段从 source 到 container 的流动路径) */ export type FlowPath = { sourceId: string; liquidType: LiquidType; /** 经过的节点 id 序列(含 source 和 container) */ nodePath: string[]; /** 流入的容器 id */ targetContainerId: string; /** 本次流入量 */ flowAmount: number; }; /** simulateLiquidFlow 的完整结果 */ export type FlowResult = { paths: FlowPath[]; /** 危险容器是否被触及 */ dangerTouched: boolean; /** 所有 target 容器是否已满 */ allTargetsFilled: boolean; }; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 必须导出的函数 // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ─── 初始化 ────────────────────────────────────────────────────────────────── /** * init:根据配置初始化游戏状态 */ export declare function init(config: PinPullConfig): PinPullState; // ─── 一体化接口(测试/AI 模拟用) ─────────────────────────────────────────── /** * dispatch:接收动作,返回新状态(纯函数,不得修改原 state) * - pull_pin:拔出销钉,自动模拟液体流动,检测胜败(一步到位) * - reset:重置到初始状态 * * ⚠️ 仅用于无头测试和 AI 模拟。渲染层请使用下方分步函数。 */ export declare function dispatch(state: PinPullState, action: PinPullAction): PinPullState; /** * getState:返回当前状态快照 */ export declare function getState(state: PinPullState): PinPullState; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 分步函数(渲染层/场景层必须使用这些函数驱动动画) // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ /** * canPullPin:检查指定销钉是否可以被拔出 * - 销钉必须存在且处于 inserted 状态 * - 游戏未结束 * * 场景层在玩家点击时调用:false → 播放锁定/摇晃提示 */ export declare function canPullPin(state: PinPullState, pinId: string): boolean; /** * pullPin:执行销钉拔出操作 * 返回更新后的状态(销钉状态改为 removed,关联通道更新为 open) * 及已开放的通道列表 * * 场景层根据 openedChannels 播放: * - 销钉拔出动画 * - 通道开放(门/挡板消失)动画 * * ⚠️ 调用 pullPin 后必须紧接着调用 simulateLiquidFlow */ export declare function pullPin( state: PinPullState, pinId: string, ): { newState: PinPullState; openedChannels: OpenedChannel[]; }; /** * simulateLiquidFlow:在当前通道图上模拟液体从所有 source 流向可达节点 * 返回所有流动路径及胜败判断 * * 场景层根据 FlowResult.paths 逐条播放液体流动动画(每段通道依次填充), * 动画完成后检查 dangerTouched / allTargetsFilled 决定胜败面板 */ export declare function simulateLiquidFlow(state: PinPullState): FlowResult; /** * checkWinLose:根据当前状态判断胜败 * - win: 所有 target 容器 filled >= capacity * - lose: 任意 danger 容器 filled > 0 * * 通常在 simulateLiquidFlow 后调用,或用于状态轮询 */ export declare function checkWinLose(state: PinPullState): { win: boolean; lose: boolean; reason?: 'all_targets_filled' | 'danger_zone_reached'; };