P-03

C++ Fundamentals Programming Showcase

A collection of C++ programs developed during my programming course, demonstrating various concepts including elementary data types, control structures, functions, arrays, strings, fundamental algorithms, computer organization, memory management, game logic, mathematical computations, data structures, and user interaction. Each program showcases different aspects of C++ programming fundamentals.

Role
Programmer
Date
Fall 2025
Language
C++
C++ Games Terminal
> 
main.cpp
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include "conversions.hpp"
#include "blackjack.hpp"
#include "maya_numbers.hpp"
#include "factors.hpp"
#include "numbers.hpp"

using namespace std;

string inputCheck(string& input) {
    while(true) {
        if( (input == "exit" || input == "EXIT") ||
            ((input.size() == 1) && (input[0] == '1' || input[0] == '2' || 
             input[0] == '3' || input[0] == '4' || input[0] == '5' || input[0] == '6')))
        {
            return input;
        }
        cin.clear();
        cin.ignore(10000, '\n');
        cout << '\n' << "Invalid Input. Please enter either 1, 2, 3, 4, 5, 6 or exit: ";
        cin >> input;
    }
}

int main() {
    string input;
    
    cout << "Hello! My name is Elijah and I completed several assignments in C++." << '\n';
    cout << "I included them all here in one file for you to enjoy!" << '\n' << '\n';
    
    do {
        cout << "Please input a number from the list of options, or type exit to quit." << '\n' << '\n'
             << "MENU" << '\n'
             << "--------" << '\n' << '\n';
        
        cout << "1) Circle Area" << '\n' << '\n'
             << "2) Distance Converter" << '\n' << '\n'
             << "3) Factors of Numbers" << '\n' << '\n'
             << "4) Convert Integer Numbers to Strings" << '\n' << '\n'
             << "5) Mayan Number Game" << '\n' << '\n'
             << "6) Blackjack" << '\n' << '\n';
        
        cout << "Please select a game to play: ";
        cin >> input;
        input = inputCheck(input);
        cout << endl;
        
        if (input == "1") circleRadius();
        else if (input == "2") distance();
        else if (input == "3") factors();
        else if (input == "4") numbers();
        else if (input == "5") maya_numbers();
        else if (input == "6") playBlackJackGame();
        else if ((input == "exit" || input == "EXIT")) {
            cout << '\n' << "Thank you for checking out my work!" << '\n';
            return 0;
        }
    } while((input!= "exit") || input != "EXIT");
    
    cout << '\n' << "Thank you for checking out my work!" << '\n';
    return 0;
}
Blackjack Game
struct Card // a struct is a way to group related information together
{
    string suit;
    string name;
    int rank;
    int value;

    Card() // a constructor is having the form come with pre-filled boxes so pages arent blank
    {
            suit = "";
            name = "";
            rank = 0;
            value = 0;
    }
};

using namespace std;
// Creates new deck of cards (ordered)
vector<Card> getNewDeck() 
{
    vector<Card> deck; // new vector of called deck of Card objects
    string suits[] = {"Spades", "Hearts", "Diamonds", "Clubs"}; // array of suits
    char suitInitials[] = {'S', 'H', 'D', 'C'}; // array of suit initials


    for(int suit = 0; suit < 4; suit++) // loops through each suit
    {
        for(int rank = 1; rank <= 13; rank++) // loops through each rank of card
        {
            Card newCard; // creates a new card
            newCard.suit = suits[suit]; // assigns it the corresponding suit
            newCard.rank = rank; // assigns it the corresponding rank

            // Adds rank to cards name
            if (rank == 1) newCard.name = "A"; // case for ace
            else if (rank == 11) newCard.name = "J"; // case for jack
            else if (rank == 12) newCard.name = "Q"; // case for queen
            else if (rank == 13) newCard.name = "K"; // case for king
            else newCard.name = to_string(rank); // converts integer r into a string to store in text
            
            newCard.name += suitInitials[suit]; //assigns suit initial to name after the rank

            if(rank == 1) newCard.value = 11; // gives aces a value of 11
            else if (rank >= 11 && rank <= 13) newCard.value = 10; // gives face cards a value of 10
            else newCard.value = rank; // assigns other cards the value of their rank

            deck.push_back(newCard); // adds the card to the deck
        }
    }
    return deck; // returns completed deck of cards once loops are finished
}

// Prints card deck
void printDeck(const vector<Card>& deck) 
{
    for(int i = 0; i < deck.size(); i++) // prints corresponding to size of vector deck
    {
        cout << setw(3) << deck[i].name << " "; // prints their name, spaced nicely with setw
        if((i+1) % 13 == 0) cout << '\n'; // every 13th card, creates a newline
    }
}

// Randomly rearranges the cards in a deck
void shuffleDeck(vector<Card>& deck) 
{
for(int i = 0; i < deck.size(); i++) // loops through each card in the deck 
        {
            int randomIndex = rand() % deck.size(); // generates random index from 0 to last index of deck
            Card tempHolder = deck[i]; // temporary card variable to hold current card so it isnt lost during swap
            deck [i] = deck [randomIndex]; // swaps current card with the card at the random index
            deck [randomIndex] = tempHolder; // to hold card swapped with to not lose original
        }
}

// Deals one card from a deck to a hand.
void deal(vector<Card>& deck, vector<Card>& hand)
{
    // if the deck is empty, replace with a fresh shuffled deck
    if (deck.empty())
    {
        deck = getNewDeck();   // new 52-card deck
        shuffleDeck(deck);     // shuffle before dealing
    }

    Card top = deck.back(); // copy last card
    deck.pop_back(); // remove from deck
    hand.push_back(top); // add to hand
}

// Calculates the sum of each cards value in a hand.
int handValue(const vector<Card>& hand)
{
    int value = 0; // running total for hand value
    int aceCount = 0; // tracks how many aces are in the hand
    const int bustLimit = 21; // maximum total before busting
    const int aceAdjustmentFactor = 10; // amount to reduce value when treating ace as 1 instead of 11

    for(int i = 0; i < hand.size(); i++) // loops through every card in the hand
    {
        value += hand[i].value; // adds card value to running total
        if ( hand[i].rank == 1) aceCount++; // counts aces by checking rank
    }

    while(value > bustLimit && aceCount > 0) // reduces value while over 21 and there are aces to adjust
    {
        value -= aceAdjustmentFactor; // converts one ace from 11 to 1
        aceCount--; // one less ace available for adjustment
    }

    return value; // returns best hand value without busting if possible
}

// Checks for an endgame condition.
bool winCheck(const vector<Card>& handPlayer, const vector<Card>& handDealer, const int WIN_CONDITION)
{
    if(handValue(handPlayer) == WIN_CONDITION && handValue(handDealer) == WIN_CONDITION) // checks for tie
    {
        cout << "Dealer Drew: " << handDealer[0].name << " " << handDealer[1].name << '\n' << '\n';
        cout << "Draw! Both dealer and player drew blackjack" << '\n'; 
        return true; // game is over, outcome decided
    }
   else if(handPlayer.size() > 2 && handValue(handPlayer) == WIN_CONDITION) // if player draws to 21 on their turn
    {
        cout << '\n' << "You drew to twenty-one. You win!" << '\n'; 
        return true; // game ends with player win
    }

    else if(handDealer.size() > 2 && handValue(handDealer) == WIN_CONDITION) // if dealer draws to 21 on their turn
    {
        cout << '\n' << "Dealer got twenty-one. You lose!" << '\n'; 
        return true; // game ends with dealer win
    }
        else if(handValue(handPlayer) == WIN_CONDITION && (handValue(handDealer) != WIN_CONDITION)) // checks for your blackjack
    {
        cout << "Dealer Drew: " << handDealer[0].name << " " << handDealer[1].name << '\n' << '\n';
        cout << "Blackjack! You win." << '\n'; 
        return true; // player blackjack ends game
    }
    else if(handValue(handPlayer) != WIN_CONDITION && handValue(handDealer) == WIN_CONDITION) // checks for dealers blackjack on game start
    {
        cout << "Dealer Drew: " << handDealer[0].name << " " << handDealer[1].name << '\n' << '\n';
        cout << "Dealer got a blackjack. You lose!" << '\n'; 
        return true; // dealer blackjack ends game
    }
    else if(handValue(handPlayer) > WIN_CONDITION) // if player busts on their turn
    {
    cout << "Dealer Drew: " << handDealer[0].name << " " << handDealer[1].name << '\n' << '\n';
    cout << "Bust! You lose." << '\n';
    return true; // game ends due to player bust
    }
    else if(handValue(handDealer) > WIN_CONDITION) // if dealer busts on their turn
    {
    cout << '\n' << "Dealer bust. You Win!" << '\n';
    return true; // game ends due to dealer bust
    }
    return false; // no terminal condition yet, game continues
}

// Function used to return a value used for game-to-game score tracking if an endgame is detected.
int scoreTracker(const vector<Card>& handPlayer, const vector<Card>& handDealer, const int WIN_CONDITION)
{

    if(handValue(handPlayer) == WIN_CONDITION && handValue(handDealer) == WIN_CONDITION) // checks for tie
    {
        return 0; // tie score
    }
    else if(handValue(handPlayer) == WIN_CONDITION && (handValue(handDealer) != WIN_CONDITION)) // checks for your blackjack
    {
        return 1; // player win
    }
    else if(handValue(handPlayer) != WIN_CONDITION && handValue(handDealer) == WIN_CONDITION) // checks for dealers blackjack
    {
        return -1; // dealer win
    }
    else if(handValue(handPlayer) > WIN_CONDITION)
    {
    return -1; // player busts, dealer wins
    }
    else if(handValue(handDealer) > WIN_CONDITION)
    {
    return 1; // dealer busts, player wins
    }
    else return 0; // default to tie in non-terminal case (used with winCheck)
}

// Function to draw and reveal the first card.
void firstCard(vector<Card>& deck, vector<Card>& handPlayer, vector<Card>& handDealer)
{
    deal(deck, handPlayer); // deal first card to player
    deal(deck, handDealer); // deal first card to dealer
    cout << '\n' << "Deal first card" << '\n' << "---------------" << '\n';
    cout << "Player Drew: " << handPlayer[0].name << '\n'; // show player's first card
    cout << "Dealer Drew: " << handDealer[0].name << '\n' << '\n';  // show dealer's first card
}

// Function to draw and reveal the second card.
void secondCard(vector<Card>& deck, vector<Card>& handPlayer, vector<Card>& handDealer)
{
    const string DEALER_UNKNOWN = "??"; // placeholder hides dealer's second card from player
    deal(deck, handPlayer); // deal second card to player
    deal(deck, handDealer); // deal second card to dealer
    cout << "Deal second card" << '\n' << "---------------" << '\n';
    cout << "Player Drew: " << handPlayer[0].name << " " << handPlayer[1].name << '\n'; // show both player cards
    cout << "Dealer Drew: " << handDealer[0].name << " " << DEALER_UNKNOWN << '\n';  // only reveal dealer's first card
}

// Ensures the player inputted a valid character when asked if they would like to hit OR stand.
char choiceValidation(char choice)
{
    while(cin.fail() || (choice != 'h' && choice != 's' && choice != 'H' && choice != 'S')) // repeats until valid hit/stand character
    {
        cin.clear(); // clears error state on cin
        cin.ignore(10000, '\n'); // discards remaining invalid input
        cout << "Invalid input, please enter h for hit OR s for stand: "; // prompt user again
        cin >> choice; // get new input
    }
    return choice; // return validated choice
}

// Ensures that the player inputted a valid character when asked if they would like to play a new game.
char choicePlayBlackJackValidation(char choicePlayBlackjack)
{
     while(cin.fail() || (choicePlayBlackjack != 'y' && choicePlayBlackjack != 'Y' && choicePlayBlackjack != 'n' && choicePlayBlackjack != 'N')) // repeats until valid yes/no input
    {
        cin.clear(); // clears error state on cin
        cin.ignore(10000, '\n'); // discards remaining invalid input
        cout << "Invalid input, please enter n for no OR y for yes: "; // prompt user again
        cin >> choicePlayBlackjack; // get new input
    }
    return choicePlayBlackjack; // return validated yes/no choice
}

// Gives advice to the player on hitting OR standing based on their hand and the dealers upcard
void giveAdvice(const vector<Card>& playerHand, const vector<Card>& dealerHand)
{
    int playerHandValue = handValue(playerHand); // stores played hand value as an int. Used in ace adjustment
    int dealerUpcardRank = dealerHand[0].rank; // stores rank of the dealers visible card as an int (used for bool)
    bool dealerStrong = dealerUpcardRank >= 7 || dealerUpcardRank == 1; // Dealers hand is strong if the upcard is an ace or greater than 6
    bool dealerFair = (dealerUpcardRank <= 6 && dealerUpcardRank > 3); // Dealers hand is fair if the upcard is greater than 3 or less than 7
    bool dealerWeak = dealerUpcardRank <= 3 && dealerUpcardRank > 1; // Dealers hand is poor of the upcard is 2 or 3
   
    int aceCount = 0; // tracks how many aces are in the hand
    for(int i = 0; i < playerHand.size(); i++) // loops through every card in the hand
    {
        if (playerHand[i].rank == 1) aceCount++; // counts aces by checking rank
    }

    // A softhand has specific strategy for the player. They should keep hitting until at least a total of 18.
    bool softHand = aceCount > 0;
    if(softHand)
    {
        if (playerHandValue < 18)
        {
            cout << "You should hit" << '\n' << "You have a soft hand (one or more aces), so taking another card is safe up until a total 18." << '\n';
        }
        else
        {
            cout << "You should stand" << '\n' << "You have a soft hand (one or more aces), and a hand with a value equal to or greater than 18. Standing is the best play." << '\n';
        }
    }
    // If there is no softhand, it is a hardhand. This depends on the value in the dealers upcard.
    else
    {
        if (dealerStrong) // If the dealer has a strong upcard-
        {
            if (playerHandValue < 17) // -and your card is less than 17.
            {
                cout << "You should hit." << '\n' << "The dealer shows a strong card. Since your total is less than 17, its likely you will lose." << '\n';
            }
            else // -and your card is greater than 17.
            {
                cout << "You should stand." << '\n' << "The dealer shows a strong card, and your hand is above 16. Hitting above 16 risks busting." << '\n';
            }
        }
        else if (dealerWeak) // If the dealer has a weak upcard-
        {
            if (playerHandValue >= 12) // -and your total is greater or equal to 12.
            {
                cout << "You should stand." << '\n' << "The dealer shows a weak card, and your hand is fair. By standing you let the dealer risk busting." << '\n';
            }
            else // -and your total is less than 12.
            {
                cout << "You should hit." << '\n' << "The dealer shows a weak card. You should draw because your hand is too low to stay." << '\n';
            }
        }
        else if (dealerFair) // If the dealer has a fair upcard-
        {
            if (playerHandValue >= 13) // -and your total is greater or equal to 13.
            {
                cout << "You should stand." << '\n' << "The dealer shows a fair card. Your total is 13 or higher. In this situation you should usually hold." << '\n';
            }
            else // -and your total is less than 13.
            {
                cout << "You should hit." << '\n' << "The dealer shows a fair card. You should draw because your hand is too low to stay." << '\n';
            }
        }
    }
}

// Prints a hand showing each cards name
void printHand(const vector<Card>& hand)
{
    for(int i = 0; i < hand.size(); i++) // loops through every card in the hand
    {
        cout << hand[i].name << " "; // prints cards name with a space
    }
}

// Player's turn to hit or stand. 
void playerTurn(vector<Card>& deck, vector<Card>& handPlayer, vector<Card>& handDealer)
{
    const int WIN_CONDITION = 21; // target total in blackjack
    char choice; // will store h for hit or s for stand

    cout << '\n' << "Deal To Player" << '\n' << "---------------" << '\n';
    giveAdvice(handPlayer, handDealer); // provide strategic advice
    cout << "Enter h to hit or s to stand: "; // prompt for action
    cin >> choice; // read input
    choice = choiceValidation(choice); // ensure valid input

    while(choice == 'h' || choice == 'H') // loop while player wants to hit
    {
        deal(deck, handPlayer); // give player another card
        cout << "Player Drew: "; // announce new hand
        printHand(handPlayer); // show all cards
        cout << '\n'; // newline after hand
        if(winCheck(handPlayer, handDealer, WIN_CONDITION)) return; // check for bust or 21

        giveAdvice(handPlayer, handDealer); // provide advice again
        cout << "Enter h to hit or s to stand: "; // prompt again
        cin >> choice; // read input
        choice = choiceValidation(choice); // validate input
    }
}

// Dealer's turn to hit or stand.
void dealerTurn(vector<Card>& deck, vector<Card>& handPlayer, vector<Card>& handDealer)
{
    const int WIN_CONDITION = 21; // target total in blackjack
    const int DEALER_STAND = 17; // dealer must stand on 17 or higher
    cout << '\n' << "Deal To Dealer" << '\n' << "---------------" << '\n';
    cout << "Dealer Drew: "; // announce dealer's hand
    printHand(handDealer); // show all dealer cards
    cout << '\n'; // newline after hand
    while(handValue(handDealer) < DEALER_STAND) // dealer must hit below 17
    {
        deal(deck, handDealer); // deal another card
        cout << "Dealer Drew: "; // announce new hand
        printHand(handDealer); // show all cards
        cout << '\n'; // newline after hand
    }

    if(winCheck(handPlayer, handDealer, WIN_CONDITION)) return; // check for dealer bust or 21
}

// Compares player and dealer hands and announces the winner.
void announceWinner(const vector<Card>& handPlayer, const vector<Card>& handDealer)
{
    int playerValue = handValue(handPlayer); // get player's total
    int dealerValue = handValue(handDealer); // get dealer's total

    if(playerValue > dealerValue) // player wins with higher total
    {
        cout << '\n' << "You win! Your hand value is " << playerValue << " and the dealer's is " << dealerValue << '\n';
    }
    else if(playerValue < dealerValue) // dealer wins with higher total
    {
        cout << '\n' << "You lose! Your hand value is " << playerValue << " and the dealer's is " << dealerValue << '\n';
    }
    else // totals are equal
    {
        cout << '\n' << "Push! Both you and the dealer have " << playerValue << '\n';
    }
}

// Function used to return a value used for score tracking.
int announceWinnerScore(const vector<Card>& handPlayer, const vector<Card>& handDealer)
{
    int playerValue = handValue(handPlayer); // get player's total
    int dealerValue = handValue(handDealer); // get dealer's total

    if(playerValue > dealerValue) // player wins
    {
        return 1; // positive for player win
    }
    else if(playerValue < dealerValue) // dealer wins
    {
        return -1; // negative for dealer win
    }
    else // push
    {
        return 0; // zero for tie
    }
}

// Function to play a single game of Blackjack
void singleBlackJackGame(vector<Card>& deck, int& wins, int& losses, int& ties, int& gameNumber)
{
    const int WIN_CONDITION = 21; // target total in blackjack
    vector<Card> handPlayer; // player's hand starts empty
    vector<Card> handDealer; // dealer's hand starts empty
    int score = 0; // will hold result of this game
    gameNumber++; // increment game count

    firstCard(deck, handPlayer, handDealer); // deal first cards
    secondCard(deck, handPlayer, handDealer); // deal second cards

    if(winCheck(handPlayer, handDealer, WIN_CONDITION)) // check for natural blackjack
    {
        score = scoreTracker(handPlayer, handDealer, WIN_CONDITION); // get score
    }
    else
    {
        playerTurn(deck, handPlayer, handDealer); // player's turn
        if(!winCheck(handPlayer, handDealer, WIN_CONDITION)) // if game continues
        {
            dealerTurn(deck, handPlayer, handDealer); // dealer's turn
            if(!winCheck(handPlayer, handDealer, WIN_CONDITION)) // if still no winner
            {
                announceWinner(handPlayer, handDealer); // compare hands
                score = announceWinnerScore(handPlayer, handDealer); // get score
            }
            else score = scoreTracker(handPlayer, handDealer, WIN_CONDITION); // dealer phase ended game
        }
        else score = scoreTracker(handPlayer, handDealer, WIN_CONDITION); // player phase ended game
    }

    if(score == 1) wins++; // increment wins
    else if(score == -1) losses++; // increment losses
    else ties++; // increment ties
}

// Main function to play Blackjack.
void playBlackJackGame()
{
    srand(time(0)); // seed random number generator
    int wins = 0; // track player wins
    int losses = 0; // track player losses
    int ties = 0; // track ties
    int gameNumber = 0; // track total games
    char choicePlayBlackjack = 'y'; // start with yes to play

    cout << "BLACKJACK" << '\n' << "----------" << '\n';
    cout << "Do you want to play a hand of blackjack (y to play)? "; // initial prompt
    cin >> choicePlayBlackjack; // read choice
    choicePlayBlackjack = choicePlayBlackJackValidation(choicePlayBlackjack); // validate

    vector<Card> deck = getNewDeck(); // create new deck
    cout << '\n' << "Unshuffled Deck:" << '\n'; // announce unshuffled
    printDeck(deck); // show ordered deck
    shuffleDeck(deck); // shuffle cards
    cout << '\n' << "Shuffled Deck:" << '\n'; // announce shuffled
    printDeck(deck); // show shuffled deck

    while(choicePlayBlackjack == 'y' || choicePlayBlackjack == 'Y') // loop while player wants to play
    {
        singleBlackJackGame(deck, wins, losses, ties, gameNumber); // play one game
        cout << "-----------------------------" << '\n'; // separator
        cout << "Do you want to play another hand (y to play)? "; // prompt again
        cin >> choicePlayBlackjack; // read choice
        choicePlayBlackjack = choicePlayBlackJackValidation(choicePlayBlackjack); // validate
    }

    cout << '\n' << "You played " << gameNumber << " games." << '\n'; // total games
    cout << "You won " << wins << " games." << '\n'; // total wins
    cout << "You lost " << losses << " games." << '\n'; // total losses
    cout << "You tied " << ties << " games." << '\n' << '\n'; // total ties
}

void playBlackJackGame()
{
    srand((unsigned int) time(nullptr)); // sets seed for random number generation
    vector<Card> deck = getNewDeck(); // generates a fresh deck of cards in order
    cout << "Unshuffled Deck:" << '\n'; // text
    printDeck(deck); // prints deck of cards in order
    cout << '\n' << '\n' << "Shuffled Deck:" << '\n'; // spacing and text
    shuffleDeck(deck); // shuffles deck
    printDeck(deck); // prints now shuffled deck
    cout << '\n';
    playCasinoGame(deck); // starts blackjack session loop  
}
Mayan Number Game
// Libraries included
using namespace std;
// Ensures that the integer limit for guessing game inputted by user is correct time. Runs loop if until accepted value is entered.
int validateLimitInput(int upperLimit)
{   
    while(cin.fail()) // Loop to check type failure
    {
        cin.clear(); // resets error state
        cin.ignore(10000, '\n'); // clears 10,000 characters or until a new line is found
        cout << "Invalid Input. Enter another number, or less than 10 to exit: "; 
        cin >> upperLimit;
    }
     return upperLimit; // if loop is not triggered, returns int
}

// Returns a, b, c from user entered guess (case-insensitive). Re-prompts until valid.
char validateGuessInput(string guess)
{
    while(true) // loop runs infinitely
    {
        if((guess.size() == 1) && //if statement ensures that size of string is one and is of allowed values
               (guess[0] == 'a' || guess[0] == 'A' || 
                guess[0] =='b' || guess[0] == 'B' || 
                guess[0] == 'c' || guess[0] == 'C'))
        {
            return guess[0]; // if true returns the accepted letter as a char
        }
        // When the if statement is not satisfied, input validation occurs and user is re-prompted
        cin.clear();
        cin.ignore(10000, '\n');
        cout << "Invalid Input. Please enter either a, b, or c ";
        cin >> guess;
    }
}

// Prints the Mayan base-20 digit extracted from a position: dots for 1-4, bars for 5s, "00" for zero.
void printMayanDigit(int value)
{
    // Constants for consistent form with Mayan Character symbols
    const string MAYAN_ZERO = "00"; // lack of specialized zero symbol. This string is used instead
    const char* MAYAN_ONE = "o"; // dot is one
    const char* MAYAN_FIVE = "\u2580\u2580\u2580\u2580\u2580\u2580\u2580"; // bar is five

    if (value == 0) cout << MAYAN_ZERO << endl; // Special case for zero
    else //Regular case)
    {
        const int DOTS_PER_BAR = 5; // In mayan number system, once 5 is reached, dots are swapped with a bar
        int bars = value / DOTS_PER_BAR; // Integer division to find amount of bars
        int dots = value % DOTS_PER_BAR; // Modulus to find the amount of dots

        for(int i = 0;i < dots;i++) cout << MAYAN_ONE << " "; // Prints amount of dots
        if(dots > 0) cout << endl; // newline once desired amount of dots is reached
        for(int i = 0; i < bars; i++) cout << MAYAN_FIVE << endl; // Prints amount of bars
    }
}

// Decomposes integer into base-20 digits, prints from most-significant to least with separators.
void printMayanNumber(int number)
{
    const string PAGE_BREAK = "--------"; // Page break displays seperation of Mayan numbres decomposed into powers of 20
    int digits[10]; // stores mayan digit for each position
    int count = 0; // tracks how many positions (base-20 digits) there are in the number

    if(number == 0) // Special case for when the number entered is zero. Not useful for game but useful for bulletproof print function
    {
        digits[0] = 0;
        count = 1;
    }
    else
    {
        // Loop that uses integer division to store a digit in each position of the array.
        while(number > 0 && count < 10) // Ends when number is empty, or size of the array is exceeded
        {
        digits[count++] = number % 20;
        number /= 20;
        }
    }

    // Loop to print the Mayan digit for each position in the array
    for(int i = (count - 1); i >= 0; i--) // Loop ends when array is at its first slot. Starts from highest slot
    {
        printMayanDigit(digits[i]); //Calls digit print function
        if(i > 0) cout << PAGE_BREAK << endl; // Creates page-break to show seperation between powers of 20
    }
}

// Picks a random integer between minimum range and user inputted m.
int getRandomNumber(int min, int max)
{
    return rand() % (max - min + 1) + min; // rand generates a random integer -> by modulus division it reduces the integer to value in the specified range -> min is then added so the smallest value is min -> Value is returned
}

// Mayan number game that takes the user's inputted limit and plays a guessing game for a randomly generated number within upperLimit (lower limit of 4)
void mayanNumberGame(int upperLimit)
{
    const int EXIT_THRESHOLD = 10; // value used to exit program if input is under the limit
    do // do-while loop so the game runs at least once through, but can run infinitely. 
    { 
        // if statement to check is limit inputted is within exit threshold to close program
        if(upperLimit < EXIT_THRESHOLD) 
            {
                cout << endl;
                return;
            }
        
        const int RANDOM_LOWER_LIMIT = 4; // the lower limit of what a one of the answers in the game can be
        const int NUM_OPTIONS = 3; // the number of options presented to the user in the game
        int correctNumber = getRandomNumber(RANDOM_LOWER_LIMIT, upperLimit); // randomly generated correct answer, inclusively between lower limit and user specified upper limit 

        // range for how far the incorrect values can be from the correct answer 
        int lowerRange = correctNumber / 2;
        int upperRange = correctNumber + correctNumber / 2; 

        // Generation of incorrect answers
        int wrong1, wrong2;
        wrong1 = getRandomNumber(lowerRange, upperRange);
        while(wrong1 == correctNumber) wrong1 = getRandomNumber(lowerRange, upperRange); //regenerates first wrong answer if equal to correct
        wrong2 = getRandomNumber(lowerRange, upperRange);
        while(wrong2 == correctNumber || wrong2 == wrong1) wrong2 = getRandomNumber(lowerRange, upperRange); //regenerates second wrong answer if equal to either correct or first wrong answer
        int options[NUM_OPTIONS] = {correctNumber, wrong1, wrong2}; // stores all answers in an array

        // Randomly shuffles the array of answers so game 'doesn't have same answer each time
        for(int i = 0; i < NUM_OPTIONS; i++)
        {
            int randomIndex = rand() % NUM_OPTIONS; // random value corresponding to size of array
            int temporaryHolder = options[i];
            options[i] = options[randomIndex];
            options[randomIndex] = temporaryHolder;
        }

        // loop to find the index associated with the correct number post-shuffling
        int correctIndex;
        for(int i = 0; i < NUM_OPTIONS; i++)
        {
            if(options[i] == correctNumber)
            correctIndex = i;
        }

        // Prompts user to guess which mayan number corresponds to the correct number and prints options
        cout << "Which of these Mayan numbers is equal to " << correctNumber << "?" << endl;

        cout << "a)" << endl;
        printMayanNumber(options[0]);
        cout << endl << endl;

        cout << "b)" << endl;
        printMayanNumber(options[1]);
         cout << endl << endl;

        cout << "c)" << endl;
        printMayanNumber(options[2]);
        cout << endl << endl;

        // Gievs user options of which to guess
        cout << "Enter a, b or c: ";
        string guess; // string is used to store guess to account for if they enter more than one character
        cin >> guess; 
        char validGuess = validateGuessInput(guess); // stores validated single-character guess as a char
        int guessIndex; // guess index to correspond the character input with the mayan number
        if (validGuess == 'a' || validGuess == 'A') guessIndex = 0;
        else if (validGuess == 'b' || validGuess == 'B') guessIndex = 1;
        else if (validGuess == 'c' || validGuess == 'C') guessIndex = 2;

        // Prints if the user guesses correctly
        if (guessIndex == correctIndex)
        {
            cout << "CORRECT! The Mayan representation of " << correctNumber << " is" << endl;
            printMayanNumber(correctNumber);
        }
        // Prints if the user's guess is incorrect
        else
        {
            cout << "INCORRECT! The Mayan representation of " << correctNumber << " is" << endl;
            printMayanNumber(correctNumber);
         }
        
        // Asks the user if they want to play again or close the application. Validates for correct input 
        cout << "Enter another number, or less than 10 to exit: ";
        cin >> upperLimit;
        upperLimit = validateLimitInput(upperLimit);
    } while(upperLimit >= EXIT_THRESHOLD); //Loop checks condition and runs again if true
}
void maya_numbers()
{
    srand(time(0)); // sets seed for random number generation
    const int JOHN_EDGAR_REQUESTED_NUMBER = 5212; // rubrik requested number to be converted and printed
    cout << "Maya representation of 5,212:" << endl; 
    printMayanNumber(JOHN_EDGAR_REQUESTED_NUMBER); 
    cout << endl << endl;

    // Game formatting and initial prompt for user input to begin game
    const char* GAME_BAR = "\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580";
    int upperLimit;
    cout << "MAYAN NUMBER GAME" << endl;
    cout << GAME_BAR << endl << endl;
    cout << "Welcome to the Mayan Number Game!" << endl << endl;
    cout << "Enter a number greater than 10. The game will choose a number" << endl;
    cout << "less than or equal to what you entered. You will then have" << endl;
    cout << "to match the decimal number to its Mayan equivalent." << endl;
    cout << "Or, enter a number less than 10 to exit: ";
    cin >> upperLimit;

    // Validation of user input and running the game
    upperLimit = validateLimitInput(upperLimit);
    mayanNumberGame(upperLimit);
    cout << '\n';
}
Convert Integer Numbers to Strings
using namespace std;
// Inclusion of all the sub-functions used by intToString, as well as eachother (e.g. intToThousands uses intToHundreds)
string intToOnes(int number);
string intToTeens(int number);
string intToTens(int number);
string intToHundreds(int number);
string intToThousands(int number);

// FUNCTION 1L CONVERTS INTEGERS TO STRING AND RETURNS IT (not print)
// process broken down into sub functions
// If intToString is asked for a number outside of range (0 : 99,999) it returns the string "error" 
string intToString(int number)
{
    // Case when integer is zero
    if(number == 0)
    {
        return("zero");
    }

    // If the integer is range zero - nine
    else if(number > 0 && number < 10)
    {
        return(intToOnes(number));
    }

    // If the integer is in range 10 - 19 
    else if(number > 9 && number < 20)
    {
        return(intToTeens(number));
    }

    // If the integer is in range 20 - 99
    else if(number > 19 && number < 100)
    {
      return(intToTens(number));
    }

    // If the integer is in range 100 - 999
    else if(number > 99 && number <= 999)
    {
       return(intToHundreds(number));
    }
    // If the integer is in range 1000 - 99,999
    else if(number >= 1000 && number <= 99999)
    {
        return(intToThousands(number));
    }
    // If the number is outside of the range
    else
    {
        return("error");
    }
}

// FUNCTION 2: PRINTING STRIGNS OF INTEGERS
//These three integers are important as it will print the number between the start and end on a specified interval
void printIntStrings(int start, int end, int interval)
{
    // Ensuring program doesnt go on infinitely
    if (interval <= 0) 
    {
        return;
    }

    // Special case where start and end are equal, so only one output
    else if(start == end)
    {
        cout << intToString(start) << endl;
    }

    // Special case for a descending interval
    else if(end < start)
    {
        for(int x = start; x >= end; x = x - interval)
        {
            cout << intToString(x) << endl;
        }
    }

    // Regular case
    else
    {
        for(int x = start; x <= end; x = x + interval)
        {
            cout << intToString(x) << endl;
        }
    }

}

// MAIN FUNCTION I USED, NOW COMMENTED OUT 
void numbers()
{
    int start = 0, end = 0, interval = 0;
    cout << "Enter a number to start: ";
    cin >> start;
    cout << "Enter a number to end: ";
    cin >> end;
    cout << "Enter an interval to go between them: ";
    cin >> interval;
   printIntStrings(start, end, interval);
   cout << '\n';
}

// Sub-function for the ones
string intToOnes(int number)
{
    // Intializes variables
    string ones;

    // Decides which case of integer input
    switch(number)
    {
        case 1: ones = "one";
        break;
        case 2: ones = "two";
        break;
        case 3: ones = "three";
        break;
        case 4: ones = "four";
        break;
        case 5: ones = "five";
        break;
        case 6: ones = "six";
        break;
        case 7: ones = "seven";
        break;
        case 8: ones = "eight";
        break;
        case 9: ones = "nine";
        break;
    }
    return(ones); // Outputs back to user
}

// Sub-function for the teens
string intToTeens(int number)
{
    // Initializes variables
    string teens;

    // Decides which case depending on number
    switch(number)
    {
        case 10: teens = "ten";
        break;
        case 11: teens = "eleven";
        break;
        case 12: teens = "twelve";
        break;
        case 13: teens = "thirteen";
        break;
        case 14: teens = "fourteen";
        break;
        case 15: teens = "fifteen";
        break;
        case 16: teens = "sixteen";
        break;
        case 17: teens = "seventeen";
        break;
        case 18: teens = "eighteen";
        break;
        case 19: teens = "nineteen";
        break;
    }
    return(teens);
}

// Sub-function for the tens
string intToTens(int number)
{
    // Initializes variables
    int tensDigit = number / 10;
    int tensRemainder = number % 10;
    string tens;

    // Deciding the amount in the tens column
    switch(tensDigit)
    {
        case 2: tens = "twenty";
        break;
        case 3: tens = "thirty";
        break;
        case 4: tens = "forty";
        break;
        case 5: tens = "fifty";
        break;
        case 6: tens = "sixty";
        break;
        case 7: tens = "seventy";
        break;
        case 8: tens = "eighty";
        break;
        case 9: tens = "ninety";
        break;
    }

    // CATEGORIZING OUTPUT

    // Special case where there is no number in the ones column (e.g. 20, 40)
    if(tensRemainder == 0)
    {
        return(tens);
    }

    // Normal case where there is a number in the ones column (e.g. 98, 45, 23)
    else
    {
        return(tens+"-"+intToOnes(tensRemainder));
    }
}

// Sub-function for the hundreds
string intToHundreds(int number)
{
    // Initializes varaibles used for computations & output
    string hundreds;
    int hundredsDigit = number / 100;
    int hundredsRemainder = number % 100;

    // Decides how many hundreds
    switch(hundredsDigit)
    {
        case 1: hundreds = "one hundred"; 
        break;
        case 2: hundreds = "two hundred";
        break;
        case 3: hundreds = "three hundred";
        break;
        case 4: hundreds = "four hundred";
        break;
        case 5: hundreds = "five hundred";
        break;
        case 6: hundreds = "six hundred";
        break;
        case 7: hundreds = "seven hundred";
        break;
        case 8: hundreds = "eight hundred";
        break;
        case 9: hundreds = "nine hundred";
        break;
    }

    // CATEGORIZING OUTPUT

    // Special case where nothing is in the tens/teens or ones column (100, 200, 300)
    if(hundredsRemainder == 0)
    {
        return(hundreds);
    }

    // Special case for a the teens being occupied (e.g. 112, 118)
    else if(hundredsRemainder > 9 && hundredsRemainder < 20)
    {
        return(hundreds + " and " + intToTeens(hundredsRemainder));
    }

    // Special case for the tens being occupied but the ones being empty (e.g. 220, 540)
    else if((hundredsRemainder) % 10 == 0)
    {
        return(hundreds + " and " + intToTens(hundredsRemainder));
    }

    // Special case for the tens column being empty (e.g. 205, 209)
    else if((hundredsRemainder) / 10 == 0)
    {
        return(hundreds + " and " + intToOnes(hundredsRemainder));
    }

    // The normal case (e.g. 437)
    else
    {
        return(hundreds + " and " + intToTens(hundredsRemainder % 100));
    }
}

// Sub-function for the thousands
string intToThousands(int number)
{
    // Initializes variables used for calculation of the thousands
    string thousands;
    int thousandsDigit = number / 1000;
    int thousandsRemainder = number % 1000;
    
    // DECIDING HOW MANY THOUSANDS

    // Categorizing how many thousands if its from 1-9 (ones)
    if(thousandsDigit >= 1 && thousandsDigit <= 9)
    {
        thousands = intToOnes(thousandsDigit) + " thousand"; // Uses intToOnes
    }

    // Categorizing how many thousands if its from 10-19 (teens)
    else if(thousandsDigit >= 10 && thousandsDigit <= 19)
    {
        thousands = intToTeens(thousandsDigit) + " thousand"; // Uses intToTeens
    }

    // Categorizing how many thousands if its from 20-99 (tens, as program cannot do above 99 thousand)
    else if(thousandsDigit >= 20)
    {
        thousands = intToTens(thousandsDigit) + " thousand"; // Uses intToTens
    }

    // CATEGORIZING OUTPUT

    // Special case where nothing is in other columns
    if(thousandsRemainder == 0)
    {
        return(thousands);
    }

    // General case for the remainder being above 100 (e.g. 100-999). From here the intToHundreds will complete the output
    else if(thousandsRemainder >= 100)
    {
        return(thousands + ", " + intToHundreds(thousandsRemainder));
    }

    // If nothing in hundreds, but some something in the tens (e.g. 20-99). From here intToTens completes the output
    else if(thousandsRemainder <= 99 && thousandsRemainder >= 20)
    {
        return(thousands + " and " + intToTens(thousandsRemainder));
    }

    // If nothing in hundreds, but some something in the teens (e.g. 10-19). From here intToTeens completes the output
     else if(thousandsRemainder < 20 && thousandsRemainder > 9)
    {
        return(thousands + " and " + intToTeens(thousandsRemainder));
    }

    // If there is nothing in the hundreds, tens/teens but there is remainder in the ones (1-9) (e.g. 2009, 4001)
     else
    {
        return(thousands + " and " + intToOnes(thousandsRemainder));
    }

}
Factors of Numbers
// Program to prints the factors, and related information, of each number between, and including, two integers entered by the user
using namespace std;
void factors() // Begins the program
{
    const int colwidth = 4; // Standardizes column width

    // Setting up the bounds for input
    const int FLOOR = 1; //minimum input
    const int CEILING = 999; // maximum input

    // Setting up values for user input
    int firstvalue, secondvalue = 1; // user inputs
    int start, end = 1; //starting and ending prime

    // Prompt user to enter 2 numbers to be used for calculations
    cout << "Enter a value between 1 and 999: ";
    cin >> firstvalue;
    while (firstvalue < FLOOR || firstvalue > CEILING) // Ensures its within the given range
    {
        cout << "The value must be greater than 0 and less than 1000: ";
        cin >> firstvalue;
    }
    
    // Second prompt for user to input.
    cout << "Enter a second value between 1 and 999: ";
    cin >> secondvalue;
    while (secondvalue < FLOOR || secondvalue > CEILING) // Ensures its within the given range
    {
        cout << "The value must be greater than 0 and less than 1000: ";
        cin >> secondvalue;
    }
    cout << endl; //extra line for spacing

    // Ensures that the start value is smaller then the end value
    if  (firstvalue > secondvalue)
    {
        start = secondvalue;
        end = firstvalue;
    }
    else
    {
        start = firstvalue;
        end = secondvalue;
    }

    // Begin Computation of factors section

    
    for (int x = start; x <= end; x++) // Runs body for every integer between start and end, increasing by 1 each iteration
    {

        // Variable to keep track of how many factors for each iteration
        int factorcount = 0; // Must be inside loop so it resets for each iteration

        cout << setw(colwidth) << x; // Prints the number for which the factors are being identified
        for (int y = 1; y <= x; y++) // Starts with a factor of 1, ends when factor is itself, trying every integer inbetween
        {
            if ((x % y) == 0) // if the remainder is zero (e.g. 2 / 4), a factor is identified and the value is printed
            {
                cout << setw(colwidth) << y; // Prints the identified factor of the number
                factorcount++; // increases the factor count since one has now been identified
            }
        }

        cout << setw(colwidth) << "(" << factorcount << ")"; //Prints factor count in line
    
    // Additional output if a special case (prime or perfect square). Utilizes nested if's
        if (factorcount == 2 || (factorcount%2) == 1) // If SpecialCase1 OR SpecialCase2
        {
            // Special Case 1: Prime Number
            // A Prime number only has 2 factors: 1 and itself. 
            if (factorcount == 2)
            {
              cout << setw(colwidth) << " **prime**" << endl;
            }

            // Special Case 2: Perfect Square
            // A perfect square is the only number with an odd number of factors since one of the factors is a repeated number.
            if ((factorcount%2) == 1) //Integer divides by 2, is a resulting 1 then it is a perfect square
            {
            cout << setw(colwidth) << " **perfect square**" << endl;
            }     
        }

       // Standard output if not a Special Case
        else 
        {
            cout << endl;
        }
    }

    cout << endl; // Spacing

    // Now we are going to sum up the digits in start and end

    // First we sum the digits, and product for the 'start' variable

    // Creates a temporary value that will be used to store and alter the inputted value of start. Also creates associated values for sum and product
    int temp_start = start;
    int sum_start = 0;
    int product_start = 1;

    // As long as temp_start still has values in it we run this loop. It stores the value in the 1s column, then shifts the number down by a factor of 10 until all digits are stored.
    while(temp_start > 0)
    {
        int digit_start = temp_start % 10; // create a integer in the loop that uses remainder integer division to keep only the digit in the 1s column. For example if start was 926, digit will be 6.
        sum_start += digit_start; // Adds this value to the sum
        product_start *= digit_start; // Multiplies this value to the product
        temp_start /= 10; // Removes the last column so process moves onto the next digit
    }

    // Next we sum the digits, and product for the 'end' variable. This follows the exact same process as it did for the start variables.

    int temp_end = end;
    int sum_end = 0;
    int product_end = 1;

    while(temp_end > 0)
    {
        int digit_end = temp_end % 10;
        sum_end += digit_end;
        product_end *= digit_end;
        temp_end /= 10;
    }

    // Now we print the sum of our start and end variables, with an optional text if the number is interesting

    cout << setw(colwidth) << start << ": sum of digits = " << sum_start;
    if (start == (sum_start + product_start)) // A number is interesting if the sum and product when added together is equal to the number the user inputted
    {
        cout << setw(colwidth) << " --interesting--" << endl;
    }
    else 
    {
        cout << endl;
    }

    cout << setw(colwidth) << end << ": sum of digits = " << sum_end;
    if (end == (sum_end + product_end))
    {
        cout << setw(colwidth) << " --interesting--" << endl;
    }
    else 
    {
        cout << endl;
    }
    cout << '\n';
}
Distance Converter & Circle Area
using namespace std;
void circleRadius()
{
    // Part 1: Circle Area

    // Establishes variables and constants needed for the computation
    double radius = 0;
    double area = 0;
    const double PI = 3.141592653589793;

    // Title Block
    cout << "CIRCLE AREA" << endl;
    cout << "-----------" << endl;

    //Prompts the user to enter a radius and stores the value for computation
    cout << "Enter radius: ";
    cin >> radius;

    // Computes corresponding circles area and prints the radius and area back to the user.
    area = PI * radius * radius; // computation
    cout << endl; // line for spacing
    cout<< "a circle with radius = " << radius << " has an area = " << area << endl; // print to user
    cout << endl;

}
void distance()
{
  // Part 2: Distance

    // Defines constants that will be used in distance conversions
    const double MetreToInches = 39.37007874; // Converts Metres to Inches
    const int InchesToFeet = 12; // Converts Inches to Feet
    const double MetretoFurlong = 0.00497096; // Converts Metres to Furlongs
    const double SpeedOfLight = 299792458; // Speed of Light in m/s

    // Title Block
    cout << "DISTANCE" << endl;
    cout << "--------" << endl;
   
    // Prompts the user to enter a distance and stores the value for computation
    double distance = 0;
    cout << "Enter distance in metres: ";
    cin >> distance;
    cout << endl;

    // Conversions from M -> Inch, and Inch -> Feet
    double TotalInches = distance * MetreToInches; // Variable for total feet from Metres
    int feet = TotalInches / InchesToFeet; // Variable as an int of distance in feet 
    double inches = TotalInches - feet * InchesToFeet; // Magic number of inches in distance once integer of feet is subtracted
    cout << distance << " metres = " << feet << "\' " << inches << "\"" << endl; // Relays computations back to user

    // Conversions from M -> Furlongs
    double furlong = distance * MetretoFurlong; // Variable that converts metres to furlongs
    cout << distance << " metres = " << furlong << " furlongs" << endl; // Prints to user


    // Conversions from M -> s at Speed of Light
    double seconds = distance / SpeedOfLight; // since light is in m/s, m / (m/s) = s (seconds)
    cout << "It takes " << seconds << "s for light to travel " << distance << "m in a vacuum" << endl; // Prints to user
}