Классификация покерных рук на Java - PullRequest
0 голосов
/ 28 октября 2019

В настоящее время я работаю над проектом CS, который классифицирует руки игрока. Я решил в первой половине проекта распечатать колоду, перетасованную колоду и руки player1, player2 и оставшейся колоды. Проблема возникает, когда я должен оценить руки. Мой код должен каким-то образом оценить, к какой категории принадлежат руки, и распечатать, победит ли player1 или player2. Пока у меня есть три класса:

public class Card {

    static String[] card_suit = {"hearts", "diamonds", "clubs", "spades"};

    static int[] card_rank = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};// 11 is Jack, 12 is Queen, 13 is King and 14 is Ace 

    public int[] getRank() {
        return card_rank;
    }
    public String[] getSuit() {
        return card_suit;
    }
}
public class Driver {

    public static void main(String[] args) {
        Card card = new Card();
        Deck deck = new Deck();

        deck.getDeck();
        System.out.print("ORIGINAL DECK: ");
        deck.printDeck();
        deck.shuffleDeck();
        System.out.print("SHUFFLED DECK: ");
        deck.printDeck();

        System.out.println();


        System.out.print("PLAYER ONE: ");
        System.out.println(java.util.Arrays.toString(deck.playerOneHands()));
        System.out.print("PLAYER TWO: ");
        System.out.println(java.util.Arrays.toString(deck.playerTwoHands()));
        System.out.print("REMAINING DECK: ");
        System.out.println(java.util.Arrays.toString(deck.remainingDeckCards()));               
        }

}
import java.util.Arrays;
import java.util.Collections;

public class Deck extends Card {

    Card card = new Card();

    private String[] deck_card = new String[52];

    public String[] getDeck() {
        int i = 0;
        for(int s = 0; s < 4; s++) {
            for(int r = 0; r < 13; r++) {
                deck_card[i]=(card_suit[s] + " of " + card_rank[r]);
                i++;
                }

            }
        return deck_card;
    }

    public void printDeck() {
        System.out.println (java.util.Arrays.toString (deck_card));
    }

    public void shuffleDeck() {
        Collections.shuffle(Arrays.asList(deck_card));
    }

    public String[] playerOneHands() {
        String [] firsthand = new String[5];
        for(int a = 0; a < 5; a++) {
            firsthand[a] = deck_card[a];
        }
        return firsthand;
    }

    public String[] playerTwoHands() {
        String[] secondhand = new String[5];
        for(int a = 0; a < 5; a++) {
            secondhand[a] = deck_card[a+5];
        }
        return secondhand;
    }

    public String[] remainingDeckCards() {
        String[] remainDeck = new String[42];
        for(int a = 0; a < 42; a++){
            remainDeck[a] = deck_card[a+10];
        }
        return remainDeck;
    }

}

Я думал, что это будет работать, потому что класс Deck выходит из класса Card, я могу использовать метод getRank для сравнения каждой руки,но я не уверен, как построить условные выражения.

Любая помощь с благодарностью. Благодарю.

Ответы [ 3 ]

1 голос
/ 28 октября 2019

Не желая делать домашнее задание за вас ...

Это проблема:

class Deck extends Card

Колода не является подтипом карты. Колода имеет карт, поэтому:

class Deck {
    List<Card> cards;
}

- лучший выбор.

Кроме того, следующий код ничего не делает с колодой:

public void shuffleDeck() {
    Collections.shuffle(Arrays.asList(deck_card));
}

Это перетасовывает копию колоды, оставляя колоду нетронутой.

Кроме того, вы не должны создавать последовательности в цикле. Вместо этого реализуйте (переопределите) метод toString () на Карте и на колоде.

Также создайте костюм enum.

Кроме того, полностью удалите card_rank - это не имеет смысла. Вместо этого добавьте поле int rank; к Карте, или лучше сделайте ранг enum.

Сначала исправьте эти вещи, а затем повторно атакуйте проблему, написав метод, который передается Hand (новый класс), у которого есть List и метод, который возвращает HandType (другое перечисление), оценивая, является ли рука стрит-флешем, еще четырьмя в своем роде, еще ... вплоть до старшей карты - от старшей к младшей.

1 голос
/ 28 октября 2019
  1. Для моделирования игры сначала определите сущности, такие как Карта , Колода и т. Д. (Что в основном вы и сделали). Я хотел бы добавить еще несколько, например Player , Evaluator (поясняется ниже) и т. Д.
  2. Ранг и костюм НЕ являются строкой / int, но они предопределены (не будут менятьсяв жизни время игры) возможные вариации в Картах. Всегда используйте словарь домена для лучшей модели. Каждая карта принадлежит одному масти и одному рангу. (Думайте о том, чтобы делать Rank и Suit как перечисления, это позволит избежать неизвестных значений, нарушающих код во время выполнения.
  3. Важно не указывать метод set для suite и rank в Card (они образуют идентичность Card в комбинации)
  4. Полная колода (при инициализации) формируется из перекрестного произведения масти и ранга. Это означает, что колода имеет (содержит) несколько карт. Помните, что карта может быть жива и за пределами колоды (в руке игрока), следовательно, еене составление. Наследование колоды с карты абсолютно неправильно. Это переводит к утверждению Колода является разновидностью карты , что неверно. Колода будет иметь коллекцию карт. Использование наследования приведет к нарушению подстановки Лискова. Принцип (Один из ТВЕРДЫХ).
  5. Чтобы смоделировать колоду, учтите тот факт, что колода не содержит дубликатов карт, колода не меняет свой порядок после формирования (если не перетасована). Это сложный выбор между Set и List. Я бы пошел на список с добавленным программным ограничением для избежания дублированияs (необходимо сделать только при инициализации).
  6. Но вместо того, чтобы моделировать Deck как коллекцию java, лучше всего позволить классу Deck содержать коллекцию java подходящего выбора, а класс Deck работать как обертку, определяя необходимый API (с точки зрения домена), такой как shuffle, getTopCard ()и т.д. Это называется шаблоном проектирования адаптера объекта. Это делает нашу платформу проектирования (реализацию) независимой.
  7. Вам нужно смоделировать еще несколько классов, таких как Player Hold CardInHand и т. Д.
  8. Об оценке картс другой стороны, лучше смоделировать его как отдельный класс, поскольку его различные задачи и правила могут меняться независимо от других классов.
  9. Игра в покер - лучшее задание для изучения объектно-ориентированного программирования.
0 голосов
/ 28 октября 2019

Кажется, что у вас Card только статические поля;Я бы изменил его так, чтобы экземпляр Card представлял одну карту из Deck. Я также сделал бы наборы типа enum. Вы также можете добавить целочисленные константы для фигур и тузов. Класс может реализовать Comparable<Card>:

public class Card implements Comparable<Card> {
    public enum Suite {CLUBS, DIAMONDS, HEARTS, SPADES};

    public static final int JACK = 11;
    public static final int QUEEN = 12;
    public static final int KING = 13;
    public static final int ACE = 14;

    public final Suite suite;
    public final int rank;

    public Card(Suite suite, int rank) {
        if (suite == null) {
            throw new IllegalArgumentException("Suite cannot be null");
        }
        if (rank < 2 || rank > 14) {
            throw new IllegalArgumentException(
                    "Value must be between 2 and 14");
        }
        this.suite = suite;
        this.rank = rank;
    }

    public Suite getSuite() {
        return suite;
    }

    public int getRank() {
        return rank;
    }

    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        if (rank >= 2 && rank <= 10) {
            buf.append(rank);
        } else {
            switch (rank) {
                case JACK:
                    buf.append("jack");
                    break;
                case QUEEN:
                    buf.append("queen");
                    break;
                case KING:
                    buf.append("king");
                    break;
                case ACE:
                    buf.append("ace");
                    break;
            }
        }
        buf.append(" of ");
        buf.append(suite.toString().toLowerCase());
        return buf.toString();
    }

    @Override
    public int compareTo(Card other) {
        if (rank > other.rank) {
            return 1;
        } else if (rank < other.rank) {
            return -1;
        } else {
            return suite.compareTo(other.suite);
        }
    }
}

Обратите внимание, что у вас также может быть два подкласса Card: один для чисел и один для цифр.

Deck - это набор из 52 карт. Инициализируется добавлением каждой карты в список. Можно shuffle колоду или take карту из колоды:

public class Deck {
    private final List<Card> cards = new ArrayList<>();

    public Deck() {
        for (Card.Suite suite: Card.Suite.values()) {
            for (int i = 2; i <= 14; ++i) {
                cards.add(new Card(suite,i));
            }
        }
    }

    public void shuffle() {
        Collections.shuffle(cards);
    }

    public boolean isEmpty() {
        return cards.isEmpty();
    }

    public Card take() {
        if (cards.isEmpty()) {
            throw new IllegalStateException("Deck is empty");
        }
        return cards.remove(0);
    }
}

Вы можете взять shuffle и взять 5 карт из колоды, например:

    Deck deck = new Deck();
    deck.shuffle();
    for (int i = 0; i < 5; ++i) {
        Card card = deck.take();
        System.out.println(card);
    }

Теперь Hand - это набор из пяти карт, взятых из Deck. Мы можем объявить Hand как реализацию Comparable<Hand>, чтобы мы могли знать, какая из двух рук имеет наибольшее значение:

public class Hand implements Comparable<Hand> {
    private final Card[] cards = new Card[5];

    public Hand(Deck deck) {
        for (int i = 0; i < 5; ++i) {
            cards[i] = deck.take();
        }
        Arrays.sort(cards);
    }

    @Override
    public int compareTo(Hand other) {
        ...
    }
}

Теперь самое интересное: вы должны определить тип руки как одну изследующее (тип enum):

public enum HandType {
    SINGLE, PAIR, TWO_PAIRS, THREE, STRAIGHT, FLUSH, FULL_HOUSE, FOUR,
    STRAIGHT_FLUSH, ROYAL_FLUSH;
}

Обратите внимание, что константы расположены от самой низкой к самой высокой. Кроме того, карты должны быть расположены так, чтобы в случае ничьей вы могли сравнивать карты, чтобы определить победителя.

Я бы посоветовал вам сделать группы карт одного ранга;в случае, когда у вас есть пять разных групп, это может быть флеш или стрит.

Другой подход заключается в объявлении подкласса Hand для каждого HandType, но я не думаю, чтосделав это, вы бы многое получили.

public class Hand implements Comparable<Hand> {
    public enum HandType {
        SINGLE, PAIR, TWO_PAIRS, THREE, STRAIGHT, FLUSH, FULL_HOUSE, FOUR,
        STRAIGHT_FLUSH, ROYAL_FLUSH;
    }

    private final Card[] cards = new Card[5];
    private final int[] groupSize;
    private final HandType type;

    public Hand(Deck deck) {
        for (int i = 0; i < 5; ++i) {
            cards[i] = deck.take();
        }
        groupSize = group(cards);
        type = identifyType(groupSize, cards);
    }

    @Override
    public int compareTo(Hand other) {
        int r = type.compareTo(other.type);
        if (r != 0) {
            return r;
        }
        for (int i = cards.length; --i >= 0; ) {
            int r1 = cards[i].getRank();
            int r2 = other.cards[i].getRank();
            if (r1 < r2) {
                return -1;
            } else if (r1 > r2) {
                return 1;
            }
        }
        return 0;
    }

    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        buf.append(type);
        buf.append(": ");
        buf.append(cards[0]);
        for (int i = 1; i < 5; ++i) {
            buf.append(", ");
            buf.append(cards[i]);
        }
        return buf.toString();
    }

    private static int[] group(Card[] cards) {
        Arrays.sort(cards);
        List<List<Card>> groups = new ArrayList<>();
        int val = -1; // invalid rank
        List<Card> currentGroup = null;
        for (Card card: cards) {
            if (val == card.getRank()) {
                currentGroup.add(card);
            } else {
                if (currentGroup != null) {
                    groups.add(currentGroup);
                }
                currentGroup = new ArrayList<>();
                currentGroup.add(card);
                val = card.getRank();
            }
        }
        if (currentGroup != null) {
            groups.add(currentGroup);
        }
        // identify groups of cards of same value
        // sort groups by size and highest card
        Collections.sort(groups, (List<Card> group1, List<Card> group2) -> {
            int s1 = group1.size();
            int s2 = group2.size();
            if (s1 < s2) {
                return -1;
            } else if (s1 > s2) {
                return 1;
            } else {
                return group1.get(s1-1).compareTo(group2.get(s2-1));
            }
        });
        int[] groupSize = new int[groups.size()];
        int g = 0;
        int i = 0;
        for (List<Card> group: groups) {
            groupSize[g++] = group.size();
            for (Card card: group) {
                cards[i++] = card;
            }
        }
        assert sum(groupSize) == 5;
        return groupSize;
    }

    private static HandType identifyType(int[] groupSize, Card[] cards) {
        switch (groupSize.length) {
            case 2:
                // can be a full house or four cards
                if (groupSize[0] == 1) {
                    return HandType.FOUR;
                } else if (groupSize[0] == 2) {
                    return HandType.FULL_HOUSE;
                } else {
                    assert false;
                    return null;
                }
            case 3:
                if (groupSize[0] == 1) {
                    // three cards or double pair
                    if (groupSize[1] == 1) {
                        return HandType.THREE;
                    } else {
                        assert groupSize[1] == 2 && groupSize[2] == 2;
                        return HandType.TWO_PAIRS;
                    }
                } else {
                    assert false;
                    return null;
                }
            case 4:
                // one pair
                return HandType.PAIR;
            case 5:
                // all different values: check for flush
                Card prev = cards[0];
                boolean sameSuite = true;
                boolean straight = true;
                for (int i = 1; i < 5; ++i) {
                    Card card = cards[i];
                    straight &= card.getRank() == prev.getRank()+1;
                    sameSuite &= card.getSuite() == prev.getSuite();
                }
                if (sameSuite) {
                    if (straight) {
                        if (cards[4].getRank() == Card.ACE) {
                            return HandType.ROYAL_FLUSH;
                        }
                        return HandType.STRAIGHT_FLUSH;
                    } else {
                        return HandType.FLUSH;
                    }
                } else {
                    if (straight) {
                        return HandType.STRAIGHT;
                    } else {
                        return HandType.SINGLE;
                    }
                }

            default:
                assert false;
                return null;
        }
    }

    private static int sum(int[] groupSize) {
        int sum = 0;
        for (int s: groupSize) {
            sum += s;
        }
        return sum;
    }
}
...