// BLACKJACK: Author: David Henke // converted to C++ /* Features to add: * a. neater display formats * b. graphics (color for card images) * c. emulate players mode to play n games with different betting * and playing styles (simulation) * d. handle n decks, inform player of reshuffle * e. handle: No more cards in deck */ #include#include #include #include #include #include typedef char BOOLEAN; const TRUE = 1; const FALSE = 0; const ERROR = -1; const NORMAL = 0; const MAX_HANDS_SIM = 1000000000; const WORDSIZE = 32; const MAX_STRING = 256; const NUM_COUNTS = 22; const NUM_CARDS = 52; const NUM_SUITS = 4; const NUM_DENOMINATIONS = 13; const CLUB = 0; const DIAMOND = 1; const HEART = 2; const SPADE = 3; const MAX_CLUB = 12; const MAX_DIAMOND = 25; const MAX_HEART = 38; const MAX_SPADE = 51; const DISPLAY_DOWN = 0; const DISPLAY_UP = 1; const MAX_CARDS_IN_HAND = 12; const MIN_TEN_COUNT = 10; const MAX_CARDS_PLAYED = 44; const MAX_HANDS = 4; const TWENTY_ONE = 21; const SEVENTEEN = 17; const ACES_TEN = 10; const SHOW_DOWN_INDEX = 13; const FIRST = 0; const SECOND = 1; const ACE = 0; const TWO = 1; const THREE = 2; const FOUR = 3; const FIVE = 4; const SIX = 5; const SEVEN = 6; const EIGHT = 7; const NINE = 8; const TEN = 9; const JACK = 10; const QUEEN = 11; const KING = 12; // globals for play control BOOLEAN debug = FALSE; BOOLEAN check_rules; BOOLEAN interactive; BOOLEAN double_all; int num_hands; // tables for rules to play by BOOLEAN split_table[NUM_DENOMINATIONS][NUM_DENOMINATIONS] = { // A 2 3 4 5 6 7 8 9 10 J Q K Dealer hole card {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // A always split {0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 2 split 4-7 {0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 3 split 4-7 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 4 never split {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 5 never split {0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 6 split 3-6 {0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 7 split 2-7 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 8 always split {0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0}, // 9 split 2-6, 8-9 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 10 never split {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // J never split {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Q never split {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // K never split }; BOOLEAN hard_double_table[NUM_COUNTS][NUM_DENOMINATIONS] = { // A 2 3 4 5 6 7 8 9 10 J Q K Dealer hole card // two card count, no ace {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0 never 0 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 1 never 1 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 2 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 3 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 4 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 5 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 6 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 7 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 8 never double down {0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 9 double down 3-6 {0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, // 10 double down 2-9 {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 11 double down 2-10 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 12 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 13 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 14 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 15 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 16 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 17 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 18 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 19 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 20 never double down {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 21 never double down }; BOOLEAN soft_double_table[NUM_COUNTS][NUM_DENOMINATIONS] = { // A 2 3 4 5 6 7 8 9 10 J Q K Dealer hole card // two card count, one is ace {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 1 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 2 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 3 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 4 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 5 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 6 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 7 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 8 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 9 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 10 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 11 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 12 never {0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 13 double down 5-6 {0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 14 double down 5-6 {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 15 double down 4-6 {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 16 double down 4-6 {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 17 double down 2-6 {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 18 double down 4-6 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 19 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 20 never {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 21 never }; BOOLEAN hard_hit_table[NUM_COUNTS][NUM_DENOMINATIONS] = { // A 2 3 4 5 6 7 8 9 10 J Q K Dealer hole card // card count, no ace {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 0 never happens {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 1 never happens {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 2 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 3 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 4 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 5 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 6 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 7 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 8 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 9 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 10 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 11 always hit {1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1}, // 12 hit all but 4-6 {1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1}, // 13 hit all but 2-6 {1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1}, // 14 hit all but 2-6 {1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1}, // 15 hit all but 2-6 {1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1}, // 16 hit all but 2-6 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 17 never hit {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 18 never hit {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 19 never hit {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 20 never hit {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 21 never hit }; BOOLEAN soft_hit_table[NUM_COUNTS][NUM_DENOMINATIONS] = { // A 2 3 4 5 6 7 8 9 10 J Q K Dealer hole card // two card count, soft ace {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 0 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 1 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 2 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 3 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 4 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 5 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 6 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 7 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 8 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 9 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 10 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 11 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 12 nop {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 13 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 14 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 15 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 16 always hit {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 17 always hit {1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, // 18 hit all but 2-8 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 19 never hit {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 20 never hit {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 21 never hit }; class card { public: int denomination; int suit; int count; int display(); }; class default_deck { public: static card ddeck[NUM_CARDS]; }; card default_deck::ddeck[] = { {ACE, CLUB, 1}, {TWO, CLUB, 2}, {THREE, CLUB, 3}, {FOUR, CLUB, 4}, {FIVE, CLUB, 5}, {SIX, CLUB, 6}, {SEVEN, CLUB, 7}, {EIGHT, CLUB, 8}, {NINE, CLUB, 9}, {TEN, CLUB, 10}, {JACK, CLUB, 10}, {QUEEN, CLUB, 10}, {KING, CLUB, 10}, {ACE, DIAMOND, 1}, {TWO, DIAMOND, 2}, {THREE, DIAMOND, 3}, {FOUR, DIAMOND, 4}, {FIVE, DIAMOND, 5}, {SIX, DIAMOND, 6}, {SEVEN, DIAMOND, 7}, {EIGHT, DIAMOND, 8}, {NINE, DIAMOND, 9}, {TEN, DIAMOND, 10}, {JACK, DIAMOND, 10}, {QUEEN, DIAMOND, 10}, {KING, DIAMOND, 10}, {ACE, HEART, 1}, {TWO, HEART, 2}, {THREE, HEART, 3}, {FOUR, HEART, 4}, {FIVE, HEART, 5}, {SIX, HEART, 6}, {SEVEN, HEART, 7}, {EIGHT, HEART, 8}, {NINE, HEART, 9}, {TEN, HEART, 10}, {JACK, HEART, 10}, {QUEEN, HEART, 10}, {KING, HEART, 10}, {ACE, SPADE, 1}, {TWO, SPADE, 2}, {THREE, SPADE, 3}, {FOUR, SPADE, 4}, {FIVE, SPADE, 5}, {SIX, SPADE, 6}, {SEVEN, SPADE, 7}, {EIGHT, SPADE, 8}, {NINE, SPADE, 9}, {TEN, SPADE, 10}, {JACK, SPADE, 10}, {QUEEN, SPADE, 10}, {KING, SPADE, 10} }; class deck { private: int card_indices[NUM_CARDS]; public: int deck_count; deck(); void dump(); void shuffle(unsigned long int modulus, long int &random_number, double &uniform_random_number); int deal_card(); }; class hand { public: BOOLEAN show_total; BOOLEAN aces; BOOLEAN hard_ace; BOOLEAN over; BOOLEAN play; int hand_count; int card_indices[MAX_CARDS_IN_HAND]; int card_count; void initialize(); BOOLEAN blackjack(); int count(); void deal_card(int); virtual void display() = 0; }; class dealer_hand : public hand { public: BOOLEAN first_card_down; BOOLEAN insurance(); void initialize(); void display(); }; class player_hand : public hand { public: BOOLEAN got_insurance; BOOLEAN split_aces; float bet; float insure; BOOLEAN split(int); BOOLEAN double_down(int); void initialize(); void display(); }; char *denom_array[] = { " A", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", "10", " J", " Q", " K", "XX" }; // Random number generating routines.... int clock_random() // start random number generation based on time { extern my_clock(); static int c = 0; if (c == 0) c = my_clock(); srand(c); return(c = rand()); } int my_clock() { long int c; struct tm *t; c = time(0); t = localtime(&c); return(t->tm_sec + (100 * (t->tm_min + (100 * (t->tm_hour + (100 * (t->tm_mday + (100 * (t->tm_mon + 1))))))))); } void random(unsigned long int modulus, long int &random_number, double &uniform_random_number) { // Xn+1 = (aXn + c) mod m random_number = ((524288 + 3) * (random_number)) % modulus; // Un = Xn/m uniform_random_number = (double) random_number / (double) modulus; } void get_modulus(unsigned long int &modulus) { modulus = (unsigned long int) pow(2.0, (double) (WORDSIZE - 2)); } // Interactive routines ....... BOOLEAN get_answer() { char your_answer[MAX_STRING]; BOOLEAN answer; BOOLEAN ok_answer; ok_answer = FALSE; while (ok_answer == FALSE) { cin >> your_answer; if ((your_answer[0] == 'y') || (your_answer[0] == 'Y')) { answer = TRUE; ok_answer = TRUE; } else if ((your_answer[0] == 'n') || (your_answer[0] == 'N')) { answer = FALSE; ok_answer = TRUE; } else { cout << "\n" << "Make up your mind!(Y/N)" << flush; } } return(answer); } void print_rule_violated() { cout << "\nCHECK: MIKEY SAYS YOU BROKE THE RULE." << endl; } // class deck methods.... deck::deck() { for (int i = 0; i < NUM_CARDS; i++) { card_indices[i] = i; } } void deck::dump() { for (int i = 0; i < NUM_CARDS; i++) { cout << "deck[" << i << "]:" << card_indices[i] << endl; } } void deck::shuffle(unsigned long int modulus, long int &random_number, double &uniform_random_number) { int card_count; int card_num; int temp; extern void random(unsigned long int, long int &, double &); for (card_count = NUM_CARDS - 1; card_count > 0; card_count--) { /* generate a random number U, uniformly distributed between 0 and 1 */ random(modulus, random_number, uniform_random_number); /* get card_num to lie between 0 and 51 */ card_num = (int) (card_count * uniform_random_number); /* exchange card_indices[card_num] with card_indices[card_count] */ temp = card_indices[card_num]; card_indices[card_num] = card_indices[card_count]; card_indices[card_count] = temp; } deck_count = -1; } int deck::deal_card() { deck_count++; if (deck_count >= NUM_CARDS) { // shuffle dead cards and finish this game // for now, recycle cards at beginning of deck to finish this hand if (debug) { cout << "No more cards in this deck, recycling." << endl; } return(card_indices[deck_count % NUM_CARDS]); } return(card_indices[deck_count]); } // class card methods() int card::display() { return(NORMAL); } // class hand methods void hand::initialize() { show_total = FALSE; card_count = 0; play = TRUE; over = FALSE; } int hand::count() { BOOLEAN hard_ace_ok = TRUE; aces = FALSE; hard_ace = FALSE; hand_count = 0; for (int i = 0; i < card_count; i++) { hand_count += default_deck::ddeck[card_indices[i]].count; if (default_deck::ddeck[card_indices[i]].denomination == ACE) { aces = TRUE; } if (aces && !hard_ace && hard_ace_ok) { if ((hand_count + ACES_TEN) <= TWENTY_ONE) { hand_count += ACES_TEN; hard_ace = TRUE; } } if ((hand_count > TWENTY_ONE) && hard_ace) { hand_count -= ACES_TEN; hard_ace = FALSE; // no more hard aces hard_ace_ok = FALSE; } } // test for over and return the count if (hand_count > TWENTY_ONE) { over = TRUE; } return(hand_count); } void hand::deal_card(int new_card) { card_indices[card_count] = new_card; card_count++; } BOOLEAN hand::blackjack() { if (default_deck::ddeck[card_indices[FIRST]].denomination == ACE) { if (default_deck::ddeck[card_indices[SECOND]].count == 10) { return(TRUE); } } else if (default_deck::ddeck[card_indices[SECOND]].denomination == ACE) { if (default_deck::ddeck[card_indices[FIRST]].count == 10) { return(TRUE); } } return(FALSE); } // sub class dealer_hand methods void dealer_hand::initialize() { hand::initialize(); first_card_down = TRUE; } BOOLEAN dealer_hand::insurance() { if (default_deck::ddeck[card_indices[SECOND]].denomination == ACE) { cout << "\n" << "Insurance?(Y/N)" << flush; return(get_answer()); } else { return(FALSE); } } void dealer_hand::display() { int index; cout << "\nDealers hand: " << flush; for (int i = 0; i < card_count; i++) { if ((first_card_down == TRUE) && (i == 0)) { index = SHOW_DOWN_INDEX; } else { index = default_deck::ddeck[card_indices[i]].denomination; } cout << " " << denom_array[index] << flush; } if (show_total == TRUE) { cout << " total: " << count() << flush; } } // sub class player_hand methods void player_hand::initialize() { hand::initialize(); got_insurance = FALSE; split_aces = FALSE; } BOOLEAN player_hand::split(int dealer_up_card) { if (default_deck::ddeck[card_indices[FIRST]].denomination == default_deck::ddeck[card_indices[SECOND]].denomination) { if (interactive) { cout << "\n" << "Split?(Y/N)" << flush; BOOLEAN answer = get_answer(); if (check_rules) { BOOLEAN rule_answer = (BOOLEAN) split_table [default_deck::ddeck[card_indices[FIRST]].denomination] [dealer_up_card]; if (answer != rule_answer) { print_rule_violated(); } } return(answer); } else { return((BOOLEAN) split_table [default_deck::ddeck[card_indices[FIRST]].denomination] [dealer_up_card]); } } else { return(FALSE); } } BOOLEAN player_hand::double_down(int dealer_up_card) { int card1_plus_card2; BOOLEAN can_ask = FALSE; if (double_all) { can_ask = TRUE; } else { card1_plus_card2 = default_deck::ddeck[card_indices[FIRST]].count + default_deck::ddeck[card_indices[SECOND]].count; if ((card1_plus_card2 == 10) || (card1_plus_card2 == 11)) { can_ask = TRUE; } } if (can_ask) { if (interactive) { cout << "\n" << "Double Down?(Y/N)" << flush; BOOLEAN answer = get_answer(); if (check_rules) { BOOLEAN rule_answer; if (aces && hard_ace) { // means hand has an ace which could be softened rule_answer = (BOOLEAN) soft_double_table[hand_count] [dealer_up_card]; } else { rule_answer = (BOOLEAN) hard_double_table[hand_count] [dealer_up_card]; } if (answer != rule_answer) { print_rule_violated(); } } return(answer); } else { if (aces && hard_ace) { // means hand has an ace which could be softened return((BOOLEAN) soft_double_table[hand_count][dealer_up_card]); } else { return((BOOLEAN) hard_double_table[hand_count][dealer_up_card]); } } } else { return(FALSE); } } void player_hand::display() { int index; cout << "\n Your hand: " << flush; for (int i = 0; i < card_count; i++) { index = default_deck::ddeck[card_indices[i]].denomination; cout << " " << denom_array[index] << flush; } if (show_total == TRUE) { cout << " total: " << count() << flush; } } // Playing routines .... int deal(deck &card_deck, hand &this_hand) { int new_card; if ((new_card = card_deck.deal_card()) == ERROR) { return(ERROR); } this_hand.deal_card(new_card); return(NORMAL); } void do_split(deck &card_deck, player_hand &hand1, player_hand &hand2, int &num_user_hands) { // reset the number of cards in split hand to 1 hand1.card_count = 1; hand1.count(); // initialize the new hand and take card from card 2 of split hand hand2.initialize(); hand2.card_indices[FIRST] = hand1.card_indices[SECOND]; hand2.card_count = 1; hand2.bet = hand1.bet; hand2.count(); // check for split of aces if (default_deck::ddeck[hand1.card_indices[FIRST]].denomination == ACE) { hand1.split_aces = TRUE; hand2.split_aces = TRUE; } num_user_hands++; // deal another card to each hand deal(card_deck, hand1); deal(card_deck, hand2); } // Tallying routines .... void settle_score(float &your_totals, player_hand &your_hand, dealer_hand &dealers_hand) { if (your_hand.over) { if (interactive) { cout << "\nYou busted!" << endl; } your_totals -= your_hand.bet; } else if (dealers_hand.over) { if (interactive) { cout << "\nDealer busted!" << endl; } your_totals += your_hand.bet; } else { if (your_hand.hand_count > dealers_hand.hand_count) { if (interactive) { cout << "\nYou win." << endl; } your_totals += your_hand.bet; } else if (your_hand.hand_count < dealers_hand.hand_count) { if (interactive) { cout << "\nYou lose." << endl; } your_totals -= your_hand.bet; } else { if (your_hand.hand_count == TWENTY_ONE) { if (your_hand.blackjack()) { if (dealers_hand.blackjack()) { if (interactive) { cout << "\nPush." << endl; } } else { if (interactive) { cout << "\nYou win." << endl; } your_totals += your_hand.bet; } } } else { if (interactive) { cout << "\nPush." << endl; } } } } } void print_totals(float your_totals) { if (your_totals < 0.0) { printf("\nYou owe me $%9.2f\n", fabs(your_totals)); } else if (your_totals == 0.0) { printf ("\nWe are dead even.\n"); } else { printf("\nI owe you $%9.2f\n", your_totals); } } void print_usage() { cout << "usage: bj -i|-b numhands [-c] [-d]" << endl; cout << "usage: -i ==> interactive" << endl; cout << "usage: -b ==> batch; numhands ==> number of hands to play" << endl; cout << "usage: -c ==> optional check against playing rules" << endl; cout << "usage: -d ==> option to allow double down for any combo" << endl; } int check_inputs(int argc, char * argv[]) { check_rules = FALSE; double_all = FALSE; if ((argc == 1) || (argc > 5)) { return(ERROR); } else { if (argv[1][0] == '-') { // check for interactive versus batch if (argv[1][1] == 'i') { interactive = TRUE; if (argc > 4) { return(ERROR); } else if ((argc == 3) || (argc == 4)) { if (strcmp(&(argv[2][0]), "-c") == 0) { check_rules = TRUE; } else if (strcmp(&(argv[2][0]), "-d") == 0) { double_all = TRUE; } else { return(ERROR); } } if (argc == 4) { if (strcmp(&(argv[3][0]), "-c") == 0) { check_rules = TRUE; } else if (strcmp(&(argv[3][0]), "-d") == 0) { double_all = TRUE; } else { return(ERROR); } } } else if (argv[1][1] == 'b') { interactive = FALSE; if (argc == 2) { return(ERROR); } // get the number of hands to play if (argv[2][0] == '-') // expecting num_hands { return(ERROR); } num_hands = atoi(&(argv[2][0])); if ((num_hands < 1) || (num_hands > MAX_HANDS_SIM)) { return(ERROR); } if (argc > 5) { return(ERROR); } else if ((argc == 4) || (argc == 5)) { if (strcmp(&(argv[3][0]), "-c") == 0) { check_rules = TRUE; } else if (strcmp(&(argv[3][0]), "-d") == 0) { double_all = TRUE; } else { return(ERROR); } } if (argc == 5) { if (strcmp(&(argv[4][0]), "-c") == 0) { check_rules = TRUE; } else if (strcmp(&(argv[4][0]), "-d") == 0) { double_all = TRUE; } else { return(ERROR); } } } else { return(ERROR); } } else { return(ERROR); } } return(NORMAL); } int main (int argc, char * argv[]) { deck card_deck; dealer_hand dealers_hand; int dealer_up_card; player_hand your_hand[MAX_HANDS]; int num_user_hands; int hands_played; float your_totals; unsigned long int modulus; long int random_number; double uniform_random_number; extern void get_modulus(unsigned long int &); cout << " ******************** BLACKJACK **********************" << endl; if (check_inputs(argc, argv) == ERROR) { print_usage(); exit(-1); } get_modulus(modulus); random_number = clock_random(); card_deck.shuffle(modulus, random_number, uniform_random_number); your_totals = 0.0; hands_played = 0; // do until user terminates the game or for n hands in batch mode for (;;) { hands_played++; if (interactive) { cout << "\n************ NEW GAME *****************" << endl; cout << "\nEnter your bet (0 or less ends the game):" << flush; cin >> your_hand[0].bet; if (your_hand[0].bet <= 0.0) { // terminate the game break; } your_hand[0].insure = your_hand[0].bet / 2.0; } else { your_hand[0].bet = 1.0; your_hand[0].insure = 0.5; } // reshuffle if minimum number of cards left if (card_deck.deck_count > MAX_CARDS_PLAYED) { card_deck.shuffle(modulus, random_number, uniform_random_number); } // initialize hands num_user_hands = 1; your_hand[0].initialize(); dealers_hand.initialize(); // deal the hand (two cards apiece) deal(card_deck, your_hand[0]); deal(card_deck, dealers_hand); deal(card_deck, your_hand[0]); deal(card_deck, dealers_hand); dealer_up_card = default_deck::ddeck[dealers_hand.card_indices[SECOND]].denomination; // display original hands if (interactive) { your_hand[0].display(); dealers_hand.display(); } // count original hands your_hand[0].count(); dealers_hand.count(); // test for your Blackjack if (your_hand[0].blackjack()) { if (interactive) { cout << "\n You got blackjack." << endl; } your_hand[0].bet += your_hand[0].insure; your_hand[0].play = FALSE; } else { // test for insurance if (interactive && dealers_hand.insurance()) { your_hand[0].got_insurance = TRUE; } else { your_hand[0].got_insurance = FALSE; } } // test for dealer Blackjack if (dealers_hand.blackjack()) { if (interactive) { cout << "\n Dealer got blackjack." << endl; } dealers_hand.first_card_down = FALSE; if (interactive) { dealers_hand.display(); } your_hand[0].play = FALSE; dealers_hand.play = FALSE; } else if (interactive && your_hand[0].blackjack()) { dealers_hand.display(); } if (your_hand[0].got_insurance) { if (dealers_hand.blackjack()) { // subtract insurance from original bet your_hand[0].bet -= your_hand[0].insure; } else { // pay out insurance your_totals -= your_hand[0].insure; } } // if neither of you got blackjack, play on if (your_hand[0].play && dealers_hand.play) { // test for split if (your_hand[0].split(dealer_up_card)) { do_split(card_deck, your_hand[0], your_hand[num_user_hands], num_user_hands); if (your_hand[0].split_aces == FALSE) { if (your_hand[0].split(dealer_up_card)) { do_split(card_deck, your_hand[0], your_hand[num_user_hands], num_user_hands); if (your_hand[0].split(dealer_up_card)) { do_split(card_deck, your_hand[0], your_hand[num_user_hands], num_user_hands); } } if (your_hand[1].split(dealer_up_card)) { do_split(card_deck, your_hand[1], your_hand[num_user_hands], num_user_hands); if (your_hand[1].split(dealer_up_card)) { do_split(card_deck, your_hand[1], your_hand[num_user_hands], num_user_hands); } } if (num_user_hands > 2) { if (your_hand[2].split(dealer_up_card)) { do_split(card_deck, your_hand[2], your_hand[num_user_hands], num_user_hands); } } } } // play all the user hands for (int i = 0; i < num_user_hands; i++) { if (interactive) { if (num_user_hands > 1) { cout << "\n\nHand: " << i << flush; } else { cout << "\n" << endl; } } your_hand[i].count(); if (interactive) { your_hand[i].display(); } if (your_hand[i].split_aces == TRUE) { // you got the one card you are entitled to your_hand[i].play = FALSE; } else if (your_hand[i].double_down(dealer_up_card)) { // test for double down and play one card for you your_hand[i].bet = your_hand[i].bet * 2.0; deal(card_deck, your_hand[i]); your_hand[i].count(); if (interactive) { your_hand[i].display(); } your_hand[i].play = FALSE; } else { // play out hand normally while (your_hand[i].play) { if (interactive) { cout << "\nHit?(Y/N)" << flush; BOOLEAN answer = get_answer(); if (check_rules) { BOOLEAN rule_answer; if (your_hand[i].aces && your_hand[i].hard_ace) { rule_answer = soft_hit_table[your_hand[i].hand_count] [dealer_up_card]; } else { rule_answer = hard_hit_table[your_hand[i].hand_count] [dealer_up_card]; } if (answer != rule_answer) { print_rule_violated(); } } if (answer == TRUE) { deal(card_deck, your_hand[i]); your_hand[i].display(); your_hand[i].count(); if (your_hand[i].over) { your_hand[i].play = FALSE; } } else { your_hand[i].play = FALSE; } } else { if (your_hand[i].aces && your_hand[i].hard_ace) { your_hand[i].play = soft_hit_table[your_hand[i].hand_count] [dealer_up_card]; } else { your_hand[i].play = hard_hit_table[your_hand[i].hand_count] [dealer_up_card]; } if (your_hand[i].play) { deal(card_deck, your_hand[i]); your_hand[i].count(); if (your_hand[i].over) { your_hand[i].play = FALSE; } } } } if (interactive || debug) { your_hand[i].display(); } } } } // dealers play dealers_hand.first_card_down = FALSE; while (dealers_hand.play) { if (interactive || debug) { dealers_hand.display(); } dealers_hand.count(); if ((dealers_hand.hand_count < SEVENTEEN) || ((dealers_hand.hand_count == SEVENTEEN) && (dealers_hand.aces && dealers_hand.hard_ace))) { /* note that dealer must hit below 17 and stay at 17 or over * but he must also hit a soft 17 */ deal(card_deck, dealers_hand); } else { // dealer must stay or is busted dealers_hand.play = FALSE; } } /* end while */ // settle score for all hands played for (int i = 0; i < num_user_hands; i++) { if (interactive) { if (num_user_hands > 1) { cout << "\n\nHand: " << i << flush; } else { cout << "\n" << endl; } } settle_score(your_totals, your_hand[i], dealers_hand); } // print running tab if (interactive) { print_totals(your_totals); } else { if (hands_played == num_hands) { break; } } } // end for loop if (!interactive) { print_totals(your_totals); } exit(0); } // end main