# Playing Card Class - is this right?

The Art and Science of Java, a course book that uses the ACM library, has an exercise that reads like this:

Implement a new class called Card that includes the following entries:

• Named constants for the four suits (CLUBS, DIAMONDS, HEARTS, SPADES) and the four ranks that are traditionally represented in words (ACE, JACK, QUEEN, KING). The values of the rank constants should be 1, 11, 12, and 13, respectively.

• A constructor that takes a rank and a suit and returns a Card with those values. • Accessor methods getRank and getSuit to retrieve the rank and suit components of a card.

• An implementation of the toString method that returns the complete name of the card.

Now, this question is a little hard to understand, but nevertheless I've done a class that I think answers this:

/** Ficheiro: Carta.java
*
* Classe que vai representar os diferentes valores e naipes de uma carta de um baralho normal
* de 52 cartas. Exercício para construir uma classe completa juntamente com construtores,
* gets de Valores e Naipes e de método toString.  */

public class Carta {

// Constantes do Naipe (Rank) das Cartas
public static final String AS = "Ás";
public static final String REI = "Rei";
public static final String DAMA = "Dama";
public static final String VALETE = "Valete";

// Constantes do Valor Facial (Suit) das Cartas
public static final String COPAS = "Copas";
public static final String PAUS = "Paus";
public static final String OUROS = "Ouros";

/**
* Cria uma nova carta de um baralho regular de 52 cartas.
* @param valor O valor facial da carta (ex. Ás, Rei, 10...)
* @param naipe O naipe da carta
*/

public Carta (int valor, int naipe) {
valorCarta = valor;
numNaipe = naipe;
}

/**
* Obtém o valor facial da carta (existem 13 valores faciais)
* @return O valor facial da carta em String
*/

public String getValorCarta() {
switch (valorCarta) {
case 1: return AS;
case 11: return REI;
case 12: return DAMA;
case 13: return VALETE;
default: return "" + valorCarta;
}
}

/**
* Obtém o naipe da carta (existem 4 naipes)
* @return O naipe da carta em String
*/

public String getNaipeCarta () {
switch (numNaipe) {
case 1: return COPAS;
case 2: return PAUS;
case 3: return OUROS;
default: return ("Naipe Inválido");
}
}

/**
* Cria uma representação em String da Carta (Valor e Naipe)
* @return Representação em String da Carta (Valor e Naipe)
*/

public String toString () {
return getValorCarta() + " de " + getNaipeCarta();
}

// variáveis de instância que registam o Valor e o Naipe da Carta em integers.
private int valorCarta;
private int numNaipe;
}


Sorry about the commentaries. I speak Portuguese and I've written the commentaries in that language. I hope the code is easy enough to understand.

I want to know if I have written well the class, according to specifications, especially the Public Constants and the Get Methods.

I am not sure if they wanted me to make the constants int types instead of Strings. Also I didn't assign any parameters to the Get Methods, so they will only give me the rank or suit of a new Card Object. I am not sure if they wanted me to attribute an int param to these methods.

As a sidenote, I wrote a short program that demonstrates this class in action, in choosing and displaying a random card (note that the run method is the main method in acm libraries):

import acm.program.*;
import acm.util.*;

public class testeCarta extends ConsoleProgram{

// Escolhe uma carta aleatóriade um baralho de 52 cartas e imprime no ecrã
public void run () {
println ("Este programa vai seleccionar uma carta aleatória");
Carta cartaAleat = new Carta (rGen.nextInt(1,13),rGen.nextInt(1,4));
println (cartaAleat);
}

// variável de instància que permite a utilização de gerador de números aleatórios
public RandomGenerator rGen = RandomGenerator.getInstance();
}

• I would think that you did not do it right. I believe they are hinting at using a enum. Because your method accepts 2 integers you could put a suit into a rank and a rank into a suit and Java wouldn't complain. If you used a enum though your types would be checked and that problem is reduced. – Robert Snyder Apr 20 '13 at 3:52
• @RobertSnyder The Book where I did this exercise still hasn't made any mention of Enums so I'm pretty sure they aren't meant to be used in this case. – Antonio Ricardo Diegues Silva Apr 20 '13 at 4:12

## Enums

Java enums have been around for a long time, so it's really a waste not to be using them at this point.

However, I understand that this may simply be an exercise, to test and build your understanding of Java, one step at a time. If that is the case, (or maybe if the exercises are given in a specific order, and you haven't yet progressed to the Chapter on enums) then maybe you are intended to avoid them. I'll work on that assumption (no enums).

## Representation

Named constants for the four suits (CLUBS, DIAMONDS, HEARTS, SPADES) and the four ranks that are traditionally represented in words (ACE, JACK, QUEEN, KING).

A named constant simply means that in code, your Java can refer to constant values with variable names that are meaningful. It does not mean that those constants must be Strings, and usually, they should not be. If you have:

public class Carta {

public static final int REI = 11;


then, this code is using a named constant:

int rank = REI;


while this code is not:

int rank = 11;


The values of the rank constants should be 1, 11, 12, and 13, respectively.

This clearly is requesting an implementation where the constants are integer types, not String objects:

public static final int AS = 1;      // Ace
public static final int VALETE = 11; // Jack
public static final int DAMA = 12;   // Queen
public static final int REI = 13;    // King


(you'll have to double check my values .. I don't speak Portuguese, and I think I recognize the word Rei and Dama, but not the others)

These constants are in addition to the other cards, ranked 2 through 10.

## Specification Terminology

... that are traditionally represented in words

This language may be confusing, I understand. When they say "words", they're not asking for String constants. They are referring to the fact that, outside of JACK/QUEEN/KING/ACE, the other cards are 2,3,4,5,6,7,8,9,10 ... which are numbers.

You have some comments here (again, with my limited understanding of Portuguese), that I believe are backwards:

// Constantes do Naipe (Rank) das Cartas
public static final String AS = "Ás";

// Constantes do Valor Facial (Suit) das Cartas
public static final String COPAS = "Copas";


As (or Ace) is not a Naipe, it is a Valor (value, or rank). Even if the code is correct, it's important in software development to make the comments correct, too.

## toString()

Finally, concerning the specification for toString(), I believe that your existing code satisfies the requirement. But, remember, the constants really should be implemented as integers, not String constants. So, if you rewrite the class to represent values as integers, you'll then need a new method to convert integer values to Strings.

A HashMap<Integer,String> would probably work for that purpose. If you haven't gotten to using generics yet, even an array of strings (String[]) could be used to map int values to String, as long as you keep track of the 0 index, or use the 0 index element as an Invalid value.

• +1 Good job with the Portuguese. It's not easy. I say this because I do speak it myself. – Jonny Sooter Apr 20 '13 at 10:26
• I once worked in an office cube with an Australian guy who talked to his Brazilian wife on the phone all the time :) – Nate Apr 20 '13 at 10:30
• @Nate Thank you for you help in understanding the exercise. I see now that it was int all along that they wanted, so I'll atribute those to my Switch Cases (like switch (numNaipe) { case COPAS: return "Copas";) and will work from there. Your Portuguese is really admirable... yes I had that comment in Portuguese wrong - it was late and I was getting very sleepy :) - I will also correct it ofc! Thank you very much for your input, I learned something new today! – Antonio Ricardo Diegues Silva Apr 20 '13 at 11:13