Ester
Ester

Reputation: 133

Collections.sort, Enum, Comparable Interface problems

I have got a class Card from which other cards(Card Game) inherit from. The Cards suits and number are stored in enums like this

public static enum Suit {
    CLUBS, DIAMONDS, HEARTS, SPADES
};

public static enum Rank {
    DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE
};

My first problem is how to change the order of the cards ranks. In each separate class(Card Game) that inherits from class Card as different card games place different levels of importance on different cards.

My second problem is using the Comparable Interface.

So I have a class card like this:

public  class Card implements Comparable<Card> {

public Suit suit;
public Rank rank;


public Card(Rank ranker, Suit suiter) {

    rank = ranker;
    suit = suiter;
}


//Other Methods for rank and suit here. 


@Override
public int compareTo(Card o) {

    int rankCom = rank.compareTo(o.rank);
    return rankCom != 0 ? rankCom : suit.compareTo(o.suit);
}

}

I have just been recently introduced to the comparable interface and I am not entirely sure my implementation is right. The problem arises when I want to sort out my cards using collections.sort(cards_saver). cards_saver is where I store my cards. All of that works fine. collections.shuffle(cards_saver) also works fine. The problem I get when I do collections.sort is this:

Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (List<Card>). The inferred type Card is not a valid substitute for the bounded parameter <T extends Comparable<? super T>>

I would have put up all the extra code I have...Only this is getting way too long. If I didn't explain the problems well enough, please comment-I will try to explain.

Thanks in Advance

Upvotes: 2

Views: 1993

Answers (3)

user unknown
user unknown

Reputation: 36269

Your code works fine for me. I just added a toString-method to Card:

import java.util.*;

class Card implements Comparable<Card> {

    static enum Suit {
        CLUBS, DIAMONDS, HEARTS, SPADES
    }

    static enum Rank {
        DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE
    }

    public Suit suit;
    public Rank rank;

    public Card (Rank ranker, Suit suiter) {
        rank = ranker;
        suit = suiter;
    }

    @Override
    public int compareTo (Card o) {
        int rankCom = rank.compareTo(o.rank);
        return rankCom != 0 ? rankCom : suit.compareTo(o.suit);
    }

    public String toString () {
        return suit.toString () + "\t" + rank.toString (); 
    }
}

and - only to my convenience, added Rank and Suit as inner enum to Card, but just to have all in one file - it shouldn't affect the sorting. Here is the test:

public class CardTest
{
    public static void main (String args[])
    {
        List <Card> lc = new ArrayList <Card> ();
        lc.add (new Card (Card.Rank.SIX, Card.Suit.CLUBS)); 
        lc.add (new Card (Card.Rank.TEN, Card.Suit.CLUBS)); 
        lc.add (new Card (Card.Rank.SIX, Card.Suit.HEARTS)); 
        lc.add (new Card (Card.Rank.ACE, Card.Suit.HEARTS)); 

        System.out.println (lc);
        Collections.sort (lc);
        System.out.println (lc);
    }
}

Output:

[CLUBS  SIX, CLUBS  TEN, HEARTS SIX, HEARTS ACE]
[CLUBS  SIX, HEARTS SIX, CLUBS  TEN, HEARTS ACE]

Your code would be:

        lc.add (new Card (Rank.TEN, Suit.CLUBS)); 

instead.

If you have a different ordering of Cards, it might be the simplest thing to create a new Card class. Factoring out similarities between between Poker, Bridge, Rommee, Blackjack and so on could be overengineering.

Upvotes: 0

user949300
user949300

Reputation: 15729

I think for the syntax error you have to declare Card as (yes, I agree this is strange looking syntax)

public  class Card implements Comparable<? extends Card>

And then you can override in subclasses. However, I find that this often gets confusing. Plus, from a design point of view, the Cards are all the same in Bridge, Hearts, Poker. Arguably, there isn't a BridgeCard and a PokerCard subclass. There is a Card, but there is a different Game and the Game determines how you compare cards.

For added clarity, and, if you believe my design argument, for better design, don't use Comparable, but implement a bunch of Comparators instead. e.g. something like:

static Comparator<Card> LOWBALL_POKER_COMPARATOR = new Comparator<Card>() {

      @Override
      public int compare(Card o1, Card o2) {
         // Ace is LOW is lowball poker, other cards as usual
      }

};

static Comparator<Card> PINOCLE_COMPARATOR = new Comparator<Card>() {
      @Override
      public int compare(Card o1, Card o2) {
         // I haven't played pinocle in so long I forget the rules...
      }
};

Note that Enums can implement Comparator, so you can have all these Comparators in Enums. The particular instance/subclass of CardGame you are playing selects the proper Enum/Comparator for that Game at startup and away you go...

Upvotes: 2

trutheality
trutheality

Reputation: 23465

My first problem is how to change the order of the cards ranks. In each separate class(Card Game) that inherits from class Card as different card games place different levels of importance on different cards.

You have two approaches:

  1. Since you're inheriting from Card, you can just override compareTo to behave accordingly.
  2. You can take a look at the Comparator interface, which is convenient for redefining the comparison rules for objects based on context.

As for that error you're getting, it doesn't really make sense. The problem might be elsewhere.

Upvotes: 4

Related Questions