确定印度拉米手是否是获胜手 - Java

Ser*_*ase 5 java

我正在寻找一种有效的解决方案,以确定一只手是否是印度拉米的获胜手牌.在融合方面,印度拉米饼类似于杜松子酒.人们可以融合同一套装的序列(笔直)或融合一组相同的价值.序列和集合应该至少包含3张牌.与杜松子酒拉米饼不同,在印度拉米纸牌中,一手牌由13张牌组成.获胜的手应该包含至少两个序列,并且这些序列中的至少一个必须是纯序列.纯粹,我的意思是不应该在小丑(外卡)的帮助下制作序列.手的其余部分可以由有或没有笑话的序列和集合组成.注意:除了甲板上的2个笑话者(52 + 2)外,还有一张来自甲板的随机牌用作小丑.例如,如果将5个黑桃随机挑选为小丑,那么甲板上剩余的3个其他套装可用作2个常规笑话者之上的小丑.

以下是一些没有使用小丑的有效获胜手的例子:

  • 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(黑桃)是从甲板上随机挑选的小丑; 所以剩下的6个人都可以用作小丑.

  • A,K,Q,J(黑桃;纯序列)| 7,7,7(钻石,俱乐部,黑桃)| 3,3,6(钻石,俱乐部,俱乐部;与小丑一起设置)| A,2,6(会所,俱乐部,心)
  • A,2,3(心)| 4,5,6(心)| 7,7,7,7(黑桃,俱乐部,钻石,心形)| 8,6,10,小丑(黑桃,钻石,黑桃;序列与小丑,6和一个普通的小丑)

以下是一些不是赢手的例子:

  • A,2,小丑(心)| 4,5,小丑(心)| 7,7,7,7(所有套装)| 9,9,9(俱乐部,钻石,心形)(这不是有效的手,因为它不包含纯序列)
  • A,2,3,4(心)| 7,7,7(球杆,钻石,心形)| 8,8,8(球杆,钻石,心形)| 9,9,9(球杆,钻石,心形)(这是无效的,因为它不包含第二个序列)

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

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();
}
Run Code Online (Sandbox Code Playgroud)

}

我还写了一些函数来获取我的卡中可能的序列和集合.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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • A,2,3(黑桃)| 4,4,4(黑桃,俱乐部,心)我的getSequences函数将返回A,2,3,4(黑桃)作为序列.我应该避免在我的序列中包含4个黑桃,而不是在4组中使用它.

请告知有效确定获胜手牌.

PS:在确定获胜手牌时,玩家手中将有14张牌.在融合13张牌后,第十四张牌将被丢弃作为整理牌.

Jor*_*ens 6

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

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

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

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

具体例子(1):

  • 红桃 A => 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, ..}

手牌价值 = 6803790

简单(递归)算法:

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

    选择

  4. 6803790 能被 210 整除

  5. (6803790 / 210) = 32399 不能被任何有效的融合数整除
  6. 递归算法结束分支到此停止

    如果您需要能够处理手牌的某些部分并不总是有效组合的一部分的情况,您可能希望研究线性代数。