Browse Source

解决牌型问题

johnclot69 2 months ago
parent
commit
21ab1ffb78
1 changed files with 208 additions and 10 deletions
  1. 208 10
      incubator-game/src/main/java/com/incubator/game/util/GDUtils.java

+ 208 - 10
incubator-game/src/main/java/com/incubator/game/util/GDUtils.java

@@ -198,13 +198,13 @@ public final class GDUtils {
                 return compareTripleWithTwo(previousPoints, currentPoints, curLevel, wildCardCountCurrent, wildCardCountPrevious);
             case TRIPLE_SEQUENCE:
                 // 三顺(二个连续三张)
-//                break;
+                return compareThreeConsecutive(previousPoints, currentPoints, curLevel, wildCardCountCurrent, wildCardCountPrevious);
             case STRAIGHT:
                 // 顺子:赖子牌可以补齐顺子
-//                return compareStraight(previousPoints, currentPoints, curLevel, wildCardCountCurrent, wildCardCountPrevious);
+                return compareStraight(previousPoints, currentPoints, curLevel, wildCardCountCurrent, wildCardCountPrevious);
             case BOMB:
                 // 炸弹:赖子牌可以增强炸弹的级别
-//                return compareBomb(previousPoints, currentPoints, wildCardCountCurrent, wildCardCountPrevious);
+                return compareBomb(previousPoints, currentPoints, wildCardCountCurrent, wildCardCountPrevious);
             default:
                 // 默认按最大点数比较
                 return Integer.compare(
@@ -485,6 +485,199 @@ public final class GDUtils {
         return Integer.compare(maxCurrentTriple, maxPreviousTriple);
     }
 
+    /**
+     * 比较两组三张连续牌型的大小,支持赖子牌的处理
+     *
+     * @param previousPoints 上一手牌的点数列表(三张连续牌)
+     * @param currentPoints 当前手牌的点数列表(三张连续牌)
+     * @param curLevel 当前级数(主牌)
+     * @param wildCardCountCurrent 当前手牌的赖子数量
+     * @param wildCardCountPrevious 上一手牌的赖子数量
+     * @return 正数表示当前牌较大,负数表示上一手牌较大,0表示相等
+     */
+    private static int compareThreeConsecutive(List<Integer> previousPoints, List<Integer> currentPoints, int curLevel, int wildCardCountCurrent, int wildCardCountPrevious) {
+        // 替换赖子牌为当前级牌点数,形成有效的三张连续牌
+        List<Integer> adjustedPrevious = replaceWildCardsWithTrump(previousPoints, wildCardCountPrevious, curLevel, 3);
+        List<Integer> adjustedCurrent = replaceWildCardsWithTrump(currentPoints, wildCardCountCurrent, curLevel, 3);
+
+        // 判断上一手牌和当前手牌的强度
+        int previousStrength = calculateHandStrength(adjustedPrevious, wildCardCountPrevious);
+        int currentStrength = calculateHandStrength(adjustedCurrent, wildCardCountCurrent);
+
+        // 如果当前牌比上一手牌强,返回1
+        if (currentStrength > previousStrength) {
+            return 1;
+        }
+        // 如果上一手牌比当前牌强,返回-1
+        if (currentStrength < previousStrength) {
+            return -1;
+        }
+
+        // 如果两手牌的强度相同,按点数进行比较
+        return compareByPoints(adjustedPrevious, adjustedCurrent);
+    }
+
+    /**
+     * 计算手牌的强度(考虑赖子牌替换后的牌型)
+     * @param points 调整后的点数列表
+     * @param wildCardCount 赖子牌数量
+     * @return 该手牌的强度值
+     */
+    private static int calculateHandStrength(List<Integer> points, int wildCardCount) {
+        // 如果有赖子牌,根据赖子的数量来决定牌型的强度
+        if (wildCardCount == 0) {
+            // 没有赖子牌,则返回手牌的最大点数
+            return points.get(points.size() - 1);
+        }
+
+        // 赖子牌数量 > 0 时,尝试使用赖子提升最大点数
+        int adjustedStrength = points.get(points.size() - 1); // 先按最大牌计算
+        // 如果赖子数量比较多,可能有机会改变牌型的强度,考虑赖子的替换效果
+        if (wildCardCount > 1) {
+            adjustedStrength += 1;  // 假设通过赖子牌,我们可以增加一张更高的牌
+        }
+        return adjustedStrength;
+    }
+
+    /**
+     * 比较两手牌的点数
+     * @param previousPoints 上一手牌的点数列表
+     * @param currentPoints 当前手牌的点数列表
+     * @return 正数表示当前牌较大,负数表示上一手牌较大,0表示相等
+     */
+    private static int compareByPoints(List<Integer> previousPoints, List<Integer> currentPoints) {
+        // 先比较最大点数
+        int maxPrevious = getMaxConsecutiveValue(previousPoints);
+        int maxCurrent = getMaxConsecutiveValue(currentPoints);
+
+        // 如果当前牌的最大点数较大,返回1
+        if (maxCurrent > maxPrevious) {
+            return 1;
+        }
+        // 如果上一手牌的最大点数较大,返回-1
+        if (maxCurrent < maxPrevious) {
+            return -1;
+        }
+
+        // 如果最大点数相同,比较最小点数
+        int minPrevious = getMinConsecutiveValue(previousPoints);
+        int minCurrent = getMinConsecutiveValue(currentPoints);
+
+        return Integer.compare(minCurrent, minPrevious);
+    }
+
+    /**
+     * 获取连续三张牌的最大点数(即三张中的最大牌)
+     *
+     * @param points 调整后的点数列表
+     * @return 三张牌中的最大点数
+     */
+    private static int getMaxConsecutiveValue(List<Integer> points) {
+        return points.get(points.size() - 1); // 假设牌已经是顺序排列
+    }
+
+    /**
+     * 获取连续三张牌的最小点数(即三张中的最小牌)
+     *
+     * @param points 调整后的点数列表
+     * @return 三张牌中的最小点数
+     */
+    private static int getMinConsecutiveValue(List<Integer> points) {
+        return points.get(0); // 假设牌已经是顺序排列
+    }
+
+    /**
+     * 比较顺子牌型的大小(考虑赖子牌的补充)
+     *
+     * @param previousPoints 上一手牌的点数列表
+     * @param currentPoints 当前手牌的点数列表
+     * @param curLevel 当前级数(主牌)
+     * @param wildCardCountCurrent 当前手牌的赖子数量
+     * @param wildCardCountPrevious 上一手牌的赖子数量
+     * @return 正数表示当前牌较大,负数表示上一手牌较大,0表示相等
+     */
+    private static int compareStraight(List<Integer> previousPoints, List<Integer> currentPoints, int curLevel, int wildCardCountCurrent, int wildCardCountPrevious) {
+        // 替换赖子牌为当前级牌点数,形成有效的顺子
+        List<Integer> adjustedPrevious = replaceWildCardsWithTrump(previousPoints, wildCardCountPrevious, curLevel, 5);
+        List<Integer> adjustedCurrent = replaceWildCardsWithTrump(currentPoints, wildCardCountCurrent, curLevel, 5);
+
+        // 获取每手牌的最大顺子点数
+        int maxPreviousStraight = getMaxStraightValue(adjustedPrevious);
+        int maxCurrentStraight = getMaxStraightValue(adjustedCurrent);
+
+        // 如果当前顺子的最大点数较大,返回1
+        if (maxCurrentStraight > maxPreviousStraight) {
+            return 1;
+        }
+        // 如果上一手牌的最大点数较大,返回-1
+        if (maxCurrentStraight < maxPreviousStraight) {
+            return -1;
+        }
+
+        // 如果顺子的最大点数相同,比较顺子的最小点数(头牌)
+        int minPreviousStraight = getMinStraightValue(adjustedPrevious);
+        int minCurrentStraight = getMinStraightValue(adjustedCurrent);
+
+        return Integer.compare(minCurrentStraight, minPreviousStraight);
+    }
+
+    /**
+     * 获取顺子的最大点数(即顺子中的最大牌)
+     *
+     * @param points 调整后的点数列表
+     * @return 顺子的最大点数
+     */
+    private static int getMaxStraightValue(List<Integer> points) {
+        // 顺子应该由连续的五张牌组成,获取顺子的最大点数
+        return points.get(points.size() - 1);
+    }
+
+    /**
+     * 获取顺子的最小点数(即顺子中的最小牌)
+     *
+     * @param points 调整后的点数列表
+     * @return 顺子的最小点数
+     */
+    private static int getMinStraightValue(List<Integer> points) {
+        // 顺子应该由连续的五张牌组成,获取顺子的最小点数
+        return points.get(0);
+    }
+
+    /**
+     * 比较炸弹牌型的大小(考虑赖子牌的增强)
+     *
+     * @param previousPoints 上一手牌的点数列表
+     * @param currentPoints 当前手牌的点数列表
+     * @param wildCardCountCurrent 当前手牌中的赖子数量
+     * @param wildCardCountPrevious 上一手牌中的赖子数量
+     * @return 正数表示当前牌较大,负数表示上一手牌较大,0表示相等
+     */
+    private static int compareBomb(List<Integer> previousPoints, List<Integer> currentPoints, int wildCardCountCurrent, int wildCardCountPrevious) {
+        // 获取上一手牌和当前手牌中的最大炸弹点数
+        int maxPreviousBomb = getMaxFrequencyCard(previousPoints, 4);
+        int maxCurrentBomb = getMaxFrequencyCard(currentPoints, 4);
+
+        // 如果当前手牌的炸弹点数较大,返回1
+        if (maxCurrentBomb > maxPreviousBomb) {
+            return 1;
+        }
+        // 如果上一手牌的炸弹点数较大,返回-1
+        if (maxCurrentBomb < maxPreviousBomb) {
+            return -1;
+        }
+
+        // 如果炸弹点数相同,考虑赖子的数量,赖子越多,炸弹越强
+        if (wildCardCountCurrent > wildCardCountPrevious) {
+            return 1;  // 当前手牌有更多赖子,炸弹更强
+        }
+        if (wildCardCountCurrent < wildCardCountPrevious) {
+            return -1; // 上一手牌有更多赖子,炸弹更强
+        }
+
+        // 如果炸弹点数和赖子数量都相同,则返回平局
+        return 0;
+    }
+
     /**
      * 获取指定频率的最大点数
      *
@@ -640,18 +833,18 @@ public final class GDUtils {
             return CardType.STRAIGHT;
         }
 
-        // 6. 连对(赖子可补齐缺失对数)
-        if (cardCount >= 6 && cardCount % 2 == 0 && uniqueCount + wildCount >= cardCount / 2
-                && isPairSequenceWithWild(pointFrequency, wildCount)) {
-            return CardType.PAIR_SEQUENCE;
-        }
-
-        // 7. 三顺(赖子可补齐缺失三张)
+        // 6. 三顺(赖子可补齐缺失三张)
         if (cardCount >= 6 && cardCount % 3 == 0 && uniqueCount + wildCount >= cardCount / 3
                 && isTripleSequenceWithWild(pointFrequency, wildCount)) {
             return CardType.TRIPLE_SEQUENCE;
         }
 
+        // 7. 连对(赖子可补齐缺失对数)
+        if (cardCount >= 6 && cardCount % 2 == 0 && uniqueCount + wildCount >= cardCount / 2
+                && isPairSequenceWithWild(pointFrequency, wildCount)) {
+            return CardType.PAIR_SEQUENCE;
+        }
+
         // 8. 三带二
         if (cardCount == 5 && uniqueCount <= 3 && isTripleWithTwo(pointFrequency, wildCount)) {
             return CardType.TRIPLE_WITH_TWO;
@@ -770,6 +963,10 @@ public final class GDUtils {
                 .sorted()
                 .collect(Collectors.toList());
 
+        // 如果没有符合条件的三张连续牌,直接返回 false
+        if (triples.isEmpty()) {
+            return false;
+        }
         // 排除特例:A-A-A-2-2-2 是有效的最小三顺
         if (triples.contains(14) && triples.contains(2)) { // A 和 2 的点数
             return true; // A-A-A-2-2-2 不是有效的三顺
@@ -790,6 +987,7 @@ public final class GDUtils {
             }
             gaps += (int) (3 - pointFrequency.get(triples.get(i)));
         }
+        // 最后一个元素也需要处理
         gaps += (int) (3 - pointFrequency.get(triples.get(triples.size() - 1)));
         return gaps <= wildCount;
     }