version 5 chapter 8 question 1
https://github.com/gaylemcd/ctci/tree/master/java/Chapter%208/Question8_1
题目是设计纸牌的数据结构,并且实现blackjack游戏
首先确认设计为标准可拓展的cards
standard 52 card set, It includes thirteen ranks of each of the four French suits, clubs (♣), diamonds (♦), hearts (♥) and spades (♠), with reversible "court" or face cards
1 Suit 纸牌有四种类型(花色)
/*
*Suit for card
*/
public enum Suit{
Club (0);
Diamon(1);
Heart(2);
Spade(3);
private int value;
private Suit(int v){
value = v;
}
public int getValue(){
return value;
}
public static Suit getSuitFromValue(int value){
switch(value){
case 0 :
return Suit.Club;
case 1:
return Suit.Diamon;
case 2 :
return Suit.Heart;
case 3:
return Suit.Spade;
default:
return null;
}
}
}
(2) card 类
abstract card class
//card abstact class can be extend
public abstract class Card{
/* number or face that's on card
a number 2 through 10,
or 11 for Jack, 12 for Queen, 13 for King, or 1 for Ace
*/
protected in faceValue;
protected Suit suit;
private boolean available = true;
public Card(int c, Suit s) {
faceValue = c;
suit = s;
}
public abstract int value();
public Suit suit() {
return suit;
}
/* returns whether or not the card is available to be given out to someone */
public boolean isAvailable() {
return available;
}
public void markUnavailable() {
available = false;
}
public void markAvailable() {
available = true;
}
public void print() {
String[] faceValues = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
System.out.print(faceValues[faceValue - 1]);
switch (suit) {
case Club:
System.out.print("c");
break;
case Heart:
System.out.print("h");
break;
case Diamond:
System.out.print("d");
break;
case Spade:
System.out.print("s");
break;
}
System.out.print(" ");
}
}
//Deck
public class Deck<T extends Card>{
private ArrayList<T> cards; // all cards, dealt or not
private int dealtIndex = 0; // mark first undealt card
public Deck(){
}
public void setDeckOfCards(ArrayList<T> deckOfCards){
cards = deckOfCards;
}
/*********** shuffle cards *************************/
public void shuffle() {
for (int i = 0; i < cards.size(); i++) {
int j = randomIntInRange(i, cards.size() - i - 1);
//swap with a random card
T card1 = cards.get(i);
T card2 = cards.get(j);
cards.set(i, card2);
cards.set(j, card1);
}
}
public int remainingCards() {
return cards.size() - dealtIndex;
}
/************************************/
public T[] dealHand(int number){
if(remainingCards() < number){
return null;
}
T[] hand = (T[]) new Card[number];
int count = 0;
while(count < number){
T card = dealCard();
if(card != null){
hand[count] = card;
count++;
}
}
return hand;
}
public T dealCard() {
if (remainingCards() == 0) {
return null;
}
T card = cards.get(dealtIndex);
card.markUnavailable();
dealtIndex++;
return card;
}
public void print() {
for (Card card : cards) {
card.print();
}
}
public static int randomInt(int n) {
return (int) (Math.random() * n);
}
public static int randomIntInRange(int min, int max) {
return randomInt(max + 1 - min) + min;
}
}
//card in Hand for player
public class Hand <T extends Card> {
protected ArrayList<T> cards = new ArrayList<T>();
public int score() {
int score = 0;
for (T card : cards) {
score += card.value();
}
return score;
}
public void addCard(T card) {
cards.add(card);
}
public void print() {
for (Card card : cards) {
card.print();
}
}
}
// for blackjack game face cards are 10 and ace is 11
public class BlackJackCard extends Card {
public BlackJackCard(int c, Suit s){
super(c, s);
}
public int value(){
//implement this function
if (isAce()) { // Ace
return 1;
} else if (faceValue >= 11 && faceValue <= 13) { // Face card
return 10;
} else { // Number card
return faceValue;
}
}
public int minValue() {
if (isAce()) { // Ace
return 1;
} else {
return value();
}
}
public int maxValue() {
if (isAce()) { // Ace
return 11;
} else {
return value();
}
}
public boolean isAce() {
return faceValue == 1;
}
public boolean isFaceCard() {
return faceValue >= 11 && faceValue <= 13;
}
}
public class BlackJackHand extends Hand<BlackJackCard> {
public BlackJackHand() {
}
public int score() {
ArrayList<Integer> scores = possibleScores();
int maxUnder = Integer.MIN_VALUE;
int minOver = Integer.MAX_VALUE;
for (int score : scores) {
if (score > 21 && score < minOver) {
minOver = score;
} else if (score <= 21 && score > maxUnder) {
maxUnder = score;
}
}
return maxUnder == Integer.MIN_VALUE ? minOver : maxUnder;
}
private ArrayList<Integer> possibleScores() {
ArrayList<Integer> scores = new ArrayList<Integer>();
if (cards.size() == 0) {
return scores;
}
for (BlackJackCard card : cards) {
addCardToScoreList(card, scores);
}
return scores;
}
private void addCardToScoreList(BlackJackCard card, ArrayList<Integer> scores) {
if (scores.size() == 0) {
scores.add(0);
}
int length = scores.size();
for (int i = 0; i < length; i++) {
int score = scores.get(i);
scores.set(i, score + card.minValue());
if (card.minValue() != card.maxValue()) {
scores.add(score + card.maxValue());
}
}
}
public boolean busted() {
return score() > 21;
}
public boolean is21() {
return score() == 21;
}
public boolean isBlackJack() {
if (cards.size() != 2) {
return false;
}
BlackJackCard first = cards.get(0);
BlackJackCard second = cards.get(1);
return (first.isAce() && second.isFaceCard()) || (second.isAce() && first.isFaceCard());
}
}
Core part: the game system
public class BlackJackGameAutomator {
private Deck<BlackJackCard> deck;
private BlackJackHand[] hands;
private static final int HIT_UNTIL = 16;
public BlackJackGameAutomator(int numPlayers) {
hands = new BlackJackHand[numPlayers];
for (int i = 0; i < numPlayers; i++) {
hands[i] = new BlackJackHand();
}
}
public boolean dealInitial(){
//each person get two card
for(BlackJackHand hand : hands){
BlackJackCard card1 = deck.dealCard();
BlackJackCard card2 = deck.dealCard();
if (card1 == null || card2 == null) {
return false;
}
hand.addCard(card1);
hand.addCard(card2);
}
return true;
}
public ArrayList<Integer> getBlackJacks() {
ArrayList<Integer> winners = new ArrayList<Integer>();
for (int i = 0; i < hands.length; i++) {
if (hands[i].isBlackJack()) {
winners.add(i);
}
}
return winners;
}
public boolean playHand(int i) {
BlackJackHand hand = hands[i];
return playHand(hand);
}
public boolean playHand(BlackJackHand hand) {
while (hand.score() < HIT_UNTIL) {
//get one more card
BlackJackCard card = deck.dealCard();
if (card == null) {
return false;
}
hand.addCard(card);
}
return true;
}
public boolean playAllHands() {
for (BlackJackHand hand : hands) {
if (!playHand(hand)) {
return false;
}
}
return true;
}
public ArrayList<Integer> getWinners() {
ArrayList<Integer> winners = new ArrayList<Integer>();
int winningScore = 0;
for (int i = 0; i < hands.length; i++) {
BlackJackHand hand = hands[i];
if (!hand.busted()) {//<=21
if (hand.score() > winningScore) {
winningScore = hand.score();
winners.clear();
winners.add(i);
} else if (hand.score() == winningScore) {
winners.add(i);
}
}
}
//winner with max score
return winners;
}
public void initializeDeck() {
ArrayList<BlackJackCard> cards = new ArrayList<BlackJackCard>();
//generate 52 cards , 13 in each suit
for (int i = 1; i <= 13; i++) {
//loop each suit
for (int j = 0; j <= 3; j++) {
Suit suit = Suit.getSuitFromValue(j);
BlackJackCard card = new BlackJackCard(i, suit);
cards.add(card);
}
}
deck = new Deck<BlackJackCard>();
deck.setDeckOfCards(cards); // add all cards
deck.shuffle(); //shuffle all cards
}
public void printHandsAndScore() {
for (int i = 0; i < hands.length; i++) {
System.out.print("Hand " + i + " (" + hands[i].score() + "): ");
hands[i].print();
System.out.println("");
}
}
}
Test function:
public static void main(String[] args) {
int numHands = 5;
BlackJackGameAutomator automator = new BlackJackGameAutomator(numHands);
automator.initializeDeck();
boolean success = automator.dealInitial();
if (!success) {
System.out.println("Error. Out of cards.");
} else {
System.out.println("-- Initial --");
automator.printHandsAndScore();
ArrayList<Integer> blackjacks = automator.getBlackJacks();
if (blackjacks.size() > 0) {
System.out.print("Blackjack at ");
for (int i : blackjacks) {
System.out.print(i + ", ");
}
System.out.println("");
} else {
success = automator.playAllHands();
if (!success) {
System.out.println("Error. Out of cards.");
} else {
System.out.println("\n-- Completed Game --");
automator.printHandsAndScore();
ArrayList<Integer> winners = automator.getWinners();
if (winners.size() > 0) {
System.out.print("Winners: ");
for (int i : winners) {
System.out.print(i + ", ");
}
System.out.println("");
} else {
System.out.println("Draw. All players have busted.");
}
}
}
}
}