package taurus.util;

import java.util.*;
import java.util.stream.Collectors;

public class ai {

    // 长沙麻将特殊规则：二五八将
    private static final Set<Integer> JIANG_PAIS;

    // 门子类型定义
    private static final int DOOR_NONE = 0;      // 无门子
    private static final int DOOR_BIAN = 1;      // 边张门子 (12/89)
    private static final int DOOR_GE = 2;        // 隔张门子 (13/79/24/68等)
    private static final int DOOR_XIANGLIN = 3;  // 相邻门子 (23/34/45/56/67/78等)
    private static final int DOOR_DUIZI = 4;     // 对子

    public boolean isTinAi = false;
    public boolean   isTingpai = false;

    static {
        Set<Integer> jiangSet = new HashSet<>();
        jiangSet.add(2);
        jiangSet.add(5);
        jiangSet.add(8);
        JIANG_PAIS = Collections.unmodifiableSet(jiangSet);
    }

    // 缓存优化
    private Map<String, Double> scoreCache = new HashMap<>();
    private Map<String, List<Integer>> tingCache = new HashMap<>();

    public static void main(String[] args) {
        System.out.println("=== 长沙麻将测试（含碰杠吃牌） ===");
        ai ai1 = new ai();

        // 测试1：普通手牌
        System.out.println("\n=== 测试1：普通14张牌 ===");
        PlayerState state1 = new PlayerState();
//        state1.handCards = Arrays.asList(208, 204, 203, 202, 107, 106, 105, 103, 102, 101, 101, 208, 206, 207);

//        test1.add(209);
//        test1.add(208);
//        test1.add(208);
//        test1.add(207);
//        test1.add(207);
//        test1.add(206);
//        test1.add(205);
//        test1.add(205);
//        test1.add(202);
//        test1.add(201);
//        test1.add(201);
//        test1.add(107);
//        test1.add(107);
//        test1.add(104);

        state1.handCards = Arrays.asList(209, 209, 208, 207, 206, 205, 203, 202, 202, 202, 108, 105, 104, 103);

//        state1.handCards = Arrays.asList(204, 206, 205, 205, 203, 109, 108, 107, 107, 106, 103, 103, 102, 101);

//        state1.addChiGroup(Arrays.asList(107,108,106));
//        state1.addPongGroup(Arrays.asList(109,109,109));
        int discard1 = ai1.findBestDiscard(state1);
        System.out.println("推荐出牌: " + ai1.formatCard(discard1));
    }


    /**
     * 主方法：根据完整玩家状态推荐出牌
     */
    public int findBestDiscard(PlayerState state) {
        System.out.println("\n=== 长沙麻将AI出牌分析 ===");
        System.out.println("手牌(" + state.handCards.size() + "张): " + formatCards(state.handCards));

        int pongGroups = state.getPongGroupCount();
        int gangGroups = state.getGangGroupCount();
        int chiGroups = state.getChiGroupCount();

        System.out.println("碰牌组数: " + pongGroups +
                "，杠牌组数: " + gangGroups +
                "，吃牌组数: " + chiGroups);

        // 清空缓存
        scoreCache.clear();
        tingCache.clear();

        long startTime = System.currentTimeMillis();

        // 获取可出的牌（手牌中的唯一牌）
        Map<Integer, DiscardResult> results = new HashMap<>();
        Set<Integer> uniqueCards = new HashSet<>(state.handCards);

        // 如果只剩一张牌，直接返回
        if (state.handCards.size() == 1) {
            int onlyCard = state.handCards.get(0);
            System.out.println("只剩一张牌，必须出: " + formatCard(onlyCard));
            return onlyCard;
        }

        for (int card : uniqueCards) {
            // 模拟打出一张牌后的状态
            PlayerState newState = simulateDiscard(state, card);
            DiscardResult result = evaluateDiscardWithState(card, state); // 传入原始状态
            results.put(card, result);

            System.out.printf("打出 %s: 评分=%.3f (听牌=%d张)%n",
                    formatCard(card), result.score, result.tingCards.size());
        }

        // 找出最佳出牌 - 优先考虑听牌数量
        int bestCard = -1;
        double bestScore = Double.NEGATIVE_INFINITY;
        int maxTingCount = 0;

        // 首先找到最大听牌数量
        for (DiscardResult result : results.values()) {
            if (result.tingCards.size() > maxTingCount) {
                maxTingCount = result.tingCards.size();
            }
        }

        // 如果有听牌，优先从听牌中选择
        if (maxTingCount > 0) {
            // 从所有听牌中选择评分最高的
            for (Map.Entry<Integer, DiscardResult> entry : results.entrySet()) {
                if (entry.getValue().tingCards.size() == maxTingCount) {
                    if (entry.getValue().score > bestScore) {
                        bestScore = entry.getValue().score;
                        bestCard = entry.getKey();
                    }
                }
            }
        } else {
            // 没有听牌，选择评分最高的
            for (Map.Entry<Integer, DiscardResult> entry : results.entrySet()) {
                if (entry.getValue().score > bestScore) {
                    bestScore = entry.getValue().score;
                    bestCard = entry.getKey();
                }
            }
        }

        long endTime = System.currentTimeMillis();
        System.out.printf("分析耗时: %dms%n", (endTime - startTime));

        if (bestCard != -1) {
            DiscardResult bestResult = results.get(bestCard);
            System.out.println("\n🎯 AI推荐出牌: " + formatCard(bestCard));
            if (!bestResult.tingCards.isEmpty()) {
                isTinAi = true;
                isTingpai = true;
                System.out.println("✅ 听牌，可听 " + bestResult.tingCards.size() + " 张牌:");
                System.out.println("----牌组----" + bestResult.tingCards);
                if (bestResult.tingCards.size() > 0) {
                    // 如果有ChangShaSuanFaTest类，需要处理
                     ChangShaSuanFaTest.tinCards.clear();
                     ChangShaSuanFaTest.tinCards.addAll(bestResult.tingCards);
                }
                List<String> tingCardsFormatted = bestResult.tingCards.stream()
                        .map(this::formatCard)
                        .collect(Collectors.toList());
                System.out.println("    " + String.join(" ", tingCardsFormatted));
            }
            System.out.println("综合评分: " + String.format("%.3f", bestResult.score));
        }

        return bestCard;
    }

    /**
     * 模拟打出一张牌
     */
    private PlayerState simulateDiscard(PlayerState originalState, int discardCard) {
        PlayerState newState = new PlayerState();

        // 复制手牌并移除要打的牌
        newState.handCards = new ArrayList<>(originalState.handCards);
        newState.handCards.remove((Integer) discardCard);

        // 复制碰牌组
        for (List<Integer> group : originalState.pongGroups) {
            newState.pongGroups.add(new ArrayList<>(group));
        }

        // 复制杠牌组
        for (List<Integer> group : originalState.gangGroups) {
            newState.gangGroups.add(new ArrayList<>(group));
        }

        // 复制吃牌组
        for (List<Integer> group : originalState.chiGroups) {
            newState.chiGroups.add(new ArrayList<>(group));
        }

        newState.isZhuang = originalState.isZhuang;

        return newState;
    }

    private DiscardResult evaluateDiscardWithState(int discardedCard, PlayerState originalState) {
        // 先模拟打出这张牌
        PlayerState simulatedState = simulateDiscard(originalState, discardedCard);
        List<Integer> hand = simulatedState.handCards;
        double totalScore = 0.0;

        // === 1. 基础分 ===
        totalScore += 10.0;

        // === 新增：花色集中度评估 ===
        double suitConcentrationScore = evaluateSuitConcentration(discardedCard, hand);
        totalScore += suitConcentrationScore;

        // === 2. 门子类型评估 ===
        System.out.println("\n=== 评估 " + formatCard(discardedCard) + " ===");

        // 使用原始状态来获取对子信息
        int originalCount = 0;
        for (int c : originalState.handCards) {
            if (c == discardedCard) originalCount++;
        }
        System.out.println("  [原始] " + formatCard(discardedCard) + " 在原始手牌中有 " + originalCount + " 张");

        int doorType = getDoorType(discardedCard, hand, originalState); // 传入原始状态
        double doorScore = evaluateDoorType(doorType, discardedCard);
        totalScore += doorScore;

        System.out.printf("  [门子] 类型=%s, 评分=%.1f%n",
                getDoorTypeName(doorType), doorScore);

        // === 3. 检查是否在完整顺子中 ===
        if (isInCompleteSequence(discardedCard, originalState.handCards)) { // 使用原始状态
            System.out.println("  [顺子] " + formatCard(discardedCard) + " 在完整顺子中");

            if (originalCount > 1) {
                System.out.println("  [冗余] " + formatCard(discardedCard) +
                        " 在顺子中且有多张，加30分鼓励打出");
                totalScore += 30.0;
            } else {
                System.out.println("  [保留] " + formatCard(discardedCard) +
                        " 是顺子中的唯一一张，扣15分");
                totalScore -= 15.0;
            }
        }

        // === 4. 对子和刻子评估 ===
        double pairScore = evaluatePairsAndPongsFinal(discardedCard, originalState); // 传入原始状态
        totalScore += pairScore;

        // === 5. 绝对孤张评估 ===
        if (isAbsolutelyLonelyFinal(discardedCard, hand)) {
            totalScore += 15.0;
            System.out.println("  [孤张] " + formatCard(discardedCard) + " 是绝对孤张，加15分");
        }

        // === 6. 简单结构评估 ===
        double structureScore = evaluateSimpleStructure(discardedCard, hand);
        totalScore += structureScore;

        // === 7. 听牌检查 ===
        List<Integer> tingCards = checkTingCardsWithState(simulatedState);
        if (!tingCards.isEmpty()) {
            totalScore += 100.0;
            totalScore += tingCards.size() * 50.0;

            for (int tingCard : tingCards) {
                int value = getCardValue(tingCard);
                if (JIANG_PAIS.contains(value)) {
                    totalScore += 20.0;
                }
            }
        }

        System.out.printf("  [总分] %.1f%n", totalScore);
        return new DiscardResult(totalScore, tingCards, 0);
    }
    /**
     * 花色集中度评估：优先打散张，保留集中花色的牌
     */
    private double evaluateSuitConcentration(int card, List<Integer> hand) {
        int type = getCardType(card);
        int value = getCardValue(card);

        // 统计该花色的牌数
        int suitCount = 0;
        for (int c : hand) {
            if (getCardType(c) == type) {
                suitCount++;
            }
        }

        double score = 0.0;

        // 如果该花色牌很少（<=3张），优先打
        if (suitCount <= 3) {
            score += 20.0; // 鼓励打散张
        }
        // 如果该花色牌很多（>=8张），尽量不打
        else if (suitCount >= 8) {
            score -= 15.0; // 扣分，尽量不打集中花色的牌
        }

        return score;
    }

    /**
     * 获取门子类型（改进版）
     */
    private int getDoorType(int card, List<Integer> hand, PlayerState state) {
        int type = getCardType(card);
        int value = getCardValue(card);

        if (type > 3) return DOOR_NONE;

        // 使用传入的状态来获取对子信息
        int originalCount = 0;
        for (int c : state.handCards) {
            if (c == card) originalCount++;
        }

        if (originalCount >= 2) {
            return DOOR_DUIZI;
        }

        // 检查边张
        if (value == 1 || value == 9) {
            int adjacent = (value == 1) ? card + 1 : card - 1;
            if (state.handCards.contains(adjacent)) {
                return DOOR_BIAN;
            }
        }

        // 检查相邻门子
        for (int other : state.handCards) {
            if (getCardType(other) == type) {
                int otherValue = getCardValue(other);
                int diff = Math.abs(otherValue - value);

                if (diff == 1) {
                    // 排除12、21、89、98的情况（这些是边张）
                    if ((value == 1 && otherValue == 2) || (value == 2 && otherValue == 1) ||
                            (value == 8 && otherValue == 9) || (value == 9 && otherValue == 8)) {
                        return DOOR_BIAN;
                    }
                    return DOOR_XIANGLIN;
                }
            }
        }

        // 检查隔张
        for (int other : state.handCards) {
            if (getCardType(other) == type) {
                int otherValue = getCardValue(other);
                int diff = Math.abs(otherValue - value);

                if (diff == 2) {
                    return DOOR_GE;
                }
            }
        }

        return DOOR_NONE;
    }    /**
     * 获取门子类型名称
     */
    private String getDoorTypeName(int doorType) {
        switch (doorType) {
            case DOOR_BIAN: return "边张门子";
            case DOOR_GE: return "隔张门子";
            case DOOR_XIANGLIN: return "相邻门子";
            case DOOR_DUIZI: return "对子";
            case DOOR_NONE: return "无门子";
            default: return "未知";
        }
    }

    private double evaluateDoorType(int doorType, int card) {
        double score = 0.0;
        int value = getCardValue(card);
        int type = getCardType(card);

        switch (doorType) {
            case DOOR_BIAN:
                // 边张门子：12或89，依赖性强
                score += 25.0; // 增加分值，更鼓励打边张
                break;

            case DOOR_GE:
                // 隔张门子：差1张才能形成顺子
                if (value == 2 || value == 8) {
                    score += 5.0;
                } else if (value == 3 || value == 7) {
                    score += 8.0;
                } else {
                    score += 10.0;
                }
                break;

            case DOOR_XIANGLIN:
                // 相邻门子：很容易形成顺子，应该保留
                score -= 15.0;
                break;

            case DOOR_DUIZI:
                if (JIANG_PAIS.contains(value)) {
                    // 258将对子是好牌，不应该扣那么多分
                    score -= 20.0;
                } else if (value == 1 || value == 9) {
                    // 边张对子（1万或9万）：价值较低，鼓励打出
                    score += 10.0; // 改为加分，鼓励打出边张对子
                } else if (value == 9 && type == 1) { // 9万对子
                    score -= 15.0;
                } else {
                    score -= 10.0; // 中张对子
                }
                break;

            case DOOR_NONE:
                // 绝对孤张：优先打
                if (JIANG_PAIS.contains(value)) {
                    score += 20.0;
                } else if (value == 1 || value == 9) {
                    // 边张孤张：19是边张，价值最低
                    score += 30.0; // 增加分值，更鼓励打边张孤张
                } else {
                    score += 20.0;
                }
                break;
        }

        return score;
    }
    private boolean isInCompleteSequence(int card, List<Integer> hand) {
        int type = getCardType(card);
        int value = getCardValue(card);

        if (type > 3) return false;

        // 统计该牌在手牌中的数量
        int cardCount = Collections.frequency(hand, card);

        // 如果该牌在手牌中，检查是否能形成顺子
        if (cardCount > 0) {
            // 检查是否能形成123顺子
            if (value == 1) {
                int card2 = card + 1;
                int card3 = card + 2;
                return hand.contains(card2) && hand.contains(card3);
            }
            // 检查是否能形成789顺子
            else if (value == 9) {
                int card7 = card - 2;
                int card8 = card - 1;
                return hand.contains(card7) && hand.contains(card8);
            }
            // 检查其他顺子情况
            else if (value >= 2 && value <= 8) {
                // 检查前顺子
                int prev1 = card - 1;
                int prev2 = card - 2;
                if (value >= 3 && hand.contains(prev1) && hand.contains(prev2)) {
                    return true;
                }
                // 检查后顺子
                int next1 = card + 1;
                int next2 = card + 2;
                if (value <= 7 && hand.contains(next1) && hand.contains(next2)) {
                    return true;
                }
                // 检查中间顺子
                int prev = card - 1;
                int next = card + 1;
                if (hand.contains(prev) && hand.contains(next)) {
                    return true;
                }
            }
        }

        return false;
    }
    /**
     * 简单结构评估（简化版）
     */
    private double evaluateSimpleStructure(int card, List<Integer> hand) {
        double score = 0.0;
        int type = getCardType(card);
        int value = getCardValue(card);

        if (type > 3) return 0.0;

        // 258将特殊处理
        if (JIANG_PAIS.contains(value)) {
            score -= 3.0; // 258将价值较高
        }

        // 边张扣分
        if (value == 1 || value == 9) {
            score -= 2.0;
        }

        return score;
    }

    /**
     * 检查是否在顺子中间
     */
    private boolean isInSequenceMiddle(int card, List<Integer> hand) {
        int type = getCardType(card);
        int value = getCardValue(card);

        if (type > 3) return false;

        // 检查前后是否能形成顺子
        int prevCard = card - 1;
        int nextCard = card + 1;

        // 需要手牌中有前后两张牌
        return hand.contains(prevCard) && hand.contains(nextCard);
    }

    private double evaluatePairsAndPongsFinal(int card, PlayerState state) {
        // 获取原始手牌中该牌的数量
        int originalCount = 0;
        for (int c : state.handCards) {
            if (c == card) originalCount++;
        }

        System.out.println("  [数量] " + formatCard(card) + " 在原始手牌中有 " + originalCount + " 张");

        // 如果有3张或以上，是刻子
        if (originalCount >= 3) {
            System.out.println("  [刻子] " + formatCard(card) + " 是刻子，扣50分");
            return -50.0;
        }

        // 如果有2张，是对子
        if (originalCount == 2) {
            int type = getCardType(card);
            int value = getCardValue(card);

            // 特别处理边张对子（1万或9万）
            if (value == 1 || value == 9) {
                // 边张对子价值最低，特别鼓励打出
                System.out.println("  [边张对子] " + formatCard(card) + " 是边张对子，加60分鼓励打出");
                return 60.0; // 增加边张对子的鼓励分
            }

            // 检查这个对子是否在顺子中且是多余的
            if (isRedundantPairInSequence(card, state.handCards)) {
                System.out.println("  [冗余] " + formatCard(card) + " 是顺子中的冗余对子，加40分鼓励打出");
                return 40.0;
            }

            // 258将的对子要保留
            if (JIANG_PAIS.contains(value)) {
                System.out.println("  [258将] " + formatCard(card) + " 是258将对子，扣30分");
                return -30.0;
            }

            // 普通对子
            System.out.println("  [对子] " + formatCard(card) + " 是普通对子，扣10分");
            return -10.0;
        }

        System.out.println("  [单张] " + formatCard(card) + " 是单张");
        return 0.0;
    }
    private boolean isRedundantPairInSequence(int card, List<Integer> originalHand) {
        int type = getCardType(card);
        int value = getCardValue(card);

        if (type > 3) return false;

        // 统计原始手牌中该牌的数量
        int count = Collections.frequency(originalHand, card);
        if (count < 2) return false; // 不是对子

        System.out.println("  [检查冗余] " + formatCard(card) + " 是" + count + "张的对子");

        // 特别处理边张（1万或9万）
        if (value == 1) {
            // 1万对子，检查是否能和2、3形成顺子
            int card2 = card + 1;
            int card3 = card + 2;
            if (originalHand.contains(card2) && originalHand.contains(card3)) {
                System.out.println("  [边张冗余] " + formatCard(card) + " 是1万且在1-2-3顺子中，应该优先打出");
                return true;
            }
        } else if (value == 9) {
            // 9万对子，检查是否能和7、8形成顺子
            int card7 = card - 2;
            int card8 = card - 1;
            if (originalHand.contains(card7) && originalHand.contains(card8)) {
                System.out.println("  [边张冗余] " + formatCard(card) + " 是9万且在7-8-9顺子中，应该优先打出");
                return true;
            }
        }

        // 对于3万，检查是否有1万和2万形成顺子
        if (value == 3) {
            int card1 = card - 2; // 1万
            int card2 = card - 1; // 2万

            boolean has1 = originalHand.contains(card1);
            boolean has2 = originalHand.contains(card2);

            System.out.println("  [顺子检查] 1万=" + has1 + ", 2万=" + has2);

            // 如果有1万和2万，且3万有2张，那么多余的1张3万应该打出
            if (has1 && has2) {
                System.out.println("  [确定冗余] " + formatCard(card) + " 在1-2-3顺子中是多余的");
                return true;
            }
        }

        // 检查其他顺子情况
        if (value >= 1 && value <= 7) {
            int next1 = card + 1;
            int next2 = card + 2;
            if (originalHand.contains(next1) && originalHand.contains(next2)) {
                System.out.println("  [确定冗余] " + formatCard(card) + " 在" + value + "-" +
                        getCardValue(next1) + "-" + getCardValue(next2) + "顺子中是多余的");
                return true;
            }
        }

        if (value >= 2 && value <= 8) {
            int prev = card - 1;
            int next = card + 1;
            if (originalHand.contains(prev) && originalHand.contains(next)) {
                System.out.println("  [确定冗余] " + formatCard(card) + " 在" +
                        getCardValue(prev) + "-" + value + "-" + getCardValue(next) + "顺子中是多余的");
                return true;
            }
        }

        if (value >= 3 && value <= 9) {
            int prev1 = card - 1;
            int prev2 = card - 2;
            if (originalHand.contains(prev1) && originalHand.contains(prev2)) {
                System.out.println("  [确定冗余] " + formatCard(card) + " 在" +
                        getCardValue(prev2) + "-" + getCardValue(prev1) + "-" + value + "顺子中是多余的");
                return true;
            }
        }

        return false;
    }


    private boolean isAbsolutelyLonelyFinal(int card, List<Integer> hand) {
        int type = getCardType(card);
        int value = getCardValue(card);

        if (type > 3) return false;

        // 检查同花色牌
        for (int other : hand) {
            if (getCardType(other) == type) {
                int diff = Math.abs(getCardValue(other) - value);
                if (diff <= 2) { // 相邻或隔张
                    return false;
                }
            }
        }

        return true;
    }

    // 以下是原有方法，保持不变...
    // checkTingCardsWithState, canHuWithState, canHuWith258, canFormMelds,
    // getReasonableHuCards, getStateKey, getCardValue, getCardType,
    // formatCard, formatCards

    /**
     * 检查听牌情况
     */
    public List<Integer> checkTingCardsWithState(PlayerState state) {
        String stateKey = getStateKey(state);
        if (tingCache.containsKey(stateKey)) {
            return tingCache.get(stateKey);
        }

        List<Integer> tingCards = new ArrayList<>();

        int pongGroups = state.getPongGroupCount();
        int gangGroups = state.getGangGroupCount();
        int chiGroups = state.getChiGroupCount();

        // 计算已使用的牌数
        int usedCardsCount = pongGroups * 3 + gangGroups * 4 + chiGroups * 3;

        // 听牌时手牌数量应为：14 - 已使用的牌数 - 1（要胡的牌）
        int expectedHandCount = 14 - usedCardsCount - 1;

        if (state.handCards.size() != expectedHandCount) {
            tingCache.put(stateKey, tingCards);
            return tingCards;
        }

        // 获取合理的胡牌候选
        Set<Integer> possibleHuCards = getReasonableHuCards(state.handCards);

        for (int huCard : possibleHuCards) {
            if (canHuWithState(state, huCard)) {
                tingCards.add(huCard);
            }
        }

        tingCache.put(stateKey, tingCards);
        return tingCards;
    }

    /**
     * 胡牌检查
     */
    private boolean canHuWithState(PlayerState state, int huCard) {
        int totalHandCards = state.handCards.size() + 1;
        int pongCardsCount = state.getPongGroupCount() * 3;
        int gangCardsCount = state.getGangGroupCount() * 4;
        int chiCardsCount = state.getChiGroupCount() * 3;
        int totalCards = totalHandCards + pongCardsCount + gangCardsCount + chiCardsCount;

        if (totalCards != 14) {
            return false;
        }

        List<Integer> remainingHand = new ArrayList<>(state.handCards);
        remainingHand.add(huCard);
        Collections.sort(remainingHand);

        return canHuWith258(remainingHand);
    }

    /**
     * 检查手牌是否能胡牌（考虑258将）
     */
    private boolean canHuWith258(List<Integer> hand) {
        if (hand.size() != 2 && hand.size() != 5 && hand.size() != 8 && hand.size() != 11 && hand.size() != 14) {
            return false;
        }

        List<Integer> sortedHand = new ArrayList<>(hand);
        Collections.sort(sortedHand);

        // 尝试所有可能的将牌
        for (int i = 0; i < sortedHand.size() - 1; i++) {
            if (sortedHand.get(i).equals(sortedHand.get(i + 1))) {
                int cardValue = getCardValue(sortedHand.get(i));
                if (JIANG_PAIS.contains(cardValue)) {
                    List<Integer> tempHand = new ArrayList<>(sortedHand);
                    tempHand.remove(i);
                    tempHand.remove(i);

                    if (canFormMelds(tempHand)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * 检查是否能组成全部顺子/刻子
     */
    private boolean canFormMelds(List<Integer> hand) {
        if (hand.isEmpty()) {
            return true;
        }

        List<Integer> sorted = new ArrayList<>(hand);
        Collections.sort(sorted);

        // 尝试刻子
        if (sorted.size() >= 3 &&
                sorted.get(0).equals(sorted.get(1)) &&
                sorted.get(1).equals(sorted.get(2))) {
            List<Integer> newHand = new ArrayList<>(sorted);
            newHand.remove(0);
            newHand.remove(0);
            newHand.remove(0);
            if (canFormMelds(newHand)) {
                return true;
            }
        }

        // 尝试顺子
        if (sorted.size() >= 3) {
            int first = sorted.get(0);
            int type = getCardType(first);

            if (type <= 3) {
                int second = first + 1;
                int third = first + 2;

                if (sorted.contains(second) && sorted.contains(third)) {
                    List<Integer> newHand = new ArrayList<>(sorted);
                    newHand.remove((Integer) first);
                    newHand.remove((Integer) second);
                    newHand.remove((Integer) third);
                    if (canFormMelds(newHand)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * 获取合理的胡牌候选
     */
    private Set<Integer> getReasonableHuCards(List<Integer> hand) {
        Set<Integer> possibleCards = new HashSet<>();

        // 现有牌和相邻牌
        for (int card : hand) {
            possibleCards.add(card);
            int type = getCardType(card);
            if (type <= 3) {
                int value = getCardValue(card);
                if (value > 1) possibleCards.add(card - 1);
                if (value < 9) possibleCards.add(card + 1);
            }
        }

        // 所有258牌
        for (int type = 1; type <= 3; type++) {
            for (int jiang : JIANG_PAIS) {
                possibleCards.add(type * 100 + jiang);
            }
        }

        // 限制数量
        if (possibleCards.size() > 15) {
            List<Integer> list = new ArrayList<>(possibleCards);
            Collections.shuffle(list);
            possibleCards = new HashSet<>(list.subList(0, 15));
        }

        return possibleCards;
    }

    /**
     * 生成状态key
     */
    private String getStateKey(PlayerState state) {
        List<Integer> sortedHand = new ArrayList<>(state.handCards);
        Collections.sort(sortedHand);

        List<String> pongKeys = new ArrayList<>();
        for (List<Integer> group : state.pongGroups) {
            List<Integer> sorted = new ArrayList<>(group);
            Collections.sort(sorted);
            pongKeys.add(sorted.toString());
        }
        Collections.sort(pongKeys);

        List<String> gangKeys = new ArrayList<>();
        for (List<Integer> group : state.gangGroups) {
            List<Integer> sorted = new ArrayList<>(group);
            Collections.sort(sorted);
            gangKeys.add(sorted.toString());
        }
        Collections.sort(gangKeys);

        List<String> chiKeys = new ArrayList<>();
        for (List<Integer> group : state.chiGroups) {
            List<Integer> sorted = new ArrayList<>(group);
            Collections.sort(sorted);
            chiKeys.add(sorted.toString());
        }
        Collections.sort(chiKeys);

        return sortedHand.toString() + "|" +
                pongKeys.toString() + "|" +
                gangKeys.toString() + "|" +
                chiKeys.toString();
    }

    /**
     * 获取牌值
     */
    private int getCardValue(int card) {
        return card % 10;
    }

    /**
     * 获取牌类型
     */
    private int getCardType(int card) {
        return card / 100;
    }

    /**
     * 格式化单张牌
     */
    String formatCard(int card) {
        int type = card / 100;
        int value = card % 10;
        switch (type) {
            case 1:
                return value + "万";
            case 2:
                return value + "筒";
            case 3:
                return value + "条";
            default:
                return "字牌";
        }
    }

    /**
     * 格式化牌列表
     */
    private String formatCards(List<Integer> cards) {
        return cards.stream()
                .map(this::formatCard)
                .collect(Collectors.joining(" "));
    }

    /**
     * 出牌结果类
     */
    private static class DiscardResult {
        double score;
        List<Integer> tingCards;
        int searchDepth;

        DiscardResult(double score, List<Integer> tingCards, int searchDepth) {
            this.score = score;
            this.tingCards = tingCards;
            this.searchDepth = searchDepth;
        }
    }
}