java - 确定 Indian Rummy 手牌是否获胜 - Java

标签 java

我正在寻找一种有效的解决方案来确定一手牌在印度拉米纸牌游戏中是否获胜。印度拉米在融合方面类似于杜松子拉米。人们可以将相同花色的序列(直线)组合在一起,也可以将一组相同的值组合在一起。序列和系列都应至少包含 3 张牌。与金拉米不同,在印度拉米中,一手牌由 13 张牌组成。一手获胜的牌应包含至少两个序列,并且这些序列中至少有一个必须是纯序列。所谓纯粹,我的意思是不应该在 clown (通配符)的帮助下制作序列。这手牌的其余部分可以由带有或不带有王牌的序列和组合组成。注意:除了一副牌 (52 + 2) 中的 2 张王牌外,牌库中还有一张随机牌用作王牌。例如,如果黑桃 5 被随机选为王牌,则牌组中其他花色的剩余三个 5 可以用作 2 个常规王牌之上的王牌。

以下是一些不使用王牌的有效获胜手牌示例:

  • A,K,Q,J(黑桃)|2,3,4(红心)|2,2,2(黑桃,梅花,方 block )|3,4,5(方 block )
  • A、K、Q、J、10(黑桃)|4、5、6、7、8(梅花)|9、9、9(方 block 、梅花、黑桃)
  • A,K,Q,J,10,9,8,7,6,5(黑桃)|4,3,2(黑桃)

以下是一些使用王牌获胜的例子。假设 6(黑桃)是从一副牌中随机抽取的 clown ;所以剩下的所有 6 都可以用作 clown 。

  • A,K,Q,J(黑桃;纯序列)|7,7,7(方 block ,梅花,黑桃)|3,3,6(方 block ,梅花,梅花;设置百搭)|A,2 ,6(梅花,梅花,红心)
  • A,2,3(红心)|4,5,6(红心)|7,7,7,7(黑桃,梅花,方 block ,红心)|8,6,10, clown (黑桃,方 block ,黑桃;王牌、6 和普通王牌的顺序)

以下是一些不是获胜手的例子:

  • A,2,Joker(hearts)|4,5,Joker(hearts)|7,7,7,7(all suits)|9,9,9(梅花,diamonds,hearts)(这不是有效手牌,因为它不包含纯序列)
  • A,2,3,4(红心)|7,7,7(梅花,钻石,红心)|8,8,8(梅花,钻石,红桃)|9,9,9(梅花,钻石, hearts)(这是无效的,因为它不包含第二个序列)

我希望这已经解释了什么是获胜的手。下面的模型代表一张卡片:

public class Card {

public final static int SPADES = 0,
        HEARTS = 1,
        DIAMONDS = 2,
        CLUBS = 3;

public final static int ACE = 1,
        JACK = 11,
        QUEEN = 12,
        KING = 13,
        JOKER = 0;

private final int suit;

private final int value;

public Card(int theValue, int theSuit) {
    value = theValue;
    suit = theSuit;
}

public int getSuit() {
    return suit;
}

public int getValue() {
    return value;
}

public String getSuitAsString() {
    switch ( suit ) {
        case SPADES:   return "Spades";
        case HEARTS:   return "Hearts";
        case DIAMONDS: return "Diamonds";
        case CLUBS:    return "Clubs";
        default:       return "??";
    }
}

public String getValueAsString() {
    switch ( value ) {
        case 1:   return "Ace";
        case 2:   return "2";
        case 3:   return "3";
        case 4:   return "4";
        case 5:   return "5";
        case 6:   return "6";
        case 7:   return "7";
        case 8:   return "8";
        case 9:   return "9";
        case 10:  return "10";
        case 11:  return "Jack";
        case 12:  return "Queen";
        case 13:  return "King";
        default:  return "JOKER";
    }
}

@Override
public String toString() {
    return getValueAsString().equals("JOKER") ? "JOKER" : getValueAsString() + "(" + getSuitAsString() + ")";
}

@Override
public boolean equals(Object card) {
    return suit == ((Card) card).getSuit() && value == ((Card) card).getValue();
}

我还写了一些函数来获取卡片中可能的序列和集合。 getSequences 函数中的参数 (List) 已经按花色排序,然后按值排序。对于 getSets 函数中的参数,卡片仅按值排序。两个函数中第二个参数 (min) 的值均为 3。

private List<List<Card>> getSequences(List<Card> hand, int min) {
    List<List<Card>> sequences = new ArrayList<>();
    List<Card> sequence = new ArrayList<>();
    for(int i=1; i<hand.size(); i++) {
        if(hand.get(i).getSuit() == hand.get(i-1).getSuit() &&
                (hand.get(i).getValue() - hand.get(i-1).getValue()) == 1) {
            sequence.add(hand.get(i-1));
            if(hand.get(i).getValue() == 13) {
                int j = i;
                while(hand.get(j).getSuit() == hand.get(i).getSuit()) {
                    j--;
                    if(hand.get(j).getValue() == 1) {
                        sequence.add(hand.get(j));
                    }
                }
            }
            if(i == hand.size() -1) {
                sequence.add(hand.get(i));
                sequences.add(sequence);
            }
        } else {
            sequence.add(hand.get(i-1));
            if(sequence.size() >= min) {
                sequences.add(sequence);
            }
            sequence = new ArrayList<>();
        }
    }
    return sequences;
}

private List<List<Card>> getSets(List<Card> hand, int min) {
    List<List<Card>> sets = new ArrayList<>();
    List<Card> set = new ArrayList<>();
    for(int i=1; i<hand.size(); i++) {
        if(hand.get(i).getValue() != joker.getValue()) {
            if(hand.get(i).getValue() == hand.get(i-1).getValue()) {
                set.add(hand.get(i-1));
                if(i == hand.size() -1) {
                    set.add(hand.get(i));
                }
            } else {
                set.add(hand.get(i-1));
                if(set.size() >= min) {
                    sets.add(set);
                }
                set = new ArrayList<>();
            }
        }
    }
    return sets;
}

我认为这不是查找序列和集合的最优雅的方法。因此,我欢迎任何关于如何改进它的建议。但我真正需要帮助的是我接下来该做什么?集合和序列之间可能存在重叠。例如,对于以下卡片:

  • A,2,3(黑桃)|4,4,4(黑桃,梅花,红桃) 我的 getSequences 函数将返回 A,2,3,4(spades) 作为序列。我应该避免在我的序列中包含黑桃 4,因为它会被用在 4 组中。

请建议如何有效地确定获胜手。

P.S:在确定获胜手牌时,玩家手中将有14张牌。融合 13 张牌后,第 14 张牌将被丢弃。

最佳答案

我已经实现了 Rummikub 的 java 版本(具有类似限制的游戏)。

我的方法是给每张卡片一个隐藏的整数属性(质数)。

然后每个有效的组合都可以唯一地表示为一个整数。 可以预先计算出构成有效组合的精确整数并将其放入 Set<Long> 中。当然。

检查一手牌是否只包含有效的组合然后简化为检查给定的长牌是否可以写成一组给定数字的乘积。 (可以使用递归和动态规划)

具体例子(一):

  • 红桃 A => 2
  • 红心二 => 3
  • 红心三 => 5

Set<Long> validMelds = {30, .., ..}

如果手牌(值 = 60)那么我们知道它包含 2 个有效的组合。

具体例子(二)

  • 1 个俱乐部 = 2 个
  • 2 个俱乐部 = 3 个
  • 3 个梅花 = 5 个
  • 4 个梅花 = 7 个
  • 红心 4 = 179
  • 4 颗钻石 = 181

已知有效组合 = {30, 210, 226793, ..}

手牌值(value) = 6803790

简单(递归)算法:

  1. 6803790 可以被 30 整除
  2. (6803790/30 = ) 226793 可以被 226793 整除
  3. 递归算法得出结论这是一个有效的分支

    备选

  4. 6803790能被210整除

  5. (6803790/210) = 32399 不能被任何有效的 meld-number 整除
  6. 递归算法结束分支在这里停止

    如果您需要能够处理部分手牌并不总是有效组合的一部分的情况,您可能希望查看 linear algebra .

关于java - 确定 Indian Rummy 手牌是否获胜 - Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51225335/

相关文章:

java - 如何在Java中动态填充类的字段

java - 在Java中递归构建字符串

java - 如何从 "Credential storage"加载证书?

java - 使用泛型类型中的 super 将 Map 流式传输到 Consumer 后使用 orElse 编译错误

java - 在 KafkaBolt 中暴露 Kafka 发布异常

java - 使用 Scanner 类获取构造函数变量的用户输入

java - 我怎样才能归还我的卡片阵列?

java - 如何在JSP页面中访问 Controller 的getter方法 - spring mvc

java - 如何在一组数组中找到元素最多的数组

javafx 创建 ComboBox TableCell