Black Jack in C++

59bf7de38472a8e2a3f2fbfff2736cd2
0
Optiplexicide 101 Oct 29, 2006 at 23:12

Hey. What am I doing wrong with this code for Black Jack?

card.h

enum suit {clubs, diamonds, hearts, spades};

class Card {

public:
    Card(suit = clubs, int = 1);
    suit su() {return f; }
    int value() {return v; }
    void write_out();

private:
    suit f;
    int v;
    int s;
};

card.cpp

#include "card.h"
#include <cassert>
#include <iostream>

using namespace std;

Card::Card(suit ss, int vv)
{
    assert(vv >=1 && vv<=13);
    s=ss;
    v=vv;
}
void Card::write_out()
{
    const char *tab1[] = {"Clubs", "Diamonds", "Hearts", "Spades"};
    const char *tab2[] = {"Jack", "Queen", "King"};
    cout << tab1[ s ] << ' ';
    if (v == 1)
        cout << "Ace";
    else if (v <= 10)
        cout << v;
    else
        cout << tab2[v-11];
}

cardstack.h

#include "card.h"
#include <vector>

using namespace std;

class Cardstack {
public:
    Cardstack() {stack.reserve(52);}
    void throw_cards() {stack.clear();}
    int number_cards() { return stack.size();}
    Card look_at(int no);
    Card deal_top();
    void lay_top(Card k);
    void new_pack();
    void shuffle();
private:
    vector<Card> stack;
   
};

cardstack.cpp

#include "cardstack.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

Card Cardstack::look_at(int no)
{
    return stack.at(stack.size() -no);
}
Card Cardstack::deal_top()
{
    Card top = stack.back();
    stack.pop_back();
    return top;
}
void Cardstack::lay_top(Card k)
{
    stack.push_back(k);
}
void Cardstack::new_pack()
{
    stack.clear();
    for (suit s=clubs; s<spades; s=suit(s+1))
        for (int v=1; v<=13; v++)
            stack.push_back(Card(s,v));
}
void Cardstack::shuffle()
{
    srand(time(0));
    for (int i=1; i<1000; i++)
    {
        int n1 = rand() % stack.size();
        int n2 = rand() % stack.size();
        Card temp = stack[n1];
        stack[n1] = stack[n2];
        stack[n2] = temp;
    }
}

player.h

#include "cardstack.h"
class Player {

public:
    Player(Cardstack& cardpack, bool is_computer)
        : pack(cardpack), computer(is_computer) {};
    int play();
private:
    Cardstack hand;
    Cardstack& pack;
    const bool computer;
    int points();
};

player.cpp

#include "player.h"
#include <iostream>

using namespace std;

main()
{
    Cardstack pack;
    Player you (pack, false);
    Player I (pack, true);
    char answer[10];
    cout << "Welcome to Black Jack, the game of twenty-one!" << endl;

    while (true)
    {
        cout << "New game? "; cin >> answer;
        if (answer[0] != 'y') break;
        pack.new_pack();
        pack.shuffle();
        int p1 = you.play();
        if (p1 > 21)
            cout << "Sorry, you busted.  You lose." << endl;
        else if (p1 == 21)
            cout << "You Win!" << endl;
        else
        {
            //the computer must play
            int p2 = I.play();
            if (p2 <=21 && p2 >=p1)
                cout << "You lost!" << endl;
            else
                cout << "You won!" << endl;
        }
    }
   
}

points.cpp

#include "player.h"

#include "card.h"

#include <iostream>

using namespace std;

int Player::points()
{
    int p = 0, number_aces = 0;

    for (int i = 1; i <= hand.number_cards(); i++)
    {
        int v = hand.look_at(i).value();
        if (v == 1) {
            p+= 14;
            number_aces++;
        }
        else
            p += v;
    }
    for (int j=1; j <= number_aces && p > 21; j++)
        p -= 13; // counts an ace as 1
    return p;
}

play.cpp

#include "points.cpp"


#include <iostream>

using namespace std;

int Player::play()
{
    bool contine = true;
    int p;
    while (contine)
    {
        Card k = pack.deal_top();
        hand.lay_top(k);
        p = points();
        if (computer) {
            cout << "The computer got "; k.write_out();
            cout << endl;

                if (p >= 16)
                {
                    cout << "The computer has " << p << " points" << endl;
                    contine = false;
                }
        }
        else
        { //Person
            cout << "You got "; k.write_out();
            cout << " and have " << p << " points" << endl;
            if (p < 21)
            {
                char answer[10];
                cout << "One more card? Indicate 'y' for yes or 'n' for no "; cin >> answer; // this needs to be fixed
                contine = answer[0] == 'y';
            }
            else
                contine = false;
        }
    }
    hand.throw_cards();
    return p;
}

Any help will be appriciated.

13 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Oct 30, 2006 at 00:19

Umm, that’s a huge amount of code! You don’t expect us to read through all that and try to guess what the error is that you’re looking for, do you? You need to be a lot more specific. Just asking “what is wrong with this” is not enough; are you talking about a compilation error or does the game compile but not work correctly (and if so, what are the precise symptoms of the problem)? Also, you need to do some work yourself to narrow down the location of the bug, as we are never going to read the amount of code that you just posted. Get it down to a segment of 30 lines or less and we’ll try to help.

Aa49fb4fa33227edb37971712c18481c
0
jmgk 101 Oct 30, 2006 at 00:35

hi,

in card.h, the constructor “Card(suit = clubs, int = 1);” seens wrong

suit = clubs? int = 1? default params dont need a variable name?

jmgk

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 Oct 30, 2006 at 01:21

jmgk: You indeed don’t have to specify variables names when using default parameters, so his code is correct.

59bf7de38472a8e2a3f2fbfff2736cd2
0
Optiplexicide 101 Oct 30, 2006 at 01:56

I did fix that, but I am getting these errors:

card.h(1) : error C2011: ‘suit’ : ‘enum’ type redefinition

card.h(3) : error C2011: ‘Card’ : ‘class’ type redefinition

Error executing cl.exe.

play.exe - 2 error(s), 0 warning(s)

59bf7de38472a8e2a3f2fbfff2736cd2
0
Optiplexicide 101 Oct 30, 2006 at 02:03

I also deleted #include “card.h” from points.cpp, and now I’m getting:

play.obj : error LNK2001: unresolved external symbol “public: class Card __thiscall Cardstack::look_at(int)” (?look_at@Cardstack@@QAE?AVCard@@H@Z)

play.obj : error LNK2001: unresolved external symbol “public: void __thiscall Card::write_out(void)” (?write_out@Card@@QAEXXZ)

play.obj : error LNK2001: unresolved external symbol “public: void __thiscall Cardstack::lay_top(class Card)” (?lay_top@Cardstack@@QAEXVCard@@@Z)

play.obj : error LNK2001: unresolved external symbol “public: class Card __thiscall Cardstack::deal_top(void)” (?deal_top@Cardstack@@QAE?AVCard@@XZ)

LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main

Debug/play.exe : fatal error LNK1120: 5 unresolved externals

Error executing link.exe.


I get these alot when trying to experiment on what to do.

46407cc1bdfbd2db4f6e8876d74f990a
0
Kenneth_Gorking 101 Oct 30, 2006 at 03:15

When you include header files in more than one source file, the contents are actually declared again if you don’t take measures to prevent it. There are two ways to so. The first is to wrap your entire header in a ifndef/endif block like this:

#ifndef __CARD_H_
#define __CARD_H_
enum suit {clubs, diamonds, hearts, spades};

class Card {

public:
    Card(suit = clubs, int = 1);
    suit su() {return f; }
    int value() {return v; }
    void write_out();

private:
    suit f;
    int v;
    int s;
};
#endif // __CARD_H_

or the more elegant solution:

#pragma once

enum suit {clubs, diamonds, hearts, spades};

class Card {

public:
    Card(suit = clubs, int = 1);
    suit su() {return f; }
    int value() {return v; }
    void write_out();

private:
    suit f;
    int v;
    int s;
};
59bf7de38472a8e2a3f2fbfff2736cd2
0
Optiplexicide 101 Oct 30, 2006 at 03:43

@Kenneth Gorking

When you include header files in more than one source file, the contents are actually declared again if you don’t take measures to prevent it. There are two ways to so. The first is to wrap your entire header in a ifndef/endif block like this:

#ifndef __CARD_H_
#define __CARD_H_
enum suit {clubs, diamonds, hearts, spades};

class Card {

public:
    Card(suit = clubs, int = 1);
    suit su() {return f; }
    int value() {return v; }
    void write_out();

private:
    suit f;
    int v;
    int s;
};
#endif // __CARD_H_

or the more elegant solution:

#pragma once

enum suit {clubs, diamonds, hearts, spades};

class Card {

public:
    Card(suit = clubs, int = 1);
    suit su() {return f; }
    int value() {return v; }
    void write_out();

private:
    suit f;
    int v;
    int s;
};

Didn’t work…

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 Oct 30, 2006 at 04:51

This probably has not much to do with the original problem but..:whistle: I would do

struct suit { enum type {clubs,diamonds,hearts,spaders}; };

instead of

enum suit {clubs, diamonds, hearts, spades};

to keep enums nicely in their own namespaces.

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 Oct 30, 2006 at 10:28

Then use a namespace instead of a struct, unless you really encapsulate the enum in the struct (so you would use just suit instead of suit::type)

46462f88a1670d7e9cbbfa360aa20134
0
juhnu 101 Oct 30, 2006 at 12:47

@.oisyn

Then use a namespace instead of a struct, unless you really encapsulate the enum in the struct (so you would use just suit instead of suit::type)

Well that doesn’t work for enums defined inside a class (which is most of the time, actually I hardly ever declare global enums) so I don’t really see the benefits of using namespaces and rather choose a convention which works for the both cases instead.

class IBuffer {
   public:
   struct PrimitiveType {
      enum type {
         Triangle=0,
     Line=1,
      };
   };

   ...methods..
};
340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 Oct 30, 2006 at 13:44

I see your point, but I still think you have to prevent people for using IBuffer::PrimitiveType as a type -or- make sure you can use that type instead of IBuffer::PrimitiveType::type.

#define IMPLEMENT_CLASS_ENUM(classtype, enumtype) \
    public:\
    classtype::classtype() : m_value() { }\
    classtype::classtype(enumtype v) : m_value(v) { }\
    operator enumtype() { return m_value; }\
    private:\
    enumtype m_value;

class IBuffer
{
public:
    struct PrimitiveType
    {
        enum type { Triangle, Line };
        IMPLEMENT_CLASS_ENUM(PrimitiveType, type)
    };
};

IBuffer::PrimitiveType t = IBuffer::PrimitiveType::Triangle;
46407cc1bdfbd2db4f6e8876d74f990a
0
Kenneth_Gorking 101 Oct 30, 2006 at 18:45

@Optiplexicide

Didn’t work…

Do you have #include “card.h” in play.cpp?

Also, including source-files in other source-files is considered bad practice. If it is done more than once, the compiler will complain about the function body being defined more than once.

59bf7de38472a8e2a3f2fbfff2736cd2
0
Optiplexicide 101 Oct 31, 2006 at 02:42

@Kenneth Gorking

Do you have #include “card.h” in play.cpp? Also, including source-files in other source-files is considered bad practice. If it is done more than once, the compiler will complain about the function body being defined more than once.

I did that, but I still get the same mess of errors.