Tuesday, November 21, 2017

Programming Challenge 13.18 - A Game Of 21

 Example File: AGameOfTwentyone.7z

Dice.h


#ifndef DICE_H_
#define DICE_H_

#include <string>
using std::string;

#include <vector>
using std::vector;

class Dice
{
    private:
        const int MIN_VALUE = 1;            // The lowest die value
        const int NUM_DICE = 2;                // The number of dice
        const int DIE_SIDES = 6;            // The number of die sides
        const int NUMELS = 5;                // The number of elements in a row of the diceGfx 2D-vector

        vector<vector<string>> diceGfx;    // Holding a graphic representation of a die
        vector<int> diceValues = {};        // Holding the dice values

    public:
        Dice();

        void seedRng();
        void roll();
        void outputDice();

        vector<int> getDiceValues() const
        { return diceValues; }
};

#endif


Dice.cpp


#include "Dice.h"

#include <cstdlib>
#include <ctime>

#include <iomanip>
using std::setw;

#include <iostream>
using std::cout;

/* **********************************************************
            Dice::Dice()
    This constructor, via initializer-list, initializes the
    diceValues vector and the diceGfx vector of vectors.
    ********************************************************** */

Dice::Dice() : diceValues { 0, 0 },
                    diceGfx { {},
                                 { "+-----+", "|     |", "|  O  |", "|     |", "+-----+" },
                                 { "+-----+", "| O   |", "|     |", "|   O |", "+-----+" },
                                 { "+-----+", "| O   |", "|  O  |", "|   O |", "+-----+" },
                                 { "+-----+", "| O O |", "|     |", "| O O |", "+-----+" },
                                 { "+-----+", "| O O |", "|  O  |", "| O O |", "+-----+" },
                                 { "+-----+", "| O O |", "| O O |", "| O O |", "+-----+" } }
{
    seedRng();
}

/* **********************************************************
    Dice::seedRng()
    This function seeds the random number generator.
    ********************************************************** */

void Dice::seedRng()
{
    srand(static_cast<unsigned int> (time(0)));
}

/* **********************************************************
            Dice::roll()
    This function simulates the rolling of two dice. When it
    is called, the diceValues vector is cleared, the roll of
    n-number of dice is simulated, and the values are pushed
    back into the vector.
    ********************************************************** */

void Dice::roll()
{
    diceValues.clear();

    for (int i = 0; i < NUM_DICE; i++)
    {
        diceValues.push_back((rand() % DIE_SIDES - MIN_VALUE + 1) + MIN_VALUE);
    }
}

/* **********************************************************
            Dice::outputDice()
    This function outputs the dice to screen.
    ********************************************************** */

void Dice::outputDice()
{
    cout << "\n";
    for (int i = 0; i < NUMELS; ++i)
    {
        for (int j = 0; j < NUM_DICE; ++j)
        {
            cout << setw(12) << diceGfx[getDiceValues()[j][i] << setw(17);
        }
        cout << "\n";
    }
    cout << "\n";
}


Player.h



#ifndef PLAYER_H_
#define PLAYER_H_

#include <string>
using std::string;

class Player
{
    private:
        string playerName;        // The players' name

        int roundScore;            // The players' round score
        int finalScore;            // The players' final score
        int highScore;                // The players' highscore

    public:
        Player();

        void setPlayerName();
        bool isPlayerName(string);

        void addRoundScore(int score)       
        { roundScore += score; }

        void addFinalScore()                       
        { finalScore = roundScore; }

        void setHighscore(int high)
        { highScore += high; }

        void resetScore()
        {
            roundScore = 0;
            finalScore = 0;
        }

        string getPlayerName() const
        { return playerName; }

        int getRoundScore() const
        { return roundScore; }

        int getFinalScore() const
        { return finalScore; }

        int getHighscore() const
        { return highScore; }
};

#endif

Player.cpp


#include "Player.h"

#include <iostream>
using std::cout;
using std::cin;

/* **********************************************************
            Player::Player() - Default constructor
    ********************************************************** */

Player::Player()
{
    playerName = "Player One";
    roundScore = 0;
    finalScore = 0;
    highScore = 0;
}

/* **********************************************************
            Player::setPlayerName()
    This function asks the player to enter his or her name.
    ********************************************************** */

void Player::setPlayerName()
{
    string tempName = "";

    cout << "\nAs you enter the ISN-RADIO BAR backroom, you notice, that the room is\n"
          << "almost empty, except for one person sitting behind a table, playing some\n"
          << "sort of game with dice. As you approach the table, he looks up and greets\n"
          << "you.\n\n";
    cout << "Aah, finally! I've been waiting all evening for a player to show up!\n"
          << "My name's Jack Black. Call me Jack, if you like. And what is your name?\n\n";
    cout << "You tell him, that he can call you: ";
   
    cin.ignore();
    getline(cin, tempName);

    while (isPlayerName(tempName) == false)
    {
        getline(cin, tempName);
    }
}

/* **********************************************************
            Player::isPlayerName()
    This function validates the players input.
    ********************************************************** */

bool Player::isPlayerName(string tempName)
{
    if (tempName.empty() || tempName.at(0) == ' ')
    {
        cout << "\nSorry, but I did not get your name.\n"
              << "Could you repeat it please? ";
        return false;
    }
    else
    {
        playerName = tempName;
        return true;
    }

    return false;
}


Dealer.h


#ifndef DEALER_H_
#define DEALER_H_

#include <string>
using std::string;

class Dealer
{
    private:
        string dealerName;        // The dealers' name
        int roundScore;            // The dealers' round score
        int finalScore;            // The dealers' final score
        int highScore;                // The dealers' highscore

    public:
        Dealer()
        {
            dealerName = "Jack Black";
            roundScore = 0;
            finalScore = 0;
        }

        void addRoundScore(int score)
        { roundScore += score; }

        void addFinalScore()
        { finalScore = roundScore; }

        void setHighscore(int high)
        { highScore += high; }

        void resetScore()
        {
            roundScore = 0;
            finalScore = 0;
        }

        string getDealerName() const
        { return dealerName; }

        int getRoundScore() const
        { return roundScore; }

        int getFinalScore() const
        { return finalScore; }

        int getHighscore() const
        { return highScore; }
};

#endif


Game.h

#ifndef GAME_H_
#define GAME_H_

#include "Dice.h"
#include "Dealer.h"
#include "Player.h"

class Game
{
    private:
        enum Choice { ROLL = 'R', HOLD = 'H' };
        enum Highscore { BLACK_JACK = 21, WIN = 2 };

        const int MAX_SCORE = 21;

        bool isPlayerTurn;
        bool isDealerTurn;
        bool isGameOver;
        char choice;
        int  score;

        Dice dice;
        Player player;
        Dealer dealer;

    public:
        Game();

        void run();
        void setup();
        void resetGame();
        void giveChoice();
        void firstTurn();
        void playerTurn();
        void dealerTurn();
        void switchPlayers();
        void calcScore();
        bool isWin();
        bool isWinDealer();
        void displayScoreboard();
        void displayHighscore();

        char getChoice() const
        { return toupper(choice); }

        bool getTurnStateDealer() const
        { return isDealerTurn; }

        bool getTurnStatePlayer() const
        { return isPlayerTurn; }

        int getScore() const
        { return score; }

        bool getGameState() const
        { return isGameOver; }       
};

#endif


Game.cpp


#include "Game.h"

#include <iomanip>
using std::setw;

#include <iostream>
using std::cin;
using std::cout;

/* **********************************************************
            Game::Game() - Default constructor
    ********************************************************** */

Game::Game()
{
    isDealerTurn = true;
    isGameOver = false;
}

/* **********************************************************
            Game::setup()
    This function makes a call to the player class, allowing
    the player to enter his or her player name.
    ********************************************************** */

void Game::setup()
{
    player.setPlayerName();
}

/* **********************************************************
            Game::run()
    This function represents the main gameloop. Upon entry, a
    call to the firstTurn function is made, the players are
    switched, and the players turn begins. If he or she or
    the artificial dealer wins or loses, the game is over, and
    the player asked, if he or she wishes to play again.
    ********************************************************** */

void Game::run()
{
    char again = ' ';

    do
    {
        firstTurn();
        playerTurn();

        if (getGameState() == false)
        {
            switchPlayers();
            dealerTurn();
        }

        if (getGameState() == true)
        {
            cout << "Do you wish to play another round? ";
            cin >> again;

            while (toupper(again) != 'Y' && toupper(again) != 'N')
            {
                cout << "Do you wish to play another round? ";
                cin >> again;
            }

            if (toupper(again) == 'Y')
            {
                resetGame();
            }
        }   
    } while (getGameState() == false);
}

/* **********************************************************
            Game::switchPlayer()
    This function switches dealer and player. If one is active
    the other is set to false, and vice versa.
    ********************************************************** */

void Game::switchPlayers()
{
    if (getTurnStateDealer() == true)
    {
        isDealerTurn = false;
        isPlayerTurn = true;
    }
    else
    {
        isPlayerTurn = false;
        isDealerTurn = true;
    }
}

/* **********************************************************
            Game::firstTurn()
    This function simulates the first turn for both dealer and
    player. After rolling the dice a score is calculated, and
    the result is passed to the appropriate member function of
    the dealer or player class.
    ********************************************************** */

void Game::firstTurn()
{
    dice.roll();
    calcScore();
    dealer.addRoundScore(getScore());

    switchPlayers();

    dice.roll();
    calcScore();
    player.addRoundScore(getScore());
}   
/* **********************************************************
            Game::displayScoreboard()
    This function outputs the dealer and player score.
    ********************************************************** */

void Game::displayScoreboard()
{
    if (getTurnStateDealer() == true)
    {
        cout << dealer.getDealerName() << "'s Score: "
              << dealer.getRoundScore() << " \n\n";
    }
    else
    {
        cout << player.getPlayerName() << "'s Score: "
              << player.getRoundScore() << " \n\n";
    }
}

/* **********************************************************
            Game::playerTurn()
    This function represents the players' turn. The player is
    given a choice to roll or hold. A player is able to roll
    the dice as long as no winning condition is met. If the
    player decides to 'H'old, which is possible at any time,
    his or her turn is over, his or her final score is set,
    and the function exits.
    ********************************************************** */

void Game::playerTurn()
{
    cout << "\n" << player.getPlayerName() << "'s Turn\n";
    displayScoreboard();

    do
    {   
        giveChoice();

        if (getChoice() == ROLL)
        {
            dice.roll();
            dice.outputDice();

            calcScore();
            player.addRoundScore(getScore());

            displayScoreboard();
        }

        if (getChoice() == HOLD)
        {
            cout << "\n" << player.getPlayerName() << " Stands!\n"
                             << player.getPlayerName() << "'s Turn is over ...\n\n";

            player.addFinalScore();
        }
    } while (isWin() == false && getChoice() != HOLD);
}

/* **********************************************************
            Game::giveChoice()
    This function asks the player during his or her turn, if
    they wish to roll or hold. The input is validated.
    ********************************************************** */

void Game::giveChoice()
{
    cout << "Do you wish to [R]oll or [H]old? ";
    cin >> choice;
   
    while (getChoice() != ROLL && getChoice() != HOLD)
    {
        cout << "Do you wish to [R]oll or [H]old? ";
        cin >> choice;
    }
}
/* **********************************************************
            Game::dealerTurn()
    This function represents the dealers' turn. The dice are
    rolled, the score calculated and passed to the appropriate
    member function of the dealer class, until a general or a
    specific winning condition unique to the dealer is met.
    ********************************************************** */

void Game::dealerTurn()
{
    cout << "\n" << dealer.getDealerName() << "'s Turn\n";
    displayScoreboard();

    do
    {
        dice.roll();
        dice.outputDice();

        calcScore();
        dealer.addRoundScore(getScore());

        displayScoreboard();
    } while (isWin() == false && isWinDealer() == false);
}

/* **********************************************************
            Game::calcScore()
    This function calculates and passes the score achieved to
    either the dealer or player classes member function.
    ********************************************************** */

void Game::calcScore()
{
    score = 0;

    for (auto points : dice.getDiceValues())
    {
        score += points;
    }   
}

/* **********************************************************
            Game::isWin()
    This function evaluates the basic winning conditions of
    this game. If a winning or losing condition is met, the
    winner or loser is announced, the isGameOver condition is
    set to true und is returned from the function.
    ********************************************************** */

bool Game::isWin()
{
    if (player.getRoundScore() == MAX_SCORE || dealer.getRoundScore() == MAX_SCORE)
    {
        cout << "BLACK JACK!\n";
   
        if (player.getRoundScore() == MAX_SCORE)
        {
            cout << player.getPlayerName() << " Wins!\n\n";       
            player.setHighscore(BLACK_JACK);
        }
        else
        {
            cout << dealer.getDealerName() << " Wins!\n\n";       
            dealer.setHighscore(BLACK_JACK);
        }
        return isGameOver = true;
    }
   
    if (player.getRoundScore() > MAX_SCORE || dealer.getRoundScore() > MAX_SCORE)
    {   
        if (player.getRoundScore() > MAX_SCORE)
        {
            cout << player.getPlayerName() << " Busts ...\n"
                  << dealer.getDealerName() << " Wins!\n\n";

            dealer.setHighscore(WIN);
        }
        else
        {
            cout << dealer.getDealerName() << " Busts ...\n"
                  << player.getPlayerName() << " Wins!\n\n";

            player.setHighscore(WIN);
        }
        return isGameOver = true;
    }

    return isGameOver = false;
}

/* **********************************************************
            Game::isWin()
    This function evaluates additional winnings conditions,
    specific to the dealer.
    ********************************************************** */

bool Game::isWinDealer()
{
    if (dealer.getRoundScore() > player.getFinalScore())
    {
        cout << dealer.getDealerName() << " Wins!\n";   
        dealer.setHighscore(WIN);
       
        return isGameOver = true;
    }
    else if (dealer.getRoundScore() == player.getFinalScore())
    {
        cout << "DRAW!\n\n";
        return isGameOver = true;
    }

    return isGameOver = false;
}

void Game::displayHighscore()
{
    cout << "\n" << setw(23) << "HIGHSCORE LIST\n\n";
    cout << setw(15) << dealer.getDealerName() << setw(20) << dealer.getHighscore() << "\n"
          << setw(15) << player.getPlayerName() << setw(20) << player.getHighscore() << "\n";
}

/* **********************************************************
            Game::isWin()
    This function evaluates additional winnings conditions,
    specific to the dealer.
    ********************************************************** */

void Game::resetGame()
{
    isGameOver = false;
    isDealerTurn = true;

    dealer.resetScore();
    player.resetScore();
}


Example Output:












No comments:

Post a Comment