A Slot Machine using ASCII Art

As explained in Chapter 12 of our book, Learning C++, the idea of this exercise is to develop a Las Vegas-style slot machine game. Slot machines allow the player to press a button and get 3 or more images. The goal is to be lucky enough to get identical images in identical colors. Since our code snippets throughout this book are console based, we will be using ASCII art images. For simplicity, the images are ones from a deck of cards, which creates a somewhat new game that combines a cards deck game and a slot machine.

What is ASCII art

ASCII art is a graphic design technique that uses printable characters from the ASCII standard to create images and designs. We discussed ASCII in Chapter 7. In a nutshell, ASCII art offers an alternative to drawing an image with lines and shapes. In ASCII art, you build the image by arranging ASCII characters in a way that the different characters and symbols take a form that resembles the subject you want to depict. Essentially, the ASCII characters serve as the ‘pixels’ of the artwork.

Our Program

You can see our program on our YouTube channel. Here is how it looks. Here is the source code of our program, and how it works.

The Source Code

#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <vector>
#undef _WIN32
#ifdef _WIN32
#include <conio.h>
#else
#include <termios.h>
#include <unistd.h>
#endif

#ifdef _WIN32
#define CLEAR_SCREEN system("cls")
#else
#define CLEAR_SCREEN system("clear")
#endif

enum class Color
{
    DEFAULT,
    RED,
    GREEN,
    BLUE,
    YELLOW,
    MAGENTA,
    CYAN
};

struct Pixel
{
    char character;
    Color color;
};

void setTextColor(Color color)
{
    switch (color)
    {
        case Color::DEFAULT:
            std::cout << "\033[0m";
            break;
        case Color::RED:
            std::cout << "\033[31m";
            break;
        case Color::GREEN:
            std::cout << "\033[32m";
            break;
        case Color::BLUE:
            std::cout << "\033[34m";
            break;
        case Color::YELLOW:
            std::cout << "\033[33m";
            break;
        case Color::MAGENTA:
            std::cout << "\033[35m";
            break;
        case Color::CYAN:
            std::cout << "\033[36m";
            break;
    }
}

void displayMatrix(const std::vector<std::vector<Pixel>>& matrix)
{
    for (const auto& row : matrix)
    {
        for (const Pixel& pixel : row)
        {
            setTextColor(pixel.color);
            std::cout << pixel.character;
        }

        std::cout << std::endl;
    }

    setTextColor(Color::DEFAULT);
}

std::vector<std::string> generateRandomImage()
{
    // #A

    std::vector<std::vector<std::string>> images = 
    {
        {" _______ ", "|A      |", "|       |", "|   o   |", "|       |",
         "|_______|"},
        {" _______ ", "|2      |", "|   o   |", "|       |", "|   o   |",
         "|_______|"},
        {" _______ ", "|3      |", "|   o   |", "|   o   |", "|   o   |",
         "|_______|"},
        {" _______ ", "|4      |", "| o   o |", "|       |", "| o   o |",
         "|_______|"},
        {" _______ ", "|5      |", "| o   o |", "|   o   |", "| o   o |",
         "|_______|"},
        {" _______ ", "|6      |", "| o   o |", "| o   o |", "| o   o |",
         "|_______|"},
        {" _______ ", "|7      |", "| o o o |", "|       |", "| o o o |",
         "|_______|"},
        {" _______ ", "|8      |", "| o o o |", "| o   o |", "| o o o |",
         "|_______|"},
        {" _______ ", "|9      |", "| o o o |", "| o o o |", "| o o o |",
         "|_______|"},
        {" _______ ", "|10     |", "| o o o |", "|o o o o|", "| o o o |",
         "|_______|"},
        {" _______ ", "|J      |", "|   o   |", "|   o   |", "| o   o |",
         "|_______|"},
        {" _______ ", "|Q      |", "|   o   |", "| o o o |", "| o   o |",
         "|_______|"},
        {" _______ ", "|K      |", "| o   o |", "| o o o |", "| o   o |",
         "|_______|"},
        {" _______ ", "|A      |", "|   /\\ |", "|  /  \\|", "| /____\|",
         "|_______|"},
        {" _______ ", "|2      |", "| /\\ /\|", "| \\/ \\|", "|       |",
         "|_______|"},
        {" _______ ", "|3      |", "|   /\\ |", "|       |", "|  \\/  |",
         "|_______|"},
        {" _______ ", "|4      |", "| /\\  /|", "|       |", "|\\/  \\|",
         "|_______|"},
        {" _______ ", "|5      |", "| /\\  /|", "|   /\\ |", "|\\/  \\|",
         "|_______|"},
        {" _______ ", "|6      |", "| /\\  /|", "| /\\  /|", "|\\/  \\|",
         "|_______|"},
        {" _______ ", "|7      |", "| /\\ /\|", "|       |", "|  /\\  |",
         "|_______|"},
        {" _______ ", "|8      |", "| /\\ /\|", "| /  \\ |", "|  \\/  |",
         "|_______|"},
        {" _______ ", "|9      |", "| /\\ /\|", "|  /\\  |", "|  \\/  |",
         "|_______|"},
        {" _______ ", "|10     |", "|  /\\  |", "| /  \\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|J      |", "|   /\\ |", "|  /  \\|", "|/____\\|",
         "|_______|"},
        {" _______ ", "|Q      |", "|   /\\ |", "|  /  \\|", "|/    \\|",
         "|_______|"},
        {" _______ ", "|K      |", "|   /\\ |", "|  /  \\|", "|/____\\|",
         "|_______|"},
        {" _______ ", "|A      |", "|  /\\  |", "| /__\\ |", "|/    \\|",
         "|_______|"},
        {" _______ ", "|2      |", "|  /\\  |", "| /_\\  |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|3      |", "|  /\\  |", "| \\_/  |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|4      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|5      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|6      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|7      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|8      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|9      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|10     |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|J      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|Q      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|K      |", "|  /\\  |", "| //_\\ |", "|/____\\|",
         "|_______|"},
        {" _______ ", "|A      |", "|  _    |", "| | |   |", "| |_|   |",
         "|_______|"},
        {" _______ ", "|2      |", "|   _   |", "|  |_)  |", "|   /   |",
         "|_______|"},
        {" _______ ", "|3      |", "|   __  |", "|  |_ \\|", "|____/\\|",
         "|_______|"},
        {" _______ ", "|4      |", "|  |_ _||", "|   |   |", "|   |   |",
         "|_______|"},
        {" _______ ", "|5      |", "|  |__  |", "|     | |", "|  |__| |",
         "|_______|"},
        {" _______ ", "|6      |", "|  |__  |", "|  |__| |", "|  |__| |",
         "|_______|"},
        {" _______ ", "|7      |", "| |___  |", "|    / /|", "|   / / |",
         "|_______|"},
        {" _______ ", "|8      |", "|  /\\  |", "| /  \\ |", "| \\  / |",
         "|_______|"},
        {" _______ ", "|9      |", "|  /\\  |", "| |__|  |", "|   /   |",
         "|_______|"},
        {" _______ ", "|10     |", "|  /\\  |", "| |__)  |", "|____   |",
         "|_______|"},
        {" _______ ", "|J      |", "|    /\\|", "|   / / |", "|  / /  |",
         "|_/_____|"},
        {" _______ ", "|Q      |", "|    /\\|", "|   /  \|", "|  |\\__|",
         "|_/_____|"},
        {" _______ ", "|K      |", "|   \\_/|", "|   / \\|", "|  |   \|",
         "|_/_____|"}};

    std::random_device rd;
    std::mt19937 rng(rd());
    std::shuffle(images.begin(), images.end(), rng);

    std::vector<std::string> selectedImages;

    int randomIndex = rand() % images.size();
    const std::vector<std::string>& image = images[randomIndex];
    for (const std::string& line : image)
    {
        selectedImages.push_back(line);
    }
    images.erase(images.begin() + randomIndex);

    return selectedImages;
}

std::vector<std::vector<Pixel>>
composeCombinedImage(const std::vector<std::string>& image1,
                     const std::vector<std::string>& image2,
                     const std::vector<std::string>& image3, Color color1,
                     Color color2, Color color3)
{
    // #B
    int maxLines = std::max({image1.size(), image2.size(), image3.size()});

    // #C
    int maxWidth =
        std::max({image1[0].size(), image2[0].size(), image3[0].size()});

    std::vector<std::vector<Pixel>> combinedImage(maxLines);

    // #D
    for (int i = 0; i < image1.size(); ++i)
    {
        for (char c : image1[i])
        {
            combinedImage[i].push_back({c, color1});
        }

        // #E
        int spacesToAdd = maxWidth - image1[i].size();
        for (int j = 0; j < spacesToAdd; ++j)
        {
            combinedImage[i].push_back({' ', Color::DEFAULT});
        }
    }

    // #F
    for (int i = image1.size(); i < maxLines; ++i)
    {
        for (int j = 0; j < maxWidth; ++j)
        {
            combinedImage[i].push_back({' ', Color::DEFAULT});
        }
    }

    // #G
    for (int i = 0; i < image2.size(); ++i)
    {
        for (char c : image2[i])
        {
            combinedImage[i].push_back({c, color2});
        }

        // #H
        int spacesToAdd = maxWidth - image2[i].size();
        for (int j = 0; j < spacesToAdd; ++j)
        {
            combinedImage[i].push_back({' ', Color::DEFAULT});
        }
    }

    // #I
    for (int i = image2.size(); i < maxLines; ++i)
    {
        for (int j = 0; j < maxWidth; ++j)
        {
            combinedImage[i].push_back({' ', Color::DEFAULT});
        }
    }

    // #J
    for (int i = 0; i < image3.size(); ++i)
    {
        for (char c : image3[i])
        {
            combinedImage[i].push_back({c, color3});
        }

        // #K
        int spacesToAdd = maxWidth - image3[i].size();
        for (int j = 0; j < spacesToAdd; ++j)
        {
            combinedImage[i].push_back({' ', Color::DEFAULT});
        }
    }

    return combinedImage;
}

bool checkWin(const std::vector<std::string>& image1,
              const std::vector<std::string>& image2,
              const std::vector<std::string>& image3, Color color1,
              Color color2, Color color3)
{
    return (image1 == image2 && image2 == image3 && color1 == color2 &&
            color2 == color3);
}

int main()
{
    srand(static_cast<unsigned>(time(0)));

    std::cout << "Welcome to the Slot Machine Game!" << std::endl;
    std::cout << "Press any key to start..." << std::endl;

    while (true)
    {
        _getch();

        CLEAR_SCREEN;

        // #L
        std::vector<std::string> image1 = generateRandomImage();
        std::vector<std::string> image2 = generateRandomImage();
        std::vector<std::string> image3 = generateRandomImage();

        // #M
        Color color1 =
            static_cast<Color>(rand() % static_cast<int>(Color::CYAN) + 1);
        Color color2 =
            static_cast<Color>(rand() % static_cast<int>(Color::CYAN) + 1);
        Color color3 =
            static_cast<Color>(rand() % static_cast<int>(Color::CYAN) + 1);

        // #N
        std::vector<std::vector<Pixel>> combinedImage = composeCombinedImage(
            image1, image2, image3, color1, color2, color3);

        // #O
        displayMatrix(combinedImage);

        // #P
        if (checkWin(image1, image2, image3, color1, color2, color3))
        {
            std::cout << "Congratulations! You win!" << std::endl;
        }
        else
        {
            std::cout << "Sorry, better luck next time!" << std::endl;
        }

        std::cout << std::endl;
    }

    return 0;
}
Here are the code annotations:


#A Array of ASCII art images
#B Determine the maximum number of lines among the three images
#C Determine the maximum width among the three images
#D Add pixels from image1
#E Add spaces to match the maximum width
#F Add empty pixels to align with image2 and image3
#G Add pixels from image2
#H Add spaces to match the maximum width
#I Add empty pixels to align with image3
#J Add pixels from image3
#K Add spaces to match the maximum width
#L Generate three random images
#M Generate three random colors
#N Compose the combined image
#O Display the combined image
#P Check if the user wins

Unknown's avatar

About Michael Haephrati מיכאל האפרתי

Michael Haephrati is a music composer, an inventor and an expert specializes in software development and information security, who has built a unique perspective which combines technology and the end user experience. Author of Learning C++ https://www.manning.com/books/learning-c-plus-plus
This entry was posted in Code Snippets and tagged , , , , , , , , . Bookmark the permalink.

Leave a comment