1

I am trying to implement different sorting algorithms on a deck of cards. I've implemented a base card class using enums to build the suits and faces. My class is based on Dietel's & Dietel's Java Book. However, I am struggling in passing the deck of cards into the sorting algorithms I implemented as I am not able to pass in an array which I can sort. I don't know if my approach is correct, I've read many of the posts on stackexchange where some recommend using Comparable (Implementing a Deck of Cards in Java) which I can't see working with my sorting algorithms. See (How to Sort the Cards. (Is my code wrong?)) and (Implementing a Deck of Cards in Java) and (Java Sorting object in ArrayList). By having the DeckOfCards return a sequence of numbers e.g. 1.1, 1.2, 1.3, I think I have a sequence which can be sorted. I also read about ordinals but all the comments on those seemed to oppose the approach. Appreciate any help on this attempt. Kindly note, that I've implemented merge sort and selection sort in the same way and its the same problem - I am clearly missing something here!

Below is my code:

//Card class

class Card
{    
     //public static enum Face {Ace, Deuce, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King};
     public static enum Face {Ace(1), King(2), Queen(3), Jack(4), Ten(5), Nine(6), Eight(7), Seven(8), Six(9), Five(10), Four(11), Three(12), Deuce(13);
     int rank;
     Face(int r){ rank = r;}
     int getRank() {return rank;}
}
//public static enum Suit {Clubs, Diamonds, Hearts, Spades };
public static enum Suit {Spades(1), Hearts(2), Diamonds(3), Clubs(4);
   int order;
   Suit(int o){ order = o;}
   int getOrder() {return order;}
}

private final Face face; // face of card
private final Suit suit; // suit of card

// two-argument constructor
public Card( Face cardFace, Suit cardSuit ) 
{   
    face = cardFace; // initialize face of card
    suit = cardSuit; // initialize suit of card
}

// return face of the card
public Face getFace() { return face;}

// return suit of Card
public Suit getSuit() { return suit;}

// return String representation of Card
public String toString()
{
   //return String.format( "%s.%s", suit.getOrder(), face.getRank() );
   return String.format( "%s.%s", suit, face );
}
}

 // class DeckOfCards declaration
 public class DeckOfCards 
{
   private List< Card > list; // declare List that will store Cards

   // set up deck of Cards and shuffle
   public DeckOfCards()
  {
     Card[] deck = new Card[ 52 ];
     int count = 0; // number of cards

     // populate deck with Card objects
     for ( Card.Suit suit : Card.Suit.values() )  
     {
         for ( Card.Face face : Card.Face.values() )   
        {
            deck[ count ] = new Card( face.getRank(), suit.getOrder() );
            count++;
        }
     }

     list = Arrays.asList( deck ); // get List
     //Collections.shuffle( list );  // shuffle deck
   }

   // output deck
   public void printCards()
  {
      // display 52 cards in two columns
      for ( int i = 0; i < list.size(); i++ )
      System.out.printf( "%-20s%s", list.get( i ),
          ( ( i + 1 ) % 2 == 0 ) ? "\n" : "" );
  }

  public static void main( String[] args )
 {
     DeckOfCards cards = new DeckOfCards();
     cards.printCards();
    //cards.InsertionSort();    
 }
 }

//Insertion Sort

public static void insertionSort(DeckOfCards[] listToSort) 
{
    for (int i = 0; i < listToSort.length-1; i++) 
    {
        for (int k = i+1; k>0; k--) 
       {
           if(listToSort[k] < listToSort[k-1]) //Code breaks here
           {
                swap(listToSort, k, k-1);
            }
            else 
            {
                break;
            }
            print(listToSort);
        }
    }
}
Community
  • 1
  • 1
Cola4ever
  • 189
  • 1
  • 1
  • 16
  • You could use [`Collections.sort`](https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#sort(java.util.List,%20java.util.Comparator)) – 4castle Jun 27 '16 at 03:33
  • 1
    @4castle "I am trying to implement different sorting algorithms", "My class". Seems like using an existing sorting method isn't what OP is looking for here. – avojak Jun 27 '16 at 03:35

3 Answers3

3

The issue is that listToSort[k] < listToSort[k-1] is attempting to compare two DeckOfCards objects using the < operator, which is not allowed in Java - See: Compare two objects with or operators in Java.


As that post points out, you should instead be using a Comparator for the Card objects.

public class CardComparator implements Comparator<Card> {
    @Override
    public int compare(Card o1, Card o2) {
        // ...
        // Use Card.getFace().getRank() and Card.getSuit().getOrder()
        // ...
    }
}

In your DeckOfCards class, I'd also recommend adding a method such as:

public List<Card> getCards() { ... }

which returns a List of the cards in the deck. Then, in your insertionSort method, instead of listToSort[k], you would have listToSort.getCards().get(k). Also, instead of using < you can use a new instance of your CardComparator to determine whether or not to swap the cards.

public static void insertionSort(DeckOfCards cardsToSort) {
    final Comparator cardComparator = new CardComparator();
    for (int i = 0; i < cardsToSort.size() - 1; i++) {
        for (int k = i + 1; k > 0; k--) {
            final Card card1 = cardsToSort.getCards().get(k);
            final Card card2 = cardsToSort.getCards().get(k - 1);
            if(cardComparator.compare(card1, card2) < 0) {
                swap(cardsToSort, k, k-1);
            } else {
                break;
            }
        }
    }
} 
Community
  • 1
  • 1
avojak
  • 2,342
  • 2
  • 26
  • 32
  • Hi @avojak, thanks for your answer, this is very useful! I am just not clear on that the compare method should do - I saw examples where if you have one enum then you would return the different but in my case and with two enums, what should it return. Another question is what should the compareTo method do, or is return 0 enough? Thanks for your help! – Cola4ever Jun 27 '16 at 05:14
  • @Cola4ever Sorry, that first link I added is a little confusing since it mentions a couple of approaches. If you take a look at the Javadoc for [Comparator.compare(T o1, T o2)](http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#compare-T-T-) you'll see that it says "Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second." So the logic in `compare()` should do just that! If the **first** object is **greater** and you want to sort in ascending order, then you would return a **negative integer**. etc. – avojak Jun 27 '16 at 13:33
1

listToSort is an array of DeckOfCards. On the line indicated with //Code breaks here you're trying to compare two DeckOfCards objects, which you just can't do in java (Operator overloading in other languages would allow you do do this).

How about you write a method, such as .getSortValue() to give you a value to sort it by. Alternatively you could write something to compare the values within the card like:

if(listToSort[k].getSuit().getOrder()*13+listToSort[k].getFace().getOrder() < listToSort[k- 1].getSuit().getOrder()*13+listToSort[k-1].getFace().getOrder())

...which is a bit long, but I would assume does what you want.

Note the *13 means that each combination of suit and face is unique

TLDR: If you want to sort it in any other order, you'll have to come up with a value from each card that you can compare properly

Tom
  • 1,221
  • 10
  • 21
  • Doesn't this mean I would have to inherit the methods getSuit() & getFace()? And invoke another constructor in the DeckOfCards class? As the getSuit & getFace methods are implemented in the Card class - sorry I don't have much experience with Java. – Cola4ever Jun 27 '16 at 03:43
  • No, not at all. `listToSort[k]` gives you the "kth" instance of a 'DeckOfCards' from the array `listToSort`. This means you can call any of its public methods from wherever your sorting code is. A constructor would be used to create a `new` `DeckOfCards`. I assume the `DeckOfCards` obhect is meant to represent a single card, so maybe it should be renamed – Tom Jun 27 '16 at 03:51
-1

The proper approach would be to split the whole deck into suits and then sort each suite individually. Your version of insertion sort is not working because the sorting is done using the face values i.e aces, 2,3,4 ... And I wouldn't count this as sorting a deck .

private HashMap<Suite,ArrayList<Cards>> deck ;

//scan through the whole deck

for(int i = 0;i < 52; ++i) {

    `switch(cards[i]) {`

      `case Aces :`
        deck.put(Suite.Aces,cards[i]) ;
        break;
    .....
}

}

//Now sort

sort(deck.get(Suite.Aces)) ;

sort(deck.get(Suite.Diamond)) ;

parthibd
  • 1
  • 1
  • 3
  • Thanks for your comment! Where would I implement the Hashmap, would it be in the deckOfCards class? – Cola4ever Jun 27 '16 at 03:43
  • @parthibd "Your version of insertion sort is not working because the sorting is done using the face values i.e aces, 2,3,4 ... And I wouldn't count this as sorting a deck" ...is that not the point of sorting a deck? Sorting a deck consists of both sorting the suit and face value - both of which can be accomplished at the same time. – avojak Jun 27 '16 at 03:54
  • @avojak : Sure it could be done . My approach was a little simpler . My approach was to sort only the face values . First split the deck into 4 different suites and then sort those suites individually . A little inefficient than yours though. – parthibd Jun 27 '16 at 04:12