我正在寻找一种有效的解决方案,以确定一只手在印度拉米纸牌中是否是获胜的手。在混合方面,印度拉米纸牌类似于 Gin 拉米纸牌。一个人可以将同一套西装的一个序列(平直)融合在一起,也可以将一组相同的值融合在一起。序列和集合都应至少包含3张卡片。与 Gin 拉米不同,在印度拉米中,一手牌有13张牌。获胜手应该包含至少两个序列,并且这些序列中的至少一个必须是纯序列。纯粹来说,我的意思是不应在一个 clown (通配符)的帮助下完成此顺序。手的其余部分可以包括有或没有 clown 的序列和布景。注意:除了套牌中的两个 clown (52 + 2)外,还有一个来自套牌的随机纸牌用作 clown 。例如,如果随机选择了5张黑桃作为 clown ,那么甲板中剩余的3副5套其他西装可以用作2个常规 clown 的 clown 。

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

  • A,K,Q,J(锹)| 2,3,4(心脏)| 2,2,2(锹,棍棒,钻石)| 3,4,5(钻石)
  • A,K,Q,J,10(锹)| 4,5,6,7,8(俱乐部)| 9,9,9(钻石,俱乐部,锹)
  • A,K,Q,J,10,9,8,7,6,5(锹)| 4,3,2(锹)

  • 这里有一些使用百搭手来赢得胜利的例子。假设从甲板上随机挑选了6个(笑话) clown ;因此剩余的6s都可以用作笑话。
  • A,K,Q,J(黑桃;纯序列)| 7,7,7(钻石,棍棒,黑桃)| 3,3,6(钻石,棍棒,棍棒;带有 clown )| A,2,6 (俱乐部,俱乐部,心)
  • A,2,3(心)| 4,5,6(心)| 7,7,7,7(黑桃,棍棒,钻石,心)| 8,6,10,Joker(黑桃,钻石,黑桃;与 clown ,6个和一个常规 clown 的序列)

  • 以下是而不是odt_rstrong获胜手的一些示例:
  • A,2, clown (心脏)| 4,5, clown (心脏)| 7,7,7,7(所有西装)| 9,9,9(俱乐部,钻石,心脏)(这不是有效的手因为它不包含纯序列)
  • A,2,3,4(hearts)| 7,7,7(club,diamonds,hearts)| 8,8,8(clubs,Diamonds,hearts)| 9,9,9(clubs,Diamonds,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个黑桃,否则将其用在4s的集合中。

  • 请提供有关有效确定获胜手的建议。

    附言:在确定获胜手时,玩家手中将有14张牌。融合13张卡片后,第14张卡片将被作为整理卡丢弃。

    最佳答案

    我已经实现了Rummikub的Java版本(具有类似约束的游戏)。

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

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

    然后,检查一手是否仅包含有效的熔体就简化为检查给定的长数是否可以写为一组给定数字的乘积。 (可以使用递归和动态编程)

    具体示例(1):

  • 红桃王牌=> 2
  • 两颗心=> 3
  • 三颗心=> 5
  • Set<Long> validMelds = {30, .., ..}
    如果手形(值= 60),那么我们知道它包含2个有效熔合。

    具体示例(2)
  • 1个俱乐部= 2
  • 2个俱乐部= 3
  • 3个俱乐部= 5
  • 4个俱乐部= 7
  • 4个心= 179
  • 4颗钻石= 181

  • 已知有效焊缝= {30,210,226793,..}

    手的值(value)= 6803790

    简单(递归)算法:
  • 6803790可被30
  • 整除
  • (6803790/30 =)226793被226793整除
  • 递归算法得出结论,这是一个有效分支

    替代
  • 6803790可被210
  • 整除
  • (6803790/210)= 32399无法被任何有效的合并编号
  • 整除
  • 递归算法得出分支在此处结束的结论

    如果您需要处理手牌的某些部分并不总是有效组合的一部分的情况,则不妨查看linear algebra
  • 09-05 11:58