From 376332412bdf9beb025800b383ca7e6e0ac9cb09 Mon Sep 17 00:00:00 2001 From: zhouwei <849588297@qq.com> Date: Mon, 9 Feb 2026 18:59:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B2=A1=E6=9C=89=E5=85=B6=E4=BB=96=E7=89=8C?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=8F=AF=E5=87=BA=EF=BC=8C=E6=89=8D=E8=83=BD?= =?UTF-8?q?=E5=87=BA=E7=82=B8=E5=BC=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/taurus/util/test_smart.java | 196 ++++++++++++++---- 1 file changed, 153 insertions(+), 43 deletions(-) diff --git a/robots/puke/robot_pk_pdk/src/main/java/taurus/util/test_smart.java b/robots/puke/robot_pk_pdk/src/main/java/taurus/util/test_smart.java index fae939b..9849648 100644 --- a/robots/puke/robot_pk_pdk/src/main/java/taurus/util/test_smart.java +++ b/robots/puke/robot_pk_pdk/src/main/java/taurus/util/test_smart.java @@ -211,15 +211,17 @@ public class test_smart { List responseCards = findMatchingResponse(handCards, type, minCard, len); if (responseCards.isEmpty()) { - // 核心规则:要得起必须出!没有对应牌型时必须出炸弹 - List bomb = findSmallestBomb(handCards); - if (!bomb.isEmpty()) { - System.out.println("[强制规则] 无法用对应牌型响应,必须出炸弹"); - return CardUtil.toTArray(bomb); + // 保守策略:只有在特定条件下才使用炸弹 + if (shouldUseBombConservatively(handCards, type, minCard, seatRemainHistory, huNanPaoDeKuai)) { + List bomb = findSmallestBomb(handCards); + if (!bomb.isEmpty()) { + System.out.println("[保守策略] 满足炸弹使用条件,出炸弹"); + return CardUtil.toTArray(bomb); + } } - // 理论上不应该到达这里(有炸弹就必须出) - System.out.println("[警告] 无匹配牌型且无炸弹,违反游戏规则"); + // 无合适牌型且不满足炸弹使用条件时的兜底策略 + System.out.println("[策略] 无匹配牌型且不满足炸弹使用条件"); return emergencyOutCard(handCards); } @@ -657,16 +659,9 @@ public class test_smart { List bestCombo = new ArrayList<>(); int bestScore = 0; - // 评估各种组合牌型的价值 + // 评估各种组合牌型的价值(炸弹不再是最高优先级) - // 1. 炸弹(最高价值) - List bomb = findSmallestBomb(handCards); - if (!bomb.isEmpty()) { - System.out.println("[残局评估] 发现炸弹,价值: 100"); - return bomb; // 炸弹直接使用 - } - - // 2. 飞机带牌 + // 1. 飞机带牌 List airplane = findSmallestAirplaneWithCards(handCards); if (!airplane.isEmpty() && airplane.size() > bestScore) { bestCombo = airplane; @@ -674,7 +669,7 @@ public class test_smart { System.out.println("[残局评估] 发现飞机,价值: " + airplane.size()); } - // 3. 四带二 + // 2. 四带二 List fourWithTwo = findSmallestFourWithTwo(handCards); if (!fourWithTwo.isEmpty() && fourWithTwo.size() > bestScore) { bestCombo = fourWithTwo; @@ -682,7 +677,7 @@ public class test_smart { System.out.println("[残局评估] 发现四带二,价值: " + fourWithTwo.size()); } - // 4. 三带二 + // 3. 三带二 List trioWithTwo = findSmallestTrioWithTwo(handCards); if (!trioWithTwo.isEmpty() && trioWithTwo.size() > bestScore) { bestCombo = trioWithTwo; @@ -690,7 +685,7 @@ public class test_smart { System.out.println("[残局评估] 发现三带二,价值: " + trioWithTwo.size()); } - // 5. 连对 + // 4. 连对 List consecutivePair = findSmallestConsecutivePair(handCards); if (!consecutivePair.isEmpty() && consecutivePair.size() > bestScore) { bestCombo = consecutivePair; @@ -698,15 +693,7 @@ public class test_smart { System.out.println("[残局评估] 发现连对,价值: " + consecutivePair.size()); } - // 6. 对子 - List pair = findSmallestPair(handCards); - if (!pair.isEmpty() && pair.size() > bestScore) { - bestCombo = pair; - bestScore = pair.size(); - System.out.println("[残局评估] 发现对子,价值: " + pair.size()); - } - - // 7. 顺子 + // 5. 顺子 List straight = findSmallestStraight(handCards); if (!straight.isEmpty() && straight.size() > bestScore) { bestCombo = straight; @@ -714,7 +701,7 @@ public class test_smart { System.out.println("[残局评估] 发现顺子,价值: " + straight.size()); } - // 8. 三张 + // 6. 三张 List trio = findSmallestTrio(handCards); if (!trio.isEmpty() && trio.size() > bestScore) { bestCombo = trio; @@ -722,6 +709,22 @@ public class test_smart { System.out.println("[残局评估] 发现三张,价值: " + trio.size()); } + // 7. 对子 + List pair = findSmallestPair(handCards); + if (!pair.isEmpty() && pair.size() > bestScore) { + bestCombo = pair; + bestScore = pair.size(); + System.out.println("[残局评估] 发现对子,价值: " + pair.size()); + } + + // 8. 炸弹(仅在完全没有其他组合时考虑) + List bomb = findSmallestBomb(handCards); + if (!bomb.isEmpty() && bestScore == 0) { // 仅在无其他组合时才考虑 + System.out.println("[残局评估] 无其他组合牌型,考虑使用炸弹"); + return bomb; + } + + if (bestScore > 0) { System.out.println("[残局决策] 选择最佳组合: " + bestCombo.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(","))); } else { @@ -738,7 +741,7 @@ public class test_smart { List bestCombo = new ArrayList<>(); int bestScore = 0; - // 按价值优先级评估组合牌型 + // 按价值优先级评估组合牌型(炸弹优先级降低) // 1. 飞机带牌(最高优先级) List airplane = findSmallestAirplaneWithCards(handCards); @@ -747,14 +750,7 @@ public class test_smart { return airplane; } - // 2. 炸弹 - List bomb = findSmallestBomb(handCards); - if (!bomb.isEmpty()) { - System.out.println("[组合优先] 发现炸弹: " + bomb.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(""))); - return bomb; - } - - // 3. 四带二 + // 2. 四带二 List fourWithTwo = findSmallestFourWithTwo(handCards); if (!fourWithTwo.isEmpty() && fourWithTwo.size() > bestScore) { bestCombo = fourWithTwo; @@ -762,7 +758,7 @@ public class test_smart { System.out.println("[组合优先] 发现四带二: " + fourWithTwo.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(""))); } - // 4. 三带二 + // 3. 三带二 List trioWithTwo = findSmallestTrioWithTwo(handCards); if (!trioWithTwo.isEmpty() && trioWithTwo.size() > bestScore) { bestCombo = trioWithTwo; @@ -770,7 +766,7 @@ public class test_smart { System.out.println("[组合优先] 发现三带二: " + trioWithTwo.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(""))); } - // 5. 连对 + // 4. 连对 List consecutivePair = findSmallestConsecutivePair(handCards); if (!consecutivePair.isEmpty() && consecutivePair.size() > bestScore) { bestCombo = consecutivePair; @@ -778,7 +774,7 @@ public class test_smart { System.out.println("[组合优先] 发现连对: " + consecutivePair.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(""))); } - // 6. 顺子 + // 5. 顺子 List straight = findSmallestStraight(handCards); if (!straight.isEmpty() && straight.size() > bestScore) { bestCombo = straight; @@ -786,7 +782,7 @@ public class test_smart { System.out.println("[组合优先] 发现顺子: " + straight.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(""))); } - // 7. 三张 + // 6. 三张 List trio = findSmallestTrio(handCards); if (!trio.isEmpty() && trio.size() > bestScore) { bestCombo = trio; @@ -794,7 +790,7 @@ public class test_smart { System.out.println("[组合优先] 发现三张: " + trio.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(""))); } - // 8. 对子 + // 7. 对子 List pair = findSmallestPair(handCards); if (!pair.isEmpty() && pair.size() > bestScore) { bestCombo = pair; @@ -802,6 +798,14 @@ public class test_smart { System.out.println("[组合优先] 发现对子: " + pair.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(""))); } + // 8. 炸弹(最低优先级,仅在没有其他组合时考虑) + List bomb = findSmallestBomb(handCards); + if (!bomb.isEmpty() && bestScore == 0) { // 只有在没有任何其他组合时才考虑炸弹 + System.out.println("[组合优先] 无其他组合牌型,考虑使用炸弹"); + return bomb; + } + + if (bestScore > 0) { System.out.println("[组合优先] 选择最佳组合: " + bestCombo.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(""))); } else { @@ -2321,6 +2325,78 @@ public class test_smart { return reportedType; } + /** + * 保守策略判断是否应该使用炸弹 + * 炸弹使用条件(严格按照跑得快规则): + * 1. 对手只剩一张牌 + * 2. 对手出2 + * 3. 自身手牌≤3张 + * 4. 对手出A且手牌≤6张 + * 5. 其他极端情况下的最后手段 + */ + private static boolean shouldUseBombConservatively( + List handCards, + int opponentType, + int opponentMinCard, + Map> seatRemainHistory, + HuNanPaoDeKuai huNanPaoDeKuai) { + + System.out.println("[炸弹策略] 分析是否满足炸弹使用条件"); + + // 条件1:对手只剩一张牌 + if (checkIfAnyOpponentHasOneCard(seatRemainHistory, huNanPaoDeKuai != null ? huNanPaoDeKuai.seat : 0)) { + System.out.println("[炸弹策略] ✓ 对手只剩一张牌,使用炸弹"); + return true; + } + + // 条件2:对手出2 + if (opponentMinCard == CARD_2) { + System.out.println("[炸弹策略] ✓ 对手出2,使用炸弹"); + return true; + } + + // 条件3:自身手牌≤3张 + if (handCards.size() <= 3) { + System.out.println("[炸弹策略] ✓ 手牌很少(" + handCards.size() + "张),使用炸弹"); + return true; + } + + // 条件4:对手出A且手牌≤6张 + if (opponentMinCard == CARD_A && handCards.size() <= 6) { + System.out.println("[炸弹策略] ✓ 对手出A且手牌较少(" + handCards.size() + "张),使用炸弹"); + return true; + } + + // 条件5:其他极端情况(最后手段) + // 比如对手出大牌且自己即将输掉 + if (isExtremeLosingSituation(handCards, opponentType, opponentMinCard)) { + System.out.println("[炸弹策略] ✓ 极端劣势局面,使用炸弹"); + return true; + } + + System.out.println("[炸弹策略] ✗ 不满足炸弹使用条件,保留炸弹"); + return false; + } + + /** 判断是否处于极端劣势局面 */ + private static boolean isExtremeLosingSituation(List handCards, int opponentType, int opponentMinCard) { + // 如果对手出的是大牌(Q及以上)且我们没有更好的应对方式 + if (opponentMinCard >= CARD_Q) { + // 检查是否还有其他组合牌型 + HandAnalysis analysis = analyzeHandComposition(handCards); + int comboTypes = (analysis.pairCount > 0 ? 1 : 0) + + (analysis.trioCount > 0 ? 1 : 0) + + (analysis.straightCount > 0 ? 1 : 0) + + (analysis.consecutivePairCount > 0 ? 1 : 0); + + // 如果几乎没有组合牌型,且对手出大牌,可以考虑使用炸弹 + if (comboTypes <= 1 && handCards.size() <= 8) { + return true; + } + } + return false; + } + /** 智能分析实际牌型 - 真正的AI核心! */ private static int analyzeActualCardType(List cards) { if (cards == null || cards.isEmpty()) return TYPE_SINGLE; @@ -2473,4 +2549,38 @@ public class test_smart { String cardNames = cards.stream().map(c -> getCardName(c.cardMod)).collect(Collectors.joining(",")); return typeName + "[" + cardNames + "]"; } + + // ====================== 测试方法 ====================== + + /** 测试炸弹使用保守策略 */ + public static void testBombConservativeStrategy() { + System.out.println("\n========== 炸弹使用保守策略测试 =========="); + + // 模拟不同场景 + testBombScenario("对手剩1张牌", 15, TYPE_SINGLE, CARD_7, true); + testBombScenario("对手出2", 10, TYPE_SINGLE, CARD_2, true); + testBombScenario("手牌≤3张", 3, TYPE_PAIR, CARD_8, true); + testBombScenario("对手出A且手牌≤6张", 5, TYPE_SINGLE, CARD_A, true); + testBombScenario("正常情况-不应使用炸弹", 12, TYPE_PAIR, CARD_9, false); + } + + private static void testBombScenario(String scenario, int handSize, int opponentType, int opponentMinCard, boolean shouldUseBomb) { + System.out.println("\n测试场景: " + scenario); + System.out.println("手牌数: " + handSize + ", 对手类型: " + getCardTypeName(opponentType) + ", 最小牌: " + getCardName(opponentMinCard)); + + // 创建模拟手牌 + List mockHand = new ArrayList<>(); + for (int i = 0; i < handSize; i++) { + mockHand.add(new CardObj(CARD_3 + (i % 13))); // 简单模拟 + } + + boolean result = shouldUseBombConservatively(mockHand, opponentType, opponentMinCard, null, null); + System.out.println("策略判断: " + (result ? "使用炸弹" : "保留炸弹")); + + if (result == shouldUseBomb) { + System.out.println("✅ 策略判断正确"); + } else { + System.out.println("❌ 策略判断错误,期望: " + (shouldUseBomb ? "使用" : "保留") + "炸弹"); + } + } } \ No newline at end of file