I'm designing a Black Jack program. My issue is that, I use a switch case to generate a random card. But when it comes time to compare the value of the cards....lets say if(pCard1 + pCard2 > 21)
it's not allowing me to compare them because they are strings. However, they need to be strings because I have to be able to assign String "Queen"
but I also need "Queen" to have an int value of 10. I'm not sure how to go about this.
Here's what I have so far. I'm not including my entire code because its a couple hundreds of lines long. Only including the blackjack section.
System.out.println("---------------------Black Jack--------------------------");
System.out.println("Welcome to BlackJack!");
System.out.println("Available balance is $"+balance);
System.out.print("How much would you like to bet on this hand?: ");
int bet = input.nextInt();
balance -= bet;
System.out.println("You just bet $"+bet+"......Dealing cards!");
System.out.println("----------------------------------------------------------");
String pCard1 = dealCard();
String pCard2 = dealCard();
System.out.println("Your hand is a "+pCard1+" and "+pCard2);
System.out.print("Would you like to Hit or Stand? :");
String hOs = input.next();
if(hOs.equals("Hit")) {
String pCard3 = dealCard();
if(pCard1 + pCard2 + pCard3);
}
}
}
public static String dealCard() {
int value = (int)(Math.random() * 13);
String returnString = "";
switch ( value ) {
case 1: returnString = "Ace"; break;
case 2: returnString = "2"; break;
case 3: returnString = "3"; break;
case 4: returnString = "4"; break;
case 5: returnString = "5"; break;
case 6: returnString = "6"; break;
case 7: returnString = "7"; break;
case 8: returnString = "8"; break;
case 9: returnString = "9"; break;
case 10: returnString = "10"; break;
case 11: returnString = "Jack"; break;
case 12: returnString = "Queen"; break;
case 13: returnString = "King"; break;
}
return returnString;
}
}
I think enums are the best way to address this kind of issue.
If we define enums for Suit and Pips like so
enum Suit {
Hearts, Diamonds, Clubs, Spades;
}
enum Pips {
Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King;
}
And if we define a class Card:
class Card {
Suit suit;
Pips pips;
public Card(Suit suit, Pips pips) {
this.suit = suit;
this.pips = pips;
}
@Override
public String toString() {
return pips.toString() + " of " + suit.toString();
}
}
Card
uses toString()
to convert Suit and Pips to strings, while a zero-index numeric value can be obtained using ordinal()
:
Card card = new Card(Suit.Spades, Pips.Ace);
System.out.println("Card: " + card);
System.out.println("Numeric suit: " + card.suit.ordinal());
System.out.println("Numeric pips: " + card.pips.ordinal());
This simple implementation has a couple of limitations. First, the name of the suit or pips can only ever be a string version of the enum name. What if you wanted all your enums in UPPER CASE as is good style? The second problem is that the ordinal is always zero-indexed. What if you need some other id system for the pips?
In this case we add maps to each enum to hold these mappings. Unfortunately we can't use inheritance to share code between enums and so the boiler plate gets a little wordy.
enum Suit {
HEARTS(1, "Hearts"), //
DIAMONDS(2, "Diamonds"), //
CLUBS(3, "Clubs"), //
SPADES(4, "Spades");
private static Map<String, Suit> nameToEnum = new HashMap<>();
private static Map<Integer, Suit> idToEnum = new HashMap<>();
static {
for (Suit suit : Suit.values()) {
nameToEnum.put(suit.getName(), suit);
idToEnum.put(suit.getId(), suit);
}
}
private int id;
private String name;
private Suit(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public static Suit fromName(String name) {
return nameToEnum.get(name);
}
public static Suit fromId(int id) {
return idToEnum.get(id);
}
}
enum Pips {
ACE(1, 1, "Ace"), //
TWO(2, 2, "Two"), //
THREE(3, 3, "Three"), //
FOUR(4, 4, "Four"), //
FIVE(5, 5, "Five"), //
SIX(6, 6, "Six"), //
SEVEN(7, 7, "Seven"), //
EIGHT(8, 8, "Eight"), //
NINE(9, 9, "Nine"), //
TEN(10, 10, "Ten"), //
JACK(11, 10, "Jack"), //
QUEEN(12, 10, "Queen"), //
KING(13, 10, "King");
private static Map<String, Pips> nameToEnum = new HashMap<>();
private static Map<Integer, Pips> idToEnum = new HashMap<>();
static {
for (Pips pips : Pips.values()) {
nameToEnum.put(pips.getName(), pips);
idToEnum.put(pips.getId(), pips);
}
}
private int id;
private int value;
private String name;
private Pips(int id, int value, String name) {
this.id = id;
this.value = value;
this.name = name;
}
public int getId() {
return id;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
public static Pips fromName(String name) {
return nameToEnum.get(name);
}
public static Pips fromId(int id) {
return idToEnum.get(id);
}
}
With these new enums, we modify Card.toString()
to use the new getName()
methods:
return pips.getName() + " of " + suit.getName();
And now when we work with Cards we can use any of the ID or the name or the enum and convert freely between them:
Card card = new Card(Suit.SPADES, Pips.ACE);
System.out.println("Card: " + card);
System.out.println("Numeric suit: " + card.suit.getId());
System.out.println("Numeric pips: " + card.pips.getId());
System.out.println("Suit by ID: " + Suit.fromId(3).getName());
System.out.println("Pips by Name: " + Pips.fromName("Ace").getName());
System.out.println("Pips value by Name: " + Pips.fromName("King").getValue());
I recommend using Enum, so you can compare the cards easily.
your desired enum class would be:
public enum Cards {
ace (1),
two (2),
three (3),
four (4),
five (5),
six (6),
seven (7),
eight (8),
nine (9),
ten (10),
jack (11),
queen (12),
king (13)
;
private final int code;
Cards(int code){
this.code = code;
}
public Integer value(){
return code;
}
public static Cards getRelatedEnum(Integer code){
if(code == null)
return null;
switch (code){
case 1: return ace;
case 2: return two;
case 3: return three;
case 4: return four;
case 5: return five;
case 6: return six;
case 7: return seven;
case 8: return eight;
case 9: return nine;
case 10: return ten;
case 11: return jack;
case 12: return queen;
case 13: return king;
default: return null;
}
}
public static String toString(Cards card){
if(card == null)
return "";
switch (card){
case ace: return "ace";
case two: return "2";
case three: return "3";
case four: return "4";
case five: return "5";
case six: return "6";
case seven: return "7";
case eight: return "8";
case nine: return "9";
case ten: return "10";
case jack: return "jack";
case queen: return "queen";
case king: return "king";
default: return null;
}
}
}
then you can change your dealCard()
method to:
public static Cards dealCard() {
int value = (int)(Math.random() * 13);
return Cards.getRelatedEnum(value);
}
to compare card values use something like:
public static void main(String[] args){
System.out.println("---------------------Black Jack--------------------------");
System.out.println("Welcome to BlackJack!");
System.out.println("Available balance is $"+balance);
System.out.print("How much would you like to bet on this hand?: ");
int bet = input.nextInt();
balance -= bet;
System.out.println("You just bet $"+bet+"......Dealing cards!");
System.out.println("-------------------------------------------");
Cards pCard1 = dealCard();
Cards pCard2 = dealCard();
System.out.println("Your hand is a "+pCard1.toString() +" and "+pCard2.toSring());
System.out.print("Would you like to Hit or Stand? :");
String hOs = input.next();
if(hOs.equals("Hit")) {
Cards pCard3 = dealCard();
if(pCard1.value() + pCard2.value() > pCard3.value());
}
}
Ten, Jack, Queen, and King are all different ranks but share the same value of 10. Since they all have the same value, you need more than just a card's value to determine it's rank. Admittedly, you could represent Jack's value as 11, Queen as 12, etc and then code your methods to recognize any value over 10 as 10, but this is bad coding practice.
Instead, you should encode both the rank and the value in each card (Additionally, you may want to include suit; although that may not matter for blackjack).
Rather than represent your card as a string, I recommend making a Card class that has a String rank and an integer value. Additionally, this would be a good opportunity to explore enums in Java as others have commented.