Code Samples

A sample Blackjack project to show off C++:

Casino.h:

// Casino.h
// Clay Foye, August 2022
// Define the Casino namespace
// see the README

#pragma once
#include <bits/stdc++.h>
#include <cstring>

namespace Casino // casino namespace declaration
{

    using namespace std;

    const int deck_size = 52; // decksize
    const int max_hand_size = 22;

    // Suit enumeration (scoped):
    enum class Suit
    {
        Hearts,
        Diamonds,
        Spades,
        Clubs
    };
    // Cast to string:
    inline const string suit_to_string(Suit suit) {
        switch(suit) {
            case Suit::Hearts:
                return "Hearts";
            case Suit::Diamonds:
                return "Diamonds";
            case Suit::Spades:
                return "Spades";
            case Suit::Clubs:
                return "Clubs";
            default:
                return "Unknown Suit";
            }
    }
    
    // Card strut
    struct CARD
    {
        Suit suit;  // the suit of a card
        string name; // the full name of a card
        int type;  // 2-14: the integer representation of card name
        int value; // 1-11: the actual blackjack value of a card
        int index;  // the index of a card in the deck
        bool activated_ace = false; // An Ace worth 11?
    };

    // Deck class
    class Deck
    {
        public:
            CARD draw_card(); // draw a card
            inline void reshuffle() { the_deck.reset(); }
            inline void print_deck() { cout << the_deck << '\n'; }

        private:
            // private functions
            void get_card_name(CARD &card);
            void get_card_suit(CARD &card);
            void get_card_value(CARD &card);
            int draw_card_helper();
            inline void get_card_type(CARD &card) 
                 { card.type = (card.index % 13) + 2; }
            inline void randomize_index() { randint = rand() % 51; }

            // Vars
            bitset<deck_size> the_deck;
            int randint;
    };

    // Person class: can be used as a dealer or as a player
    class Person
    {
        public:
            inline void add_card(CARD& card) { hand.push_back(card); }
            inline void flush_hand() {
                hand_value = 0;
                hand.clear();
            }
            void print_hand();
            void bjack_eval();
            inline int get_hand_value() { return hand_value; }

        private:
            vector<CARD> hand;
            int hand_value =0;
    };
}

deck.cpp:

// Deck class implementation

#include "../include/casino.h"
#include <bits/stdc++.h>
#include <cstring>

using namespace Casino;
using namespace std;

// Assign the suit to a card (assume card_index exists)
void Deck::get_card_suit(CARD &card)
{
    if (card.index < 13)
    {
        card.suit = Suit::Hearts;
        return;
    }
    if (card.index < 26)
    {
        card.suit = Suit::Diamonds;
        return;
    }
    if (card.index < 39)
    {
        card.suit = Suit::Spades;
        return;
    }
    card.suit = Suit::Clubs;
}

// Assign the blackjack value to a card (assume card_type exists)
void Deck::get_card_value(CARD &card)
{
    card.value = card.type; // default
    if (card.type > 10 && card.type < 14) //face cards
    {
        card.value = 10;
    }
    if (card.type == 14) // aces
    {
        card.activated_ace = true;
        card.value = 11;
    }
}

// Assign the name to a card (assume type and suit exist)
void Deck::get_card_name(CARD &card)
{
    switch (card.type)
    {
    case 14:
        card.name = "Ace of " + suit_to_string(card.suit);
        break;
    case 13:
        card.name = "King of " + suit_to_string(card.suit);
        break;
    case 12:
        card.name = "Queen of " + suit_to_string(card.suit);
        break;
    case 11:
        card.name = "Jack of " + suit_to_string(card.suit);
        break;
    default:
        card.name = to_string(card.type) + " of " + suit_to_string(card.suit);
        break;
    }
}

// Recursive to find a valid card
int Deck::draw_card_helper()
{
    if (the_deck[randint] == 0)
    {
        the_deck[randint] = 1;
        return randint;
    }
    else
    {
        randint = (randint + 1) % deck_size;
        return draw_card_helper();
    }
}


CARD Deck::draw_card() {
    // Card to return:
    CARD card;

    // get the card index:
    Deck::randomize_index();
    card.index = draw_card_helper();

    // get the card type:
    Deck::get_card_type(card);

    // get the card suit:
    Deck::get_card_suit(card);

    // get the card name:
    Deck::get_card_name(card);

    // get blackjack value: (can expand this out to different games eventually)
    Deck::get_card_value(card);

    // return the card
    return card;
}

person.cpp:

// Person class implementation

#include "../include/casino.h"
#include <cstring>

using namespace Casino;
using namespace std;

void Person::print_hand() {
    for (CARD c : hand){
        cout << c.name + '\n';
    }
    cout << '\n';
}

void Person::bjack_eval() {
    // lambda to sum a card value
    auto card_count = [](int sum, CARD c) { return sum + c.value; };

    // accumulate value
    int total = std::accumulate(hand.begin(), hand.end(), 0, card_count);

    // Handle aces
    if (total > 21) {
        // find an activated ace:
        auto result = find_if(hand.begin(), hand.end(), [](CARD& c) 
                                { return c.activated_ace; });
        if (result != hand.end()) {
            auto pos = distance(hand.begin(), result);
            hand[pos].value = 1;
            hand[pos].activated_ace = false;
        }
        total = std::accumulate(hand.begin(), hand.end(), 0, card_count);
    }
    hand_value = total;
}

game.cpp:

// Run the blackjack game!
#include "../include/casino.h"
#include <cstring>

#include <chrono>
#include <thread>

using namespace Casino;
using namespace std;

// Let the player draw cards
void player_draw(Deck& deck, Person& player, CARD& c) {
    string answer = "";

    c = deck.draw_card();
    player.add_card(c);
    cout << "You draw: " + c.name + '\n';
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    c = deck.draw_card();
    player.add_card(c);
    cout << "You draw: " + c.name + '\n';
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    // Player Hand:
    player.bjack_eval();
    cout << "You show " + to_string(player.get_hand_value()) + '\n';

    while (player.get_hand_value() < 21)
    {
        cout << "Hit or Stand? (h/s)\n";
        getline(cin, answer);
        if (answer.compare("h") == 0)
        {
            c = deck.draw_card();
            player.add_card(c);
            cout << "You draw: " + c.name + '\n';
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            player.bjack_eval();
            cout << "You show " + to_string(player.get_hand_value()) + '\n';
        }
        else if (answer.compare("s") == 0)
        {
            break;
        }
        else
        {
            cout << "Please type 'h' or 's'.\n";
        }
        player.bjack_eval();
    }
}

// Draw the dealer's inital hand
void dealer_initial_draw(Deck& deck, Person& dealer, CARD& c) {
    dealer.add_card(c);
    cout << "Dealer draws: " + c.name + '\n';
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    dealer.bjack_eval();
    c = deck.draw_card();
    dealer.add_card(c);
    cout << "Dealer draws a card face-down.\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    // Dealer hand:
    cout << "Dealer shows " + to_string(dealer.get_hand_value()) + '\n';
    dealer.bjack_eval();
}

// Draw out the dealer at the end of a hand
void draw_out_dealer(Deck& deck, Person& dealer, CARD& c) {
    while (dealer.get_hand_value() < 17)
    {
        c = deck.draw_card();
        dealer.add_card(c);
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        cout << "Dealer draws: " + c.name + '\n';
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        cout << "Dealer hand:\n\n";
        dealer.print_hand();
        std::this_thread::sleep_for(std::chrono::milliseconds(1500));
        dealer.bjack_eval();
        cout << "Dealer shows: " + to_string(dealer.get_hand_value()) + '\n';
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

    if (dealer.get_hand_value() > 21)
    {
        cout << "Dealer busts!\n";
        return;
    }
}

// Check for a win/loss using player and dealer hand values
void check_win(Person& player, Person& dealer) {
    // Check for win/loss conditions
    if (dealer.get_hand_value() > player.get_hand_value())
    {
        cout << "Dealer wins!\n";
        return;
    }
    else if (dealer.get_hand_value() == player.get_hand_value())
    {
        cout << "Push!\n";
        return;
    }
    else if (dealer.get_hand_value() < player.get_hand_value())
    {
        cout << "You win!\n";
        return;
    }
}

// A hand of blackjack
void blackjack(Deck& deck, Person& player, Person& dealer) {

    // Dealer draws
    CARD c = deck.draw_card();
    dealer_initial_draw(deck, dealer, c);


    if (dealer.get_hand_value() == 21) {
        cout << "Dealer turns over " + c.name + " for Blackjack.\n";
        return;
    }

    // Draw the player
    player_draw(deck, player, c);

    // Check for Bust
    if (player.get_hand_value() > 21) {
        cout << "Bust!\n";
        return;
    }

    // Check for Blackjack
    if (player.get_hand_value() == 21) {
        cout << "Blackjack!\n";
        return;
    }

    // Draw out the dealer
    cout << "Dealer hand:\n\n";
    dealer.print_hand();
    cout << "Dealer shows: " + to_string(dealer.get_hand_value()) + '\n';

    if (dealer.get_hand_value() > player.get_hand_value()) {
        cout << "Dealer wins!\n";
        return;
    }

    draw_out_dealer(deck, dealer, c);

    // Check for a win or loss
    check_win(player, dealer);
}

int main(int argc, char const *argv[])
{
    // Seed
    srand(time(NULL));

    // Store inputs
    string answer = "";

    // Deck, Player, and Dealer
    Deck deck;
    Person player, dealer;

    // Main Execution Loop
    while (true) {
        // Ask to play:
        cout << "Want to play Blackjack? (y/n)\n";
        // Get answer
        getline(cin, answer);
        // Play the game
        if (answer.compare("y") == 0){
            blackjack(deck, player, dealer);
            cout << "Good Game!\n\n";
            deck.reshuffle();
            player.flush_hand();
            dealer.flush_hand();
        }
        // Leave execution
        else if (answer.compare("n") == 0)
        {
            cout << "Goodbye!\n";
            break;
        }
        else
        {   // handle unknown input
            cout << "please type 'y' or 'n' \n";
        }
    }
    return 0;
}

Some Unit Tests:

draw_deck.cpp:

// Unit test the Deck class, CARD struct, and card-drawing functionality

#include "../include/casino.h"

using namespace Casino;
using namespace std;

// draw a card, print a name
int main(int argc, char const *argv[])
{
    srand(time(NULL));
    Deck deck;
    

    int i = 0;
    int j = 3;
    while (j < 15) {
        cout << "Drawing " + to_string(j) + "s: \n";
        while (i < 52)
        {
            CARD card = deck.draw_card();
            if (card.type == j)
            {
                cout << "Card Num: " + to_string(i + 1) + ":    " + card.name << '\n';
            }
            i++;
        }
        deck.reshuffle();
        i = 0;
        j = j + 1;
    }
}

test_hand.cpp:

// Unit Test the Person class and the hand functionalities.

#include "../include/casino.h"

using namespace Casino;
using namespace std;

int main(int argc, char const *argv[])
{

    // seed
    srand(time(NULL));

    // deck and player
    Deck deck;
    Person player;

    int i = 0;
    
    // 64 games of Blackjack
    while (i < 64) {
        // Draw until bust or blackjack
        while (player.get_hand_value() < 21) {
            cout << "Drawing card!\n";
            CARD c = deck.draw_card();
            player.add_card(c);
            player.bjack_eval();
        }   

        (player.get_hand_value() == 21) ? cout << "BLACKJACK!\n" : cout << "" ;

        // Print the hand:
        cout << "Printing Hand!\n";
        player.print_hand();

        // Print Hand value:
        cout << "Hand value: " + to_string(player.get_hand_value()) + '\n';

        cout << "Flushing hand and reshuffling deck . . .\n\n";
        player.flush_hand();
        deck.reshuffle();
        i++;
    }
    return 0;
}