comparing two 'card' objects in Java

103 Views Asked by At

I'm stuck on this question where I need to compare two card objects based upon what rank and suit they are. Heart being the lowest suit, Spades the highest. And for Rank, One the lowest and Ace the highest. And 5 Spades being > 2 Hearts. These values are stored in two enums of their respective type. With Heart being the first ordinal and Spades the last ordinal.

@Override
    public int compareTo(Card o) {
        
        if(this.rank.ordinal() > o.rank.ordinal()) {
            return 1;
        }
        if (this.rank.ordinal() < o.rank.ordinal()) {
            return -1;
        } 
        else {
            return 0;
        }

In my comapreTo() I've implemented the comparing of the rank, but I'm stuck on THEN comparing the suit to find the greater card. This code fails once it goes past Ace of Hearts as it thinks 1 of clubs is higher. I've tried a bunch of different methods using if's but it just becomes convoluted and ugly and doesn't work anyways. Does anyone have any suggestions?

3

There are 3 best solutions below

0
Ahmed Ashour On

You can use Comparator.comparing:

I understand rank is having priority over the suit, so it can be done like:

import java.util.Comparator;

public class Cards {

  enum Suit {hearts, clubs, diamonds, spades}

  enum Rank {_2, _3, _4, _5, _6, _7, _8, _9, _10, joker, queen, king, ace,}

  record Card(Suit suit, Rank rank) implements Comparable<Card> {
    @Override
    public int compareTo(Card o) {
      return Comparator.comparing(Card::rank).thenComparing(Card::suit).compare(this, o);
    }
  }

  public static void main(String[] args) {
    var c1 = new Card(Suit.hearts, Rank.ace);
    var c2 = new Card(Suit.spades, Rank._2);
    System.out.println(c1.compareTo(c2));
  }
}
0
Emanuel Trandafir On

An alternative way would be to use the Comparator interface and its static factory methods introduced in Java8:

private final Comparator<Card> comparator = Comparator.comparingInt((Card card) -> card.rank.ordinal())
        .thenComparing((Card card) -> card.suit.ordinal());

You can then use this comparator directly, or through the overridden compareTo method:

@Override
public int compareTo(Card other) {
    return comparator.compare(this, other);
}

Since this question is also tagged with oop, I'll add that the whole comparison logic should belong to a card game, not to the card itself.

In other words, if this comparison is game-specific, you should avoid putting it inside your entity/model. Asa result, you'll be able to easily reuse the Card object for different card games.

0
Lajos Arpad On

You can add the further comparison into the else:

@Override
    public int compareTo(Card o) {
        
        if(this.rank.ordinal() > o.rank.ordinal()) {
            return 1;
        }
        else if (this.rank.ordinal() < o.rank.ordinal()) {
            return -1;
        } 
        else {
            if (this.suit.ordinal() > o.suit.ordinal()) {
                return 1;
            }
            else if (this.suit.ordinal() < o.suit.ordinal()) {
                return -1;
            }
        }

        return 0;
    }