0
votes

In a Java program I am trying to return the largest value card in a deck.

Diamonds are the lowest valued suit. Then clubs, then hearts and finally spades have the largest value. As you can see I have a section of code that simply says largest = in the findLargest methods. I am not sure where to go with the rest of this method.

public class Card {

    private int number;
    private String suit;

    /*
     * Randomly creates a card numbered 1 to 13 (ace = 1!) and labelled "Hearts","Clubs","Diamonds" or "Spades".
     */
    public Card() {
        double randomNum = Math.random() * 4.0;
        if (randomNum < 1.0)
            suit = "Hearts";
        else if (randomNum < 2.0)
            suit = "Clubs";
        else if (randomNum < 3.0)
            suit = "Diamonds";
        else
            suit = "Spades";
        randomNum = Math.random() * 13.0;
        number = (int) randomNum + 1;
    }
    /*
     * Creates a card with specified number and suit
     */
    public Card (int n, String s) {
        number = n;
        suit = s;
    }

    public int getNumber() {
        return number;
    }

    public String getSuit () {
        return suit;
    }


    public String cardString() {
        // System.out.println(number + " " + suit);
        String stringNum = "";
        switch (number) {
        case 1:
                stringNum = "Ace";
                break;
            case 2:
                stringNum = "Two";
                break;
            case 3:
                stringNum = "Three";
                break;
            case 4:
                stringNum = "Four";
                break;
            case 5:
                stringNum = "Five";
                break;
            case 6:
                stringNum = "Six";
                break;
            case 7:
                stringNum = "Seven";
                break;
            case 8:
                stringNum = "Eight";
                break;
            case 9:
                stringNum = "Nine";
                break;
            case 10:
                stringNum = "Ten";
                break;
            case 11:
                stringNum = "Jack";
                break;
            case 12:
                stringNum = "Queen";
                break;
            case 13:
                stringNum = "King";
                break;
            default:
                System.out.println("Error in Card - illegal number");
            }
            return stringNum + " of " + suit;
        }
    }


public class PackCards {

    private ArrayList<Card> pack;

    /*
     * Create a random pack of size n
     */
    public PackCards(int n) {
        Card c;
        pack = new ArrayList<Card>();
        for (int i = 1; i <= n; i++) {
            c = new Card();
            pack.add(c);
        }
    }

    public void printPack() {
        for (Card c : pack) {
            System.out.println(c.cardString());
        }
    }


    public Card findLargest() {

        if ( c.getNumber() > largest.getNumber() ) 
            largest = 
                else if (c.getNumber() == largest.getNumber() ) {
                    if (largest.getSuit().equals("Diamonds"))
                largest = largest.getNumber; 
                }
                else if (c.getNumber() == largest.getNumber() ) {
                    if (largest.getSuit().equals("Clubs"))
                        largest = largest.getNumber;
                }
                else if (c.getNumber() == largest.getNumber() ) {
                    if (largest.getSuit().equals("Hearts"))
                        largest = largest.getNumber;
                }

                else return;


    }
3

3 Answers

1
votes

I would simplify the code to make it easier to see what you are trying to achieve. In Java 8 you can do.

import java.util.Random;

public class Card  {
    enum Suit {
        // must be in increasing order.
        Spades, Diamonds, Clubs, Hearts
    }

    static final Suit[] SUITS = Suit.values();

    private final int number;
    private final Suit suit;

    /*
     * Randomly creates a card numbered 1 to 13 (ace = 1!) and labelled "Hearts","Clubs","Diamonds" or "Spades".
     */
    public Card() {
        Random rand = new Random();
        suit = SUITS[rand.nextInt(SUITS.length)];
        number = rand.nextInt(13) + 1;
    }

    public int getNumber() {
        return number;
    }

    public Suit getSuit() {
        return suit;
    }

    static final String[] NAMES = ",Ace,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King".split(",");

    public String cardString() {
        assert number > 1 && number < NAMES.length;
        return NAMES[number] + " of " + suit;
    }
}

This simplifies your pack as well

public class PackOfCards {
    private final List<Card> cards;

    public PackOfCards(int size) {
        // note duplicates are possible, i.e. ever card could be the same.
        cards = IntStream.range(0, size)
                .mapToObj(n -> new Card())
                .collect(Collectors.toList());
    }

    public Card findLargest() {
        return cards.stream().max(Comparator.comparing(Card::getNumber)
                .thenComparing(Card::getSuit)).get();
    }
}
1
votes

You can change the Card class to implements the Comparable interface. For example:

public class Card implements Comparable<Card> {
    ....// your current implementation for the Card class

    public int compareTo(Card another) {
        if (this.suit.compareTo(another.suit) == 0) {
            if (this.number < another.number) {
                return -1;
            } else if (this.number > another.number) {
                return 1;
            } else {
                return 0;
            }
        } else if (this.suit.compareTo("Diamonds") == 0) {
            // Diamonds being the lowest valued suit ...
            return -1;
        } else if (this.suit.compareTo("Clubs") == 0) {
            // ... then Clubs ...
            if (another.suit.compareTo("Diamonds") == 0) {
                return 1;
            } else {
                return -1;
            }
        } else if (this.suit.compareTo("Hearts") == 0) {
            // ... Hearts ...
            if (another.suit.compareTo("Spades") == 0) {
                return -1;
            } else {
                return 1;
            }
        } else {
            // ... and largest values, Spades
            return 1;
        }
    }
}

Then, you can modify the PackCards to store the cards in an ordered collection. For example:

pack = new TreeSet<Card>();

That way, the cards in the pack are ordered, and the last one is the largest.

If you want to mantain the order in wich the cards was added to the list, you can obtain the largest one in this way:

largest = Collections.max(pack);
0
votes

For this sort of work, you want to leverage the object-oriented nature of Java and utilize Enums for both the FaceValue and the Suit. Enums are 'naturally ordered' in the order you list them, making your construction and string output a LOT easier:

public class Card implements Comparable<Card> {

  private FaceValue faceValue;
  private Suit suit;

  /*
   * Randomly creates a card numbered 1 to 13 (ace = 1!)
   * labelled "Hearts","Clubs","Diamonds" or "Spades".
   */
  public Card() {
    int randomSuit = (int)Math.floor(Math.random() * 4.0); //Number between 0 and 3, inclusive.
    int randomFace = (int)Math.floor(Math.random() * 13.0);
    this.faceValue = FaceValue.values()[randomFace];
    this.suit = Suit.values()[randomSuit];
  }

  public Card(FaceValue value, Suit suit) {
    this.faceValue = value;
    this.suit = suit;
  }

  // TODO Constructor that convert ints and strings to proper enums and call previous constructor

  public int compareTo(Card that) {
    int comparison = this.suit.compareTo(that.suit);
    return (comparison != 0) ? comparison : this.faceValue.compareTo(that.faceValue);
  }

  public String cardString() {
    return this.faceValue + " of " + this.suit;
  }

  public enum Suit{
    DIAMOND, CLUB, HEART, SPADE;
  }

  public enum FaceValue {
     ACE, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING;
  }  // You can modify this enum if you need to give back something more specific as the string value.
}

Then for your Deck you can simplify things as well by choosing a good data structure, in this case a TreeSet, which will automatically use the compareTo function you've provided for cards to sort the cards.:

public class Deck {
  //By using a Set we eliminate duplicates
  private final TreeSet<Card> cards;

  public Deck(int size) {
    cards = Sets.newTreeSet(IntStream.range(0, size)
                                     .mapToObj(n -> new Card())
                                     .collect(Collectors.toList());
  }

  //Because this is a TreeSet, finding the largest value is trivial.
  public Card findLargest() {
    return this.cards.last();
  }
}

If you need special strings for the cards in your deck, you would do the following modification to FaceValue:

public enum FaceValue {
  ACE {
    public String toString() { return "Ace"; }
  }, 
  ONE {
    public String toString() { return "One"; }
  }, 
  ...  // Fill out the rest in the same manner.
  KING {
    public String toString() { return "King"; }
  }
}

Remember that in Object-Oriented programming, the number one rule is that an object should know how behave. Thus, if you find yourself writing a switch statement, chances are you can defer the behavior to the objects themselves. In this case, you need to create sub-objects (the FaceValue and Suit enums) that you assign to a given card. The card asks those sub parts how they are ordered, and how they should respond to a toString request.