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

时间:2018-07-07 17:14:06

标签: java

我正在寻找一种有效的解决方案,以确定一手牌是否是印度拉米纸牌中的胜出手。在混合方面,印度拉米酒与杜松子酒拉米酒相似。可以将相同西装的序列(平直)融合或将一组相同值融合。序列和集合都应至少包含3张卡片。与杜松子酒拉米不同,在印度拉米中,一手牌有13张牌。中奖牌必须包含至少两个序列,并且这些序列中的至少一个必须是纯序列。纯粹来说,我的意思是不应在一个小丑(通配符)的帮助下完成此顺序。手的其余部分可以包括有或没有小丑的序列和布景。注意:除了套牌中的两个小丑(52 + 2)外,还有一个来自套牌的随机纸牌用作小丑。例如,如果随机选择了5张黑桃作为小丑,那么甲板中其余3套其他5套西服可以用作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个小丑作为黑桃。因此剩余的6s都可以用作笑话。

  • A,K,Q,J(黑桃;纯序列)| 7,7,7(钻石,棍棒,黑桃)| 3,3,6(钻石,棍棒,棍棒;设置为小丑)| A,2 ,6(clubs,clubs,hearts)
  • A,2,3(心)| 4,5,6(心)| 7,7,7,7(黑桃,棍棒,钻石,心)| 8、6、10,小丑(黑桃,钻石,黑桃;与小丑,6个和一个普通小丑的序列)

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

  • A,2,Joker(心)| 4,5,Joker(心)| 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();
}

}

我还编写了一些函数来获取卡中可能的序列和设置。 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的集合中。

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

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

1 个答案:

答案 0 :(得分:4)

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

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

然后,每个有效的融合都可以唯一地表示为整数。 可以预先计算出有效熔合的精确整数,并将其放在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,..}

手的价值= 6803790

简单(递归)算法:

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

    替代

  4. 6803790被210整除

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

    如果您需要处理手牌的某些部分并不总是有效组合的一部分的情况,则不妨研究linear algebra