您的位置:首页 > 其它

OOD - blackjack design

2016-03-20 23:38 447 查看


How
is my BlackJack game design?

up
vote7down
votefavorite

This is a command line BlackJack game created in Java as my final project for an advanced programming class.

What do you think about it?
Have I used OOP correctly?
What grade should I get for this? :D
Any concept in game that could be improved?

I used JRE 1.7. And to make Unicode characters work you must use Unicode in Eclipse.

This is my Class Diagram:



BlackJack.java
import java.io.*;

public class BlackJack
{
private static int BLACKJACK = 21;
private static int DECKSIZE = 52;
private static boolean isPlayerDone;

public static void main(String[] args) throws IOException
{
Deck deck = null;
Hand playersHand = null;
Hand splitHand = null;
Hand dealersHand = null;

System.out.println("--------------------------------------------------------");
System.out.println("-               BLACK               JACK               -");
System.out.println("--------------------------------------------------------\n");
boolean runGame = true;
while(runGame)
switch(options())
{
case "deal":
dealersHand = new Hand("Dealer");
playersHand = new Hand("Player");
splitHand = null;

isPlayerDone = false;

deck = initialDraw(deck, playersHand, splitHand, dealersHand);

if (playersHand.getHandTotal() == BLACKJACK)
{
System.out.print("Player has BLACKJACK!\n\n");
isPlayerDone = true;
System.out.print("Dealer uncovers card...\n\n");
showHands(playersHand, splitHand, dealersHand);
System.out.print("Dealer's move...\n\n");
deck = dealerDraw(deck, playersHand, splitHand, dealersHand);
showHands(playersHand, splitHand, dealersHand);
compareHands(playersHand, splitHand, dealersHand);
} // end if()

break; // end case "deal"

case "hit":
if(!isPlayerDone)
deck = hit(deck, playersHand, splitHand, dealersHand);
else
System.out.print("You must deal cards first!\n\n");
break; // end case "hit"

case "stand":
if(!isPlayerDone)
{
isPlayerDone = true;
deck = stand(deck, playersHand, splitHand, dealersHand);
} // end if()
else
System.out.print("You must deal cards first!\n\n");
break; // end case "stand"

case "split":
if(!isPlayerDone)
splitHand = split(playersHand, splitHand, dealersHand);
else
System.out.print("You must deal cards first!\n\n");
break; // end case "split"

case "exit":
runGame = false;
System.out.print("Game ended.\n\n");
break; // end case "exit"

default:
System.out.print("Invalid entry\n\n");
} // end switch()
} // end main()

private static Hand split(Hand player, Hand split, Hand dealer)
{
if(player == null)
System.out.print("You must deal cards first!\n\n");
else if(player.getHandSize() == 2 && player.bothEqual())
{
split = new Hand("Player");
split.insert(player.deleteFirst());

showHands(player, split, dealer);
compareHands(player, split, dealer);
} // end else if()
else if(!player.bothEqual())
System.out.print("Both card values must be the same!\n\n");
else
System.out.print("You must have no more than 2 cards to split!\n\n");

return split;
} // end split()

private static Deck stand(Deck deck, Hand player, Hand split, Hand dealer)
{
if(player == null)
System.out.print("You must deal cards first!\n\n");
else
{
isPlayerDone = true;
System.out.print("Dealer uncovers card...\n\n");
showHands(player, split, dealer);
System.out.print("Dealer's move...\n\n");
deck = dealerDraw(deck, player, split, dealer);
showHands(player, split, dealer);
compareHands(player, split, dealer);
} // end else

return deck;
} // end stay()

private static Deck hit(Deck deck, Hand player, Hand split, Hand dealer)
{
if(player == null)
System.out.print("You must deal cards first!\n\n");
else
{
deck = drawFromDeck(deck, player);
System.out.print("\n");

if(split != null)
{
deck = drawFromDeck(deck, split);
System.out.print("\n");
} // end if()

showHands(player, split, dealer);
compareHands(player, split, dealer);

if (player.getHandTotal() == BLACKJACK)
{
System.out.print("Player has BLACKJACK!\n\n");
isPlayerDone = true;
System.out.print("Dealer uncovers card...\n\n");
showHands(player, split, dealer);
System.out.print("Dealer's move...\n\n");
deck = dealerDraw(deck, player, split, dealer);
showHands(player, split, dealer);
compareHands(player, split, dealer);
} // end if()
else if(player.getHandTotal() > BLACKJACK)
{
System.out.print("Player Busted!\n\n");
isPlayerDone = true;
System.out.print("Dealer uncovers card...\n\n");
showHands(player, split, dealer);
compareHands(player, split, dealer);
}
} // end else

return deck;
} // end hit()

private static Deck dealerDraw(Deck deck, Hand player, Hand split, Hand dealer)
{
if(player.getHandTotal() <= BLACKJACK)
{
// Dealer takes a precaution and only draws
// if hand total is less than or equal to 16.
while(dealer.getHandTotal() <= 16 &&
(dealer.getHandTotal() <= player.getHandTotal() ||
(split != null  && dealer.getHandTotal() <= split.getHandTotal())))
deck = drawFromDeck(deck, dealer);

// Player has reached BLACKJACK!
// There's no or little chance to win,
// dealer risks and draws even if total is high.
if (player.getHandTotal() == BLACKJACK || (split != null  &&
split.getHandTotal() == BLACKJACK))
while(dealer.getHandTotal() < BLACKJACK)
deck = drawFromDeck(deck, dealer);
} // end if()

return deck;
} // dealerDraw()

private static Deck drawFromDeck(Deck deck, Hand hand)
{
deck = checkDeck(deck);

Card temp = new Card(deck.pop());

if (hand.getName().equals("Dealer") && !isPlayerDone)
{
if(hand.getHandSize() < 1)
System.out.print("Drawing Dealer's card... X_X");
else
System.out.print("Drawing Dealer's card... " + temp.toString());
} // end if()
else
{
if(hand.getName().equals("Dealer"))
System.out.print("Drawing Dealer's card... " + temp.toString() + "\n");
else
System.out.print("Drawing Player's card... " + temp.toString());
} // end else

System.out.print("\n");

hand.insert(temp);

return deck;
} // end drawFromDeck()

private static void compareHands(Hand player, Hand split, Hand dealer)
{
if (isPlayerDone)
{
if(player.getHandTotal() > BLACKJACK ||
(split != null && split.getHandTotal() > BLACKJACK))
{
System.out.print("Player Busted!\n");
if(dealer.getHandTotal() <= BLACKJACK)
System.out.print("Dealer Wins!\n\n");
} // end if()
else if(dealer.getHandTotal() > BLACKJACK)
{
System.out.print("Dealer Busted!\n");
if(player.getHandTotal() <= BLACKJACK ||
(split != null && split.getHandTotal() <= BLACKJACK))
System.out.print("Player Wins!\n\n");
} // end else if()
else if(dealer.getHandTotal() > BLACKJACK &&
(player.getHandTotal() > BLACKJACK ||
(split != null && split.getHandTotal() > BLACKJACK)))
{
System.out.print("Both Busted!\n");
} // end else if()
else
{
if((player.getHandTotal() > dealer.getHandTotal() &&
player.getHandTotal() <= BLACKJACK) ||
(split != null && (split.getHandTotal() > dealer.getHandTotal() &&
player.getHandTotal() <= BLACKJACK)))
System.out.print("Player Wins!\n\n");
else if((player.getHandTotal() < dealer.getHandTotal() &&
dealer.getHandTotal() <= BLACKJACK) ||
(split != null && (split.getHandTotal() < dealer.getHandTotal() &&
dealer.getHandTotal() <= BLACKJACK)))
System.out.print("Dealer Wins!\n\n");

if(player.getHandTotal() == BLACKJACK ||
(split != null && split.getHandTotal() == BLACKJACK))
System.out.print("Player has BLACKJACK!\n\n");
if(dealer.getHandTotal() == BLACKJACK)
System.out.print("Dealer has BLACKJACK!\n\n");
} // end else
} // end if()
} // end compareHands()

private static Deck checkDeck(Deck deck)
{
if(deck == null)
deck = createDeck();
else if(deck.isEmpty())
{
System.out.print("\nDeck is empty! You must create and shuffle new deck of cards!\n\n");
deck = createDeck();
} // end else if()

return deck;
} // end checkDeck()

private static Deck createDeck()
{
System.out.println("Creating deck...");
Deck deck = new Deck(DECKSIZE);
deck.createDeck();
System.out.println("Shuffling deck...");
deck.shuffleDeck();
System.out.print("\n");

return deck;
} // end createDeck()

private static Deck initialDraw(Deck deck, Hand player, Hand split, Hand dealer)
{
deck = drawFromDeck(deck, player);
deck = drawFromDeck(deck, dealer);
deck = drawFromDeck(deck, player);
deck = drawFromDeck(deck, dealer);

System.out.print("\n");

showHands(player, split, dealer);
compareHands(player, split, dealer);

return deck;
} // end initialDraw()

private static void showHands(Hand player, Hand split, Hand dealer)
{
System.out.print("Dealers Hand:");

if(!isPlayerDone)
{
dealer.peek();
System.out.print(" X_X = " + dealer.peekValue() + "\n");
} // end if()
else
{
dealer.displayHand();
System.out.print(" = " + (dealer.getHandTotal() == BLACKJACK ?
dealer.getHandTotal() + " : BLACKJACK!" :
((dealer.getHandTotal() > BLACKJACK) ?
dealer.getHandTotal() + " : BUSTED!" :
dealer.getHandTotal())) + "\n");
} // end else

System.out.print("Players Hand:");
player.displayHand();
System.out.print(" = " + (player.getHandTotal() == BLACKJACK ?
player.getHandTotal() + " : BLACKJACK!" :
((player.getHandTotal() > BLACKJACK) ?
player.getHandTotal() + " : BUSTED!" :
player.getHandTotal())) + "\n");

if (split != null)
{
System.out.print("Players Hand:");
split.displayHand();
System.out.print(" = " + (split.getHandTotal() == BLACKJACK ?
split.getHandTotal() + " : BLACKJACK!" :
((split.getHandTotal() > BLACKJACK) ?
split.getHandTotal() + " : BUSTED!" :
split.getHandTotal())) + "\n\n");
} // end if()
else
System.out.print("\n");
} // end showHands()

private static String options() throws IOException
{
System.out.print("deal, hit, split, stand, exit: ");
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
System.out.print("\n");
return s;
} // end options()
} // end BlackJack


Hand.java
class Hand
{
private Card first;
private int cardTotal;
private String name;
private int handSize;

public Hand(String name)
{
first = null;
this.name = name;
cardTotal = 0;
handSize = 0;
} // end Hand()

public void insert(Card card)
{
Card newLink = new Card(card);
newLink.next = first;

if (card.getRank() == 1 && cardTotal + card.getValue() > 21)
cardTotal = cardTotal + (card.getValue() - 10);
else
cardTotal = cardTotal + card.getValue();

handSize = handSize + 1;

first = newLink;
} // end insert()

public Card deleteFirst()
{
Card temp = first;
first = first.next;
cardTotal = cardTotal - temp.getValue();
handSize = handSize - 1;
return temp;
} // end deleteFirst()

public void displayHand()
{
Card current = first;
while(current != null)
{
current.showCard();
current = current.next;
} // end while()
} // end displayHand()

public boolean isEmpty()
{
return first == null;
} // end isEmpty()

public boolean bothEqual()
{
Card temp = first;
return temp != null && (temp.getValue() == temp.next.getValue());
} // end bothEqual()

public void peek()
{
first.showCard();
} // end peek()

public int peekValue()
{
return first.getValue();
} // end peekValue()

public int getHandSize()
{
return handSize;
} // end getHandSize()

public String getName()
{
return name;
} // end getName()

public int getHandTotal()
{
return cardTotal;
} // end getHandTotal()
} // end Hand


Deck.java
class Deck
{
private int maxSize;
private Card[] stackArray;
private int top;

public Deck(int s)
{
maxSize = s;
stackArray = new Card[maxSize];
top = -1;
} // end Deck()

private void push(Card card)
{
stackArray[++top] = new Card(card);
} // end push()

public Card pop()
{
return stackArray[top--];
} // end pop()

public boolean isEmpty()
{
return top == -1;
} // end isEmpty()

public void shuffleDeck()
{
Card swap;

for (int i = 0; i < stackArray.length; i++)
{
int r = i + (int) (Math.random() * (stackArray.length - i));
swap = stackArray[i];
stackArray[i] = stackArray[r];
stackArray[r] = swap;
} // end for()
} // end shuffleDeck()

public void createDeck()
{
String[] suit = {"\u2663", "\u2666", "\u2665", "\u2660"};
int[] rank = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};

for (int i = 0; i < rank.length; i ++)
{
for (int j = 0; j < suit.length; j++)
{
push(new Card(suit[j], rank[i]));
} // end for()
} // end for()
} // end createDeck()
} // end Deck


Card.java
class Card
{
public Card next;
private String suit;
private int rank;

Card(String suit, int rank)
{
this.suit = suit;
this.rank = rank;
} // end Card()

Card(Card card)
{
suit = card.suit;
rank = card.rank;
} // end Card()

private String getRankName()
{
if (rank == 1)
return "A";
else if (rank == 11)
return "J";
else if (rank == 12)
return "Q";
else if (rank == 13)
return "K";
else
return String.valueOf(rank);
} // end getRankName()

public int getValue()
{
if (rank == 1)
return 11;
else if (rank == 11 || rank == 12 || rank == 13)
return 10;

return rank;
} // end getValue()

public String getSuit()
{
return suit;
} // end getSuit()

public int getRank()
{
return rank;
} // end getRank()

public void showCard()
{
System.out.print(" " + getRankName() + "_" + suit);
} // end showCard()

@Override
public String toString()
{
return getRankName() + "_" + suit;
} // end toString()
} // end Card


java oop game playing-cards
shareimprove
this question
edited Jan
5 '14 at 22:08




Jamal
27.4k9102205

asked Dec 19 '12 at 0:55





HelpNeeder
391420

3
If you ever have a class with only static methods, it is should only be a Utility class (such as for static operations,
extracting variables etc). This class is not OO! – Tom
Cammann Dec
19 '12 at 18:58
what happens if you draw an ace, then a 2, then a 10? (you are supposed to be at 13, but apparently your
Hand.insert
method
puts you at 23, it does not appear to keep track of previous aces.) – njzk2Jan
21 '15 at 14:42
Njzk2, you are right. Never had a time to do this part. – HelpNeeder Jan
21 '15 at 16:22
I guess, we could solve this problem by checking the hands after each turn and do compare of the total with both upper
and lower bound value of the aces. – HelpNeeder Jan
21 '15 at 16:24
add
a comment


2 Answers

activeoldestvotes

up vote8down
voteaccepted
+50

A few notes:

I don't think you're utilizing OOP to its full potential in your
BlackJack
class;
all its methods are static and you're passing around too many variables. A cleaner alternative would be to make
deck
,
playersHand
,
splitHand
,
and
dealersHand
class-level
variables, change the methods to be non-static, and then you won't have to pass them all around. So something like this:
public class BlackJack {

...

private Deck deck;
private Hand splitHand;
private Hand playersHand;
private Hand dealersHand;
private boolean isPlayerDone;

public static void main(String[] args) throws IOException {
BlackJack blackjack = new BlackJack();
blackjack.start();
}

public void start() {
while(runGame) {
switch(options()) {
case "deal":
deal();
break;
case "hit":
hit();
break;
case "stand":
stand();
break;
...
}
}
}

public void deal() {
playersHand = new Hand("Player");
dealersHand = new Hand("Dealer");
splitHand = null;
isPlayerDone = false;

...
}

...

}


The
Hand
class
doesn't really need a
name
because
there are only 2 types of hands: dealer and player. So you can just pass in a
boolean
for
drawFromDeck()
:
private Deck drawFromDeck(boolean drawForPlayer) {
Hand hand = drawForPlayer ? playersHand
: dealersHand;

...
}


You have several different places where you're checking for blackjack, and I can't easily follow the logic.
compareHands()
checks
for blackjack, but there are a couple other places with some checks too. These might be necessary (I don't know the rules of Blackjack that well), but you should try to minimize duplicate logic as much as possible. For example, this block of code is in both
main()
and
hit()
:
if (player.getHandTotal() == BLACKJACK)
{
System.out.print("Player has BLACKJACK!\n\n");
isPlayerDone = true;
System.out.print("Dealer uncovers card...\n\n");
showHands(player, split, dealer);
System.out.print("Dealer's move...\n\n");
deck = dealerDraw(deck, player, split, dealer);
showHands(player, split, dealer);
compareHands(player, split, dealer);
} // end if()


I think fixing those (mostly points 1 & 3) would go a long way to making the code easier to read and maintain. I skimmed over your other classes and they seemed fine at a glance, having good separation
of concerns.

shareimprove
this answer
answered Dec 19 '12 at 4:32




seand
2,37711129

Thanks for yourr feedback. I was wondering with con/pros for global class variables but then decided to try to have
as little global variables as possible. I know they would have reduced amount of variables. Overall I guess you are right with your comments. Thanks. – HelpNeeder Dec
19 '12 at 21:35
@HelpNeeder: is there anything else you wanted me to critique specifically or are you just looking for other opinions? – seand Dec
21 '12 at 15:19
add
a comment
up vote3down
vote
Some remarks:

Your main method is HUGE, consider splitting it

This code:
deck = drawFromDeck(deck, player);
deck = drawFromDeck(deck, dealer);
deck = drawFromDeck(deck, player);
deck = drawFromDeck(deck, dealer);


can be reduced to this:
for(int i = 0; i < 4; i++)
deck = drawFromDeck(deck, dealer);


This code:
System.out.print(" = " + (player.getHandTotal() == BLACKJACK ?
player.getHandTotal() + " : BLACKJACK!" :
((player.getHandTotal() > BLACKJACK) ?
player.getHandTotal() + " : BUSTED!" :
player.getHandTotal())) + "\n");


is duplicated the lines below, you can create a method that accepts an
Hand
and
does its calculations

getRankName() in Card.java could be rewritten more cleanly with a switch

shareimprove
this answer
answered Dec 25 '12 at 18:52





miniBill
32619

1
#2, how would you rewrite this? I mean first we must draw player's card, then dealer's, then player's, then dealer's.
The for loop does not do this... – HelpNeeder Dec
25 '12 at 22:33
2
#2 could be done like so (typed without a compiler):
for(hand
: new Hand[]{player,dealer,player,dealer}) deck = drawFromDeck(deck,hand);
. Not sure if that is actually better. – Brian Dec
26 '12 at 18:26
@HelpNeeder oh, I'm sorry, I misread that code :| – miniBill Dec
26 '12 at 19:25
1
@Brian, this is interesting. I never used an array within for loop like you did. Thanks. But I wouldn't do this, in
this situation, like this because it's unnecessary to allocate more memory space for such array. – HelpNeeder Dec
26 '12 at 22:17
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: