Question

Question (short version): How do I compare elements in an ArrayList to each other?

I've got most of the basics of ArrayList down pretty well (add, get, set, size...). I'm having trouble stepping into the ArrayList to compare objects (playing cards' values and suits) in order to determine best poker hands. I have a class to store information about a card.

Card class:

    /** class Card : for creating playing card objects
     *  it is an immutable class.
     *  Rank - valid values are 1 to 13
     *  Suit - valid values are 0 to 3
     *  Do not modify this class!
     */
    class Card {

        /* constant suits and ranks */
        static final String[] Suit = {"Clubs", "Diamonds", "Hearts", "Spades" };
        static final String[] Rank = {"","A","2","3","4","5","6","7","8","9","10","J","Q","K"};

        /* Data field of a card: rank and suit */
        private int cardRank;  /* values: 1-13 (see Rank[] above) */
        private int cardSuit;  /* values: 0-3  (see Suit[] above) */

        /* Constructor to create a card */
        /* throw PlayingCardException if rank or suit is invalid */
        public Card(int rank, int suit) throws PlayingCardException { 
        if ((rank < 1) || (rank > 13))
            throw new PlayingCardException("Invalid rank:"+rank);
        else
                cardRank = rank;
        if ((suit < 0) || (suit > 3))
            throw new PlayingCardException("Invalid suit:"+suit);
        else
                cardSuit = suit;
        }

        /* Accessor and toString */
        /* You may impelemnt equals(), but it will not be used */
        public int getRank() { return cardRank; }
        public int getSuit() { return cardSuit; }
        public String toString() { return Rank[cardRank] + " " + Suit[cardSuit]; }


        /* Few quick tests here */
        public static void main(String args[])
        {
        try {
            Card c1 = new Card(1,3);    // A Spades
            System.out.println(c1);
            c1 = new Card(10,0);    // 10 Clubs
            System.out.println(c1);
            //c1 = new Card(10,5);        // generate exception here
        }
        catch (PlayingCardException e)
        {
            System.out.println("PlayingCardException: "+e.getMessage());
        }
        }
    } 

And a class to check each hand of cards (this is the class I'm having trouble figuring out). I have currently added code to make this add an ArrayList and print each hand over again (just to make sure I can create a separate ArrayList because I wasn't too comfortable with my ability), but I can't figure out how to compare elements of each card (rank and suit).

Check hands class:

/** Check current currentHand using multipliers and goodHandTypes arrays
*  Must print yourHandType (default is "Sorry, you lost") at the end o function.
*  This can be checked by testCheckHands() and main() method.
*/
    private void checkHands()
    {
        // implement this method!
        ArrayList<Card> multiplierCheck = new ArrayList<Card>();
        String yourhandtype = "Sorry, you lost";

        for (int toList = 0; toList<5; toList++) {
                multiplierCheck.add(currentHand.get(toList));
            }
        System.out.println(multiplierCheck);

        System.out.println(yourhandtype);
    }

And a method to test check hands that creates hands which are winning hands (straight, flush, three of a kind). I can't figure out how to compare the cards to each other in my Check Hands Class.

testCheckHands() Method

public void testCheckHands()
    {
        try {
            currentHand = new ArrayList<Card>();

        // set Royal Flush
        currentHand.add(new Card(1,3));
        currentHand.add(new Card(10,3));
        currentHand.add(new Card(12,3));
        currentHand.add(new Card(11,3));
        currentHand.add(new Card(13,3));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // set Straight Flush
        currentHand.set(0,new Card(9,3));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // set Straight
        currentHand.set(4, new Card(8,1));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // set Flush 
        currentHand.set(4, new Card(5,3));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // "Royal Pair" , "Two Pairs" , "Three of a Kind", "Straight", "Flush   ", 
        // "Full House", "Four of a Kind", "Straight Flush", "Royal Flush" };

        // set Four of a Kind
        currentHand.clear();
        currentHand.add(new Card(8,3));
        currentHand.add(new Card(8,0));
        currentHand.add(new Card(12,3));
        currentHand.add(new Card(8,1));
        currentHand.add(new Card(8,2));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // set Three of a Kind
        currentHand.set(4, new Card(11,3));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // set Full House
        currentHand.set(2, new Card(11,1));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // set Two Pairs
        currentHand.set(1, new Card(9,1));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // set Royal Pair
        currentHand.set(0, new Card(3,1));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");

        // non Royal Pair
        currentHand.set(2, new Card(3,3));
        System.out.println(currentHand);
            checkHands();
        System.out.println("-----------------------------------");
        }
        catch (Exception e)
        {
        System.out.println(e.getMessage());
        }
    }
Was it helpful?

Solution

To evaluate Poker hands probably the most common thing you're going to do is loop through the data structure (could be an array, list, whatever) and compare the cards to each other. For example here's some pseudo-Java to compare a straight:

for (int i = 1; i < /* length of hand */; i++) {

    if (/* rank for card i is not 1 greater
           than rank for card i - 1 */) {

         /* not a straight */
    }
}

Note that the above assumes the structure is sorted which I'll get to. Also since Poker hands are so different there's not really a 'best way' to do all of them. You will have to write a routine for each one. So I would recommend you come up with some abstraction that helps you out. What I would do is use Enum. Here's a basic example:

enum PokerHand {
    STRAIGHT {
        @Override
        boolean matches(List<Card> hand) {

            for (int i = 1; i < hand.size(); i++) {
                if (
                    card.get(i).getRank() !=
                    card.get(i - 1).getRank() + 1
                ) {
                    return false;
                }
            }

            return true;
        }
    },
    FOUR_OF_A_KIND {
        @Override
        boolean matches(List<Card> hand) {

            int[] rankCount = new int[14];

            /* count up the ranks in the hand */
            for (Card card : hand) {
                rankCount[card.getRank()]++;
            }

            boolean foundHasOne = false;
            boolean foundHasFour = false;

            /* now evaluate exclusively
             * there must be only a 1 count and a 4 count
             */
            for (int i = 1; i < rankCount.length; i++) {

                if (rankCount[i] == 1) {
                    if (!foundHasOne) {
                        foundHasOne = true;
                    } else {
                        return false;
                    }

                } else if (rankCount[i] == 4) {
                    if (!foundHasFour) {
                        foundHasFour = true;
                    } else {
                        return false;
                    }

                } else if (rankCount[i] != 0) {
                    return false;
                }
            }

            return true;
        }
    },
    ROYAL_FLUSH {
        final int[] rfRanks = {
            1, 10, 11, 12, 13
        };

        @Override
        boolean matches(List<Card> hand) {

            for (int i = 0; i < rfRanks.length; i++) {
                if (rfRanks[i] != hand.get(i).getRank())
                    return false;
            }

            return true;
        }
    };

    abstract boolean matches(List<Card> hand);
}

Of course the above does not cover all Poker hands, just a few examples. Also I don't play Poker so those could be a little wrong but the point is to show some evaluation examples.

As I said before this becomes much simpler if you sort your lists ahead of time. java.util.Collections and java.util.Arrays have utility methods for this so it is fairly trivial. Just make sure to make a copy before sorting if you don't want the sort to persist after you check the hands.

/* make a shallow copy */
List<Card> sortedHand = new ArrayList<Card>(playerHand);

/* sort based on rank */
Collections.sort(sortedHand, new Comparator<Card>() {
    @Override
    public int compare(Card card1, Card card2) {
        int rank1 = card1.getRank();
        int rank2 = card2.getRank();

        if (rank1 > rank2) {
            return 1;

        if (rank1 < rank2)
            return -1;

        return 0;
    }
});

See Comparator#compare for a description of how that works but that's basically it to sort.

Using an enum or something like it then makes the evaluation fairly trivial logically.

Now what I recommend is to make a method for the evaluation because then you can conveniently return the constant for what the hand is.

static PokerHand evaluateHand(List<Card> hand) {
    for (PokerHand potential : PokerHand.values()) {
        if (potential.matches(hand))
            return potential;
    }

    /* imply there is not a matching hand */
    return null;
}

So after you make your copy of the hand and have sorted it you can call to evaluate it:

PokerHand evaluated = evaluateHand(sortedHand);

if (evaluated != null) {
    /* it's a recognized hand */
}

You don't have to make a method, you could do something like the following:

PokerHand evaluated = null;
for (PokerHand potential : PokerHand.values()) {
    if (potential.matches(sortedHand)) {
        evaluated = potential;
        break;
    }
}

if (evaluated != null) {
    /* it's a recognized hand */
}

But using helper methods helps organize your code.

I hope that helps. If you also need to score the hands to decide if there is a winner, just add another method to the enum that returns a score. Then see which one is the biggest.

OTHER TIPS

Not sure if you said how it isn't working, but to iterate through an arrayList..

for (String s : arrayList)
    if (s.equals(value))
         // ...

String can be replaced for int, ect..

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top