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

Java 确定印度拉米手牌是否是获胜手牌-爪哇,java,Java,我正在寻找一个有效的解决方案,以确定一手牌是否是印度拉米酒的赢家。印度拉米酒和杜松子拉米酒在融合方面很相似。一个人可以将同一套衣服的序列(直线)融合在一起,也可以将一组相同的值融合在一起。序列和集合应至少包含3张卡。与杜松子酒不同,在印度拉米酒中,一手牌由13张牌组成。获胜的手牌应至少包含两个序列,且其中至少一个序列必须是纯序列。我所说的纯,是指序列不应该在小丑(外卡)的帮助下进行。手的其余部分可以由有或没有小丑的序列和场景组成。注:除了一副牌(52+2)中的两张小丑牌外,还有一张随机牌用作小丑

我正在寻找一个有效的解决方案,以确定一手牌是否是印度拉米酒的赢家。印度拉米酒和杜松子拉米酒在融合方面很相似。一个人可以将同一套衣服的序列(直线)融合在一起,也可以将一组相同的值融合在一起。序列和集合应至少包含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(黑桃)是从牌堆中随机挑选的小丑;所以剩下的6都可以当小丑用

  • A、 K,Q,J(黑桃;纯序列)| 7,7,7(钻石,棍棒,黑桃)| 3,3,6(钻石,棍棒,棍棒;与小丑一起设定)| A,2,6(棍棒,棍棒,红桃)
  • A、 2,3(红桃)| 4,5,6(红桃)| 7,7,7(黑桃,梅花,钻石,红桃)| 8,6,10,小丑(黑桃,钻石,黑桃;与小丑的顺序,6和普通小丑)
以下是一些不是赢家的例子:

  • A、 2,小丑(红桃)| 4,5,小丑(红桃)| 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函数中的参数(列表)已按suit排序,然后按值排序。对于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;
}
private List-getSequences(List-hand,int-min){
列表序列=新的ArrayList();
列表序列=新的ArrayList();
对于(int i=1;i=min){
顺序。添加(顺序);
}
序列=新的ArrayList();
}
}
返回序列;
}
私有列表getset(列表手,int-min){
列表集=新的ArrayList();
列表集=新的ArrayList();
对于(int i=1;i=min){
集合。添加(集合);
}
set=newarraylist();
}
}
}
返回集;
}
我不认为这是寻找序列和集合的最优雅的方式。因此,我欢迎任何关于如何改进的建议。但我真正需要帮助的是我下一步该做什么?集合和序列之间可能存在重叠。例如,在以下卡的情况下:

  • A、 2,3(黑桃)| 4,4,4(黑桃、梅花、红桃) 我的getSequences函数将返回一个,2,3,4(黑桃)作为序列。我应该避免在我的序列中包含4个黑桃,以便在4个黑桃中使用
请就如何有效地确定获胜一手提出建议


附言:在决定胜出一手牌时,玩家手中将有14张牌。融合13张牌后,第14张牌将作为结束牌丢弃。

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

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

然后,每个有效的meld可以唯一地表示为一个整数。 当然,可以事先计算出构成有效融合的精确整数,并将其放入
集合中

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

具体示例(1):

  • 红桃王牌=>2
  • 两颗心=>3
  • 三颗红心=>5颗
Set validmels={30,…,…}

如果手(值=60),那么我们知道它包含两个有效的混合

具体示例(2)

  • 1个俱乐部=2个
  • 2个俱乐部=3个
  • 3个俱乐部=5个
  • 4个俱乐部=7个
  • 4颗红心=179颗
  • 4颗钻石=181
已知有效的MELD={30,210,226793,…}

手的价值=6803790

简单(递归)算法:

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

    备选方案

  • 6803790可被210整除

  • (6803790/210)=32399不能被任何有效的meld数整除
  • 递归算法在这里结束分支

    如果您需要能够处理手牌的某些部分并不总是有效meld的一部分的情况,您可能希望研究一下


  • 在这个游戏中,手牌总是在14张牌上评估,还是玩家可以有不同数量的牌?总是在14张牌上评估!在你的例子中,你说
    A,K,Q,J(黑桃)| 2,3,4(红桃)| 2,2,2(黑桃,梅花,钻石)| A,2,3(钻石)
    是赢的一手牌。我看到2吨