/** * solitaire.aigameplay — reducer 接口模板 * * Agent 生成实际 reducer 时,必须导出以下函数。 * 此文件是接口约束模板,不是可执行代码。 * * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ * ⚠️ 重要:渲染层(GameScene)不应直接调用 dispatch() * * dispatch() 是一体化接口,适用于无头测试。 * 渲染层需要在移牌前先验证合法性(canMoveToTableau/canMoveToFoundation), * 再执行 moveCards,然后根据 lastFlipped 决定是否播放翻牌动画。 * 不要用 dispatch 然后全量重建所有牌精灵——这会破坏动画连续性。 * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */ // ─── 配置类型 ───────────────────────────────────────────────────────────────── export type SolitaireConfig = { /** 每次翻牌数量,默认 1(Klondike)或 3(Vegas) */ drawCount: number; /** 翻牌堆循环限制,-1 = 无限,0 = 不可循环 */ stockRecycleLimit: number; /** 是否自动将可用的牌移到目标堆(auto-complete 提示) */ autoComplete: boolean; }; // ─── 核心类型 ───────────────────────────────────────────────────────────────── export type Suit = 'S' | 'H' | 'D' | 'C'; // 黑桃、红心、方块、梅花 export type CardColor = 'red' | 'black'; export type CardValue = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13; export type Card = { suit: Suit; value: CardValue; // 1=A, 11=J, 12=Q, 13=K faceUp: boolean; color: CardColor; // H/D=red, S/C=black }; /** 移牌来源/目标位置 */ export type ZoneRef = | { zone: 'tableau'; col: number } // 7 列牌堆,col 0~6 | { zone: 'foundation'; suit: Suit } // 4 个花色目标堆 | { zone: 'waste' }; // 废牌堆顶 // ─── 动作类型 ───────────────────────────────────────────────────────────────── export type SolitaireAction = | { type: 'move_cards'; from: ZoneRef; to: ZoneRef; count: number } | { type: 'draw_from_stock' } | { type: 'recycle_stock' } | { type: 'auto_complete' } | { type: 'reset' }; // ─── 状态类型 ───────────────────────────────────────────────────────────────── export type SolitaireState = { /** 7 列牌堆,tableau[col] = Card[] 从底到顶 */ tableau: Card[][]; /** 备用牌堆(未翻开),stock[0] 是顶部 */ stock: Card[]; /** 废牌堆(已翻开),waste[waste.length-1] 是顶部 */ waste: Card[]; /** 4 个花色目标堆,foundations[suit] = Card[] 从 A 到顶 */ foundations: Record; /** 翻牌堆已循环次数 */ stockRecycleCount: number; /** 游戏是否结束 */ gameOver: boolean; /** 是否胜利(所有牌进入 foundations) */ win: boolean; /** 上一次操作是否触发了自动翻牌 */ lastFlipped: boolean; /** 上一次翻开的牌所在列(用于渲染层播放翻牌动画) */ lastFlippedCol: number | null; /** 所有牌是否都已翻面(触发 auto-complete 提示) */ allFaceUp: boolean; }; // ─── 分步操作返回类型 ───────────────────────────────────────────────────────── /** 合法移动描述 */ export type ValidMove = { from: ZoneRef; to: ZoneRef; count: number; /** 是否为移到 foundation 的操作(通常优先级更高) */ toFoundation: boolean; }; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 必须导出的函数 // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ─── 初始化 ────────────────────────────────────────────────────────────────── /** * init:初始化 Klondike 纸牌接龙 * - 随机洗52张牌 * - 第 i 列(1-indexed)发 i 张牌,最顶部翻面 * - 剩余牌放入 stock */ export declare function init(config: SolitaireConfig): SolitaireState; // ─── 一体化接口(测试/AI 模拟用) ─────────────────────────────────────────── /** * dispatch:接收动作,返回新状态(纯函数,不得修改原 state) * ⚠️ 仅用于无头测试和 AI 模拟。渲染层请使用下方分步函数。 */ export declare function dispatch(state: SolitaireState, action: SolitaireAction): SolitaireState; /** * getState:返回当前状态快照 */ export declare function getState(state: SolitaireState): SolitaireState; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 分步函数(渲染层/场景层必须使用这些函数) // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ /** * canMoveToTableau:验证将指定牌移到目标列是否合法 * 规则:颜色交替(红↔黑),数值 = 目标列顶牌值 - 1;空列只接受 K * * 渲染层在玩家拖动牌到列时调用,若返回 false 则播放弹回动画 */ export declare function canMoveToTableau( state: SolitaireState, card: Card, targetCol: number, ): boolean; /** * canMoveToFoundation:验证将指定牌移到目标堆是否合法 * 规则:同花色,值 = 目标堆顶牌值 + 1;空堆只接受 A(value == 1) * * 渲染层在玩家双击牌时调用,自动移到 foundation */ export declare function canMoveToFoundation( state: SolitaireState, card: Card, ): boolean; /** * moveCards:执行移牌操作 * - 支持从 tableau/waste 移到 tableau/foundation * - 移完后自动翻开源列新顶牌(若 faceDown) * - 更新 lastFlipped 和 lastFlippedCol * - 检测胜利条件 * * 渲染层在验证合法后调用,根据 lastFlipped 决定是否播放翻牌动画 */ export declare function moveCards( state: SolitaireState, from: ZoneRef, to: ZoneRef, count: number, ): SolitaireState; /** * drawFromStock:从备用堆翻 drawCount 张牌到 waste(faceUp) * 若 stock 为空则循环(受 stockRecycleLimit 限制) * * 渲染层在玩家点击备用堆时调用,播放翻牌动画 */ export declare function drawFromStock(state: SolitaireState): SolitaireState; /** * getValidMoves:获取当前状态下所有合法的移动 * 用于:1) AI 自动解牌;2) 检测是否无解(no valid moves);3) 提示功能 * * 性能注意:完整扫描所有组合,不要在每帧调用 */ export declare function getValidMoves(state: SolitaireState): ValidMove[];