C++ Text File Logging

profileYani334
program.zip

blackjackrevised2/BlackJack.h

//BLACKJACK #ifndef _BLACKJACK #define _BLACKJACK #include "BlackJackHand.h" #include "BlackJackDeck.h" #include "ValidInput.h" class BlackJack { public: BlackJack(unsigned int deckNumber = 1); void Run(); //GetArrayOfStats private: enum class GameState { Wager, FirstRound, //check for blackjack and allow double down; splitting COULD also go here; might be better to have isFirstRound bool PlayerInput, DealerReveal, //let player surrender DealerInput, EndRound, Exit }; const int DECK_NUMBER; // not actually used should delete string message; string error; int input; string name; //PLAYER NAME needed for persistent stats (not implemented) should be constructor parameter default:"Player" BlackJackDeck deck; BlackJackHand player; BlackJackHand dealer; int playerChips; int playerWager; //stuff for persistant stats (not implemented) maybe make it an array which can be passed to the main.cpp menu which will handle the user profile txt unsigned long int handsPlayed; unsigned long int handsWon; unsigned long int handsLost; unsigned long int chipsWon; unsigned long int chipsLost; void Output(); void Input(); void Processing(); void DealCards(); void HandsOnTable(); GameState state; }; BlackJack::BlackJack(unsigned int deckNumber) : DECK_NUMBER(deckNumber), deck(deckNumber) { playerChips = 500; //use static constant input = 0; state = GameState::Wager; deck.Shuffle(); } void BlackJack::Run() { while (state != GameState::Exit) { Output(); Input(); Processing(); } } void BlackJack::Output() { system("CLS"); //clear the console if (state == GameState::Wager) { //player betting screen cout << "Place your bet." << endl << endl << "Player Chips: " << playerChips << endl << endl << error << endl << "How much do you want to wager? "; } else if (state == GameState::PlayerInput) { //player input menu HandsOnTable(); cout << "1. Hit" << endl << "2. Stand" << endl //<< "3. Double Down //not done" << endl //<< "4. Surrender //not done" << endl << endl << error << message << endl << "Option: "; } else if (state == GameState::DealerInput) { HandsOnTable(); cout << message << endl << "Continue..."; } else if (state == GameState::EndRound) { HandsOnTable(); cout << message << endl << "Continue..."; } } void BlackJack::Input() { string sInput; getline(cin, sInput); stringstream linestream(sInput); linestream >> input; } void BlackJack::Processing() { //CHECK IF DECK IS EMPTY HERE error = ""; message = ""; //new round state? if (state == GameState::Wager) { //player betting screen if (input < 1 ) { error += "You must bet at least one chip. "; } else if (input > playerChips) { error += "You cannot bet more chips than you have. "; } else { playerWager = input; playerChips -= input; stringstream linestream; linestream << "Player wagers " << playerWager << " chips. "; message = linestream.str(); state = GameState::PlayerInput; DealCards(); } } else if (state == GameState::PlayerInput) { //player input menu //may have to split GameState::FirstRound where we let player double down and check for blackjack switch (input) { case 1: { BlackJackCard card = deck.DrawCard(); player.AddCard(card); message += "Player drew "; message += card.ToString(); message += ". "; if (player.GetBust()) { message += "Player busts. "; dealer.FlipFirstCard(); state = GameState::EndRound; } else if (player.GetHandValue() == 21) { dealer.FlipFirstCard(); state = GameState::DealerInput; } break; } case 2: { message += "Player stands. Dealer hand is revealed. "; dealer.FlipFirstCard(); state = GameState::DealerInput; break; } /* case 3: //betting not implemented break; case 4: break; */ default: error += "Invalid Option "; } } else if (state == GameState::DealerInput) { if (dealer.GetHandValue() < 17 && dealer.GetHandValue() <= player.GetHandValue()) { BlackJackCard card = deck.DrawCard(); message += "Dealer drew "; message += card.ToString(); message += ". "; dealer.AddCard(card); if (dealer.GetBust()) { message += " Dealer busts. "; state = GameState::EndRound; } else if (dealer.GetHandValue() >= 17) { message += " Dealer stands. "; state = GameState::EndRound; } } else { message += "Dealer stands. "; state = GameState::EndRound; } } else if (state == GameState::EndRound) { if (playerWager == 0) { if (playerChips == 0) { } else { state = GameState::Wager; player.EmptyHand(); dealer.EmptyHand(); } } else { if (player.GetBust() || (dealer.GetHandValue() > player.GetHandValue() && !dealer.GetBust())) { stringstream linestream; linestream << "You lost " << playerWager << " chips. "; message = linestream.str(); } else if (player.GetHandValue() == dealer.GetHandValue()) { playerChips += playerWager; stringstream linestream; linestream << "Push. " << playerWager << " chips were returned to you. "; message = linestream.str(); } else { stringstream linestream; if (player.isBlackJack) { playerChips += playerWager * 3 / 2; linestream << "You won " << (playerWager * 3 / 2) << " chips. "; } else { playerChips += playerWager * 2; linestream << "You won " << playerWager << " chips. "; } message = linestream.str(); } playerWager = 0; } } } void BlackJack::DealCards() { BlackJackCard card; card = deck.DrawCard(); player.AddCard(card); card = deck.DrawCard(); dealer.AddCard(card); card = deck.DrawCard(); player.AddCard(card); card = deck.DrawCard(); dealer.AddCard(card); if (player.GetHandValue() == 21) { message += "Player Black Jack! "; player.isBlackJack = true; state = GameState::EndRound; } if (dealer.GetHandValue() == 21) { message += "Dealer Black Jack! "; dealer.isBlackJack = true; state = GameState::EndRound; } else if ((dealer.GetHandValue() == 21 && player.GetHandValue() == 21) == false) { dealer.FlipFirstCard(); } } void BlackJack::HandsOnTable() { cout << "Cards left in deck: " << deck.CardsRemaining() << endl; cout << "Dealer Hand: " << dealer.ToString() << " (" << dealer.GetHandValue(); if (dealer.GetFaceDown()) cout << "?"; //estimate dealer's hand cout << ")\n\n" << "Player Hand: " << player.ToString() << " (" << player.GetHandValue() << ")" << endl << endl << "Player Chips: " << playerChips << endl << "Player Wager: " << playerWager << endl << endl; } #endif

blackjackrevised2/BlackJackCard.h

/* HEADER */ #ifndef _BLACKJACK_CARD #define _BLACKJACK_CARD #include <iostream> #include <stdexcept> #include <sstream> using namespace std; enum Rank // converts implicitly to int { Ace = 1, // explicity set Ace to 1 Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King }; enum Suit // converts implicitly to int { Spades = 1, Hearts, Diamonds, Clubs }; class BlackJackCard { public: //constants static const Rank MIN_RANK; static const Rank MAX_RANK; static const Suit MIN_SUIT; static const Suit MAX_SUIT; static const char RANKS[]; // an array that holds the names of the ranks static const char SUITS[]; //constructors BlackJackCard() : myRank(Rank::Ace), mySuit(Suit::Spades), isFaceUp(true) {} BlackJackCard(Rank rank, Suit suit, bool faceUp = true); //accessors Rank GetRank(){ return myRank; } Suit GetSuit(){ return mySuit; } bool GetFaceUp(){ return isFaceUp; } string ToString(); //mutators void SetRank(Rank rank); void SetSuit(Suit suit); void FlipCard(){ isFaceUp = !isFaceUp; } private: Rank myRank; Suit mySuit; bool isFaceUp; }; //static member initialization const Rank BlackJackCard::MIN_RANK = Rank::Ace; const Rank BlackJackCard::MAX_RANK = Rank::King; const Suit BlackJackCard::MIN_SUIT = Suit::Spades; const Suit BlackJackCard::MAX_SUIT = Suit::Clubs; const char BlackJackCard::RANKS[] = { '0', 'A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K'}; const char BlackJackCard::SUITS[] = { '0', 'S', 'H', 'D', 'C' }; BlackJackCard::BlackJackCard(Rank rank, Suit suit, bool faceUp) { SetRank(rank); mySuit = suit; isFaceUp = faceUp; } void BlackJackCard::SetRank(Rank rank) { if(rank < MIN_RANK || rank > MAX_RANK) { //throw out of range exception with description stringstream strOut; strOut << "Rank argument: " << rank << " is out of range. Rank must be between " << MIN_RANK << " and " << MAX_RANK << ". "; throw out_of_range(strOut.str()); } else { myRank = rank; } } void BlackJackCard::SetSuit(Suit suit) { if(suit < MIN_SUIT || suit > MAX_SUIT) { //throw out of range exception with description stringstream strOut; strOut << "Suit argument: " << suit << " is out of range. Suit must be between " << MIN_SUIT << " and " << MAX_SUIT << ". "; throw out_of_range(strOut.str()); } else { mySuit = suit; } } string BlackJackCard::ToString() { stringstream strOut; if (isFaceUp) { strOut << SUITS[GetSuit()] << RANKS[GetRank()]; } else { strOut << '?' << '?'; } return strOut.str(); } #endif

blackjackrevised2/BlackJackDeck.h

/* HEADER */ #ifndef _BLACKJACK_DECK #define _BLACKJACK_DECK #include "BlackJackCard.h" #include <ctime> #include <vector> using namespace std; class BlackJackDeck { public: static const int STANDARD_SIZE; //constructor BlackJackDeck(unsigned int num = 1); // use usinged int? //dont need to delete vector? //destructor //copy constructor //assignment operator BlackJackCard DrawCard(); //initialize void Initialize(); //use vector? deque? stack? void Shuffle(); const int CardsRemaining() { return cardNumber; } void OutputDeck(); //debug only, should not exist here private: int deckNumber; int cardNumber; vector<BlackJackCard> deck; }; const int BlackJackDeck::STANDARD_SIZE = BlackJackCard::MAX_SUIT * BlackJackCard::MAX_RANK; //52 card deck BlackJackDeck::BlackJackDeck(unsigned int num) { deckNumber = num; Initialize(); } void BlackJackDeck::Initialize() { deck.clear(); cardNumber = deckNumber * STANDARD_SIZE; deck.reserve(cardNumber); //generate deck BlackJackCard card; for (int i = 0; i < deckNumber; i++) { for (int suit = BlackJackCard::MIN_SUIT; suit <= BlackJackCard::MAX_SUIT; suit++) { for (int rank = BlackJackCard::MIN_RANK; rank <= BlackJackCard::MAX_RANK; rank++) { card.SetSuit(static_cast<Suit>(suit)); card.SetRank(static_cast<Rank>(rank)); deck.push_back(card); } } } } void BlackJackDeck::Shuffle() { //just use random_shuffle lmao <algorithm> vector<BlackJackCard> tempDeck = deck; deck.clear(); int randomCard = 0; srand(time(NULL)); for (int i = 0; i < cardNumber; i++) { randomCard = rand() % (cardNumber - i); deck.push_back(tempDeck.at(randomCard)); tempDeck.erase(tempDeck.begin() + randomCard); } } BlackJackCard BlackJackDeck::DrawCard() { BlackJackCard card = deck.back(); deck.pop_back(); cardNumber--; return card; } //remove later void BlackJackDeck::OutputDeck() { cout << "\nDeck Contents\n" << "===================" << endl; for (int i = 0; i < cardNumber; i++) { cout << deck.at(i).ToString() << endl; } cout << "===================" << endl; } #endif

blackjackrevised2/BlackJackHand.h

/* HEADER BlackJackHand */ #ifndef _BLACKJACK_HAND #define _BLACKJACK_HAND #include "BlackJackCard.h" #include <list> class BlackJackHand { public: //constructor BlackJackHand() { handValue = 0; isBust = false; isBlackJack = false; hasFaceDown = false;} void EmptyHand(); void AddCard(BlackJackCard card); void CalculateValue(); // needed to recalculate if has ace and hand is bust string ToString(); bool GetBust(){ return isBust; } bool GetFaceDown(){ return hasFaceDown; } int GetHandValue(){ return handValue; } bool isBlackJack; void FlipFirstCard(); private: list<BlackJackCard> hand; list<BlackJackCard>::iterator handIter; bool isBust; bool hasFaceDown; int handValue; }; //constuctor? void BlackJackHand::AddCard(BlackJackCard card) { hand.push_back(card); CalculateValue(); } void BlackJackHand::CalculateValue() { bool calculate = true; int aceLow = 0; //loop while (calculate) { hasFaceDown = false; handValue = 0; int aceCount = 0; for(handIter = hand.begin(); handIter != hand.end(); ++handIter) { if (handIter->GetFaceUp()) { //if card is ace ++acecount add 11 if (handIter->GetRank() == Ace) { if (aceLow > aceCount) { handValue += 1; } else { handValue += 11; } aceCount++; } //if card is jack, queen, king ++10 else if (handIter->GetRank() == Jack || handIter->GetRank() == Queen || handIter->GetRank() == King) { handValue += 10; } //else use enum rank int else { handValue += handIter->GetRank(); } } else { hasFaceDown = true; } } //if handValue > 21 and contians aces -> recalculate with one ace as value of 1 if (handValue > 21 && aceLow < aceCount) { aceLow++; } //elseif value > 21 isBust = true else { if (handValue > 21) { isBust = true; } calculate = false; } } } string BlackJackHand::ToString() { stringstream strOut; for(handIter = hand.begin(); handIter != hand.end(); ++handIter) { strOut << handIter->ToString() << ' '; } return strOut.str(); } void BlackJackHand::FlipFirstCard() { handIter = hand.begin(); handIter->FlipCard(); CalculateValue(); } void BlackJackHand::EmptyHand() { hand.clear(); isBust = false; isBlackJack = false; hasFaceDown = false; handValue = 0; } #endif

blackjackrevised2/main.cpp

blackjackrevised2/main.cpp

/*
HEADER

main for testing


*/

#include   < iostream >
#include   "BlackJackCard.h"
#include   "BlackJackDeck.h"
#include   "BlackJackHand.h"
#include   "BlackJack.h"

#include   "ValidInput.h"

using   namespace  std ;



enum   State
{
     MainMenu ,
     DeckNumber ,
     Game ,
     Exit  
};

int  main ()
{
     State  state  =   MainMenu ;
     int  input  =   0 ;
    string error  =   "" ;
    
     int  deckNumber  =   1 ;
    
     while   ( state  !=   Exit )
     {
         if ( state  ==   MainMenu )    
         {
            cout  <<   "Main Menu \n\n\n\n"   <<   "1. Start\n2. Exit"   <<  endl ;
            cout  <<  error  <<  endl ;
            
            error  =   "" ;
            
            
            
             ValidInput :: CinGetInteger ( input ,   "Enter Choice: " ,   "" );
            
             switch   ( input )
             {
                 case   1 :
                    state  =   DeckNumber ;
                     break ;
                 case   2 :
                    state  =   Exit ;
                     break ;  
                 default :
                    error  =   "Invalid Option" ;                    
             }

         }
        
         else   if ( state  ==   DeckNumber )
         {
            cout  <<   "How many decks do you want to play with? \n\n\n\n"   <<   "1. (1)\n2. (2)\n3. (4)\n4. (6)\n5. (8)"   <<  endl ;
            cout  <<  error  <<  endl ;
            
            error  =   "" ;
            
             ValidInput :: CinGetInteger ( input ,   "Enter Choice: " ,   "" );
            
            
             switch   ( input )
             {
                 case   1 :
                    deckNumber  =   1 ;
                    state  =   Game ;
                     break ;
                 case   2 :
                    deckNumber  =   2 ;
                    state  =   Game ;
                     break ;  
                 case   3 :
                    deckNumber  =   4 ;
                    state  =   Game ;
                     break ;
                 case   4 :
                    deckNumber  =   6 ;
                    state  =   Game ;
                     break ;
                 case   5 :
                    deckNumber  =   8 ;
                    state  =   Game ;
                     break ;
                 default :
                    error  =   "Invalid Option" ;                    
             }
         }    
        
         else   if   ( state  ==   Game )
         {
             BlackJack  game ( deckNumber );  
            game . Run ();      
            state  =   MainMenu ;
         }
        system ( "CLS" );
     }
    
    
     return   0 ;
}

blackjackrevised2/ValidInput.h

//Nick Pierson //Validation and Utility Functions #ifndef _VALIDINPUT #define _VALIDINPUT #include <sstream> #include <string> #include <iostream> #include <cstdio> #include <cstdlib> #include <iomanip> #include <climits> // for limits of a int INT_MIN and INT_MAX #include <cfloat> // for limits of a double DBL_MIN and DBL_MAX using namespace std; namespace ValidInput { bool IsStringInteger(string); int StringToInteger(string); bool CinGetInteger(int& value, string preText = "Please enter an integer: ", string postText = "\nPlease enter a valid integer.\n"); // double GetValidDouble(const double MIN = -DBL_MAX, const double MAX = DBL_MAX); /** ClearInputBuffer function * Clears the input buffer and resets the fail state of an istream object. * * @param in (istream object by ref) - the object to clear & reset; defaults to cin. * @return none. */ void ClearInputBuffer(istream &in = cin); // function prototype bool IsStringInteger(string sInput) { char character = 0; int number = 0; stringstream linestream(sInput); return ((linestream >> number) && !(linestream >> character)); } int StringToInteger(string sInput) { int number = 0; if (IsStringInteger(sInput)) { stringstream linestream(sInput); linestream >> number; } return number; } bool CinGetInteger(int& value, string preText, string postText) { string input = ""; bool valid = true; cout << preText; cin.sync(); getline(cin, input); if (IsStringInteger(input)) { value = StringToInteger(input); } else { value = -1; cout << postText; valid = false; } return valid; } //THOMS CODE double GetValidDouble(const double MIN, const double MAX) { double validNumber = 0.0; // holds the user input cin >> validNumber; // try to get input if(cin.fail()) // if user input fails... { // reset the cin object and clear the buffer. ClearInputBuffer(); // report the problem to the user. cerr << "\nInvalid input. Please try again and enter a numeric value.\n"; // Try again by calling the function again (recursion) validNumber = GetValidDouble(MIN, MAX); } else if(validNumber < MIN || validNumber > MAX)// if value is outside range... { // report the problem to the user. cerr << "\nInvalid input. Please try again and enter a value between " << MIN << " and " << MAX << ".\n"; // Try again by call the function again (recursion) validNumber = GetValidDouble(MIN, MAX); } return validNumber; // returns a valid value to the calling function. } void ClearInputBuffer(istream &in) { char characterFromBuffer; // a char variable to hold input from the buffer // if the in object has failed... if(in.fail()) { in.clear(); // clear the fail state of the object characterFromBuffer = in.get(); // attempt to read a character // while the character read is not new-line or not end-of-file while (characterFromBuffer != '\n' && characterFromBuffer != EOF) { // therefore something was read from the buffer // attempt to read another character characterFromBuffer = in.get(); } // end of while }// end of if } // end of ClearInputBuffer } #endif