Cpt0Teemo Cpt0Teemo - 1 month ago 8
C++ Question

C++ code compiles but doesn't run

I am currently writing a Texas Hold'em code in order to learn more about c++ and gain experience. But I recently ran into a problem in which I have no idea what to do.My code compiles just fine without errors but once I make it run and it arrive at a specific function it just stops working (as in I get an error from CodeBlock saying your program has stopped working). I have tried cutting out parts such as loops in the function to see which specific part is the problem but after a couple of days im still at a stop.
Here is the function and class that I believe is the problem:

class Player{
string name;
int bank=100;
static string cards[53];
static string final_card[2][6];
static string table_cards[5];

public:
void set_name(string a){name=a;}
string print_name(){return name;}
void card_generator();
string set_cards(int c){return cards[c];}
int print_bank(){return bank;}
void set_final_card(int i, int max_i);
void print_cards(){for(int i=0;i<6;i++){cout<<final_card[0][i]<<endl;}}
};

void Player::set_final_card(int i, int max_i){
srand(time(NULL));
int tempV = 17;//create temp cards
string tempCards[tempV];
int randNB[tempV];

int check1 = 0, tmp;
while (check1==0){
for(int g=0; g<tempV;g++){

tempCards[g]=cards[rand()%53];
check1=1;
tmp = g - 1;
for(int o=tmp; o!=0; o--){
if (tempCards[g]==tempCards[o]){
check1=0;
}
}

}

}
int p=0,k;
while(p<6){
k=0;
final_card[0][k]=tempCards[p];
k++;
p++;
}
while(p<12){
k=0;
final_card[1][k]=tempCards[p];
k++;
p++;
}
while(p<17){
k=0;
table_cards[k]=tempCards[p];
k++;
p++;
}
}


Here is the full code in case I am wrong of the source of the problem:

#include <iostream>
#include <string>
#include <stdlib.h>
#include <ctime>
using namespace std;

class Player{
string name;
int bank=100;
static string cards[53];
static string final_card[2][6];
static string table_cards[5];

public:
void set_name(string a){name=a;}
string print_name(){return name;}
void card_generator();
string set_cards(int c){return cards[c];}
int print_bank(){return bank;}
void set_final_card(int i, int max_i);
void print_cards(){for(int i=0;i<6;i++){cout<<final_card[0][i]<<endl;}}
};

string Player::cards[53];
string Player::final_card[2][6];
string Player::table_cards[5];

int main () {
int choice1=0, i, max_i, tempV;
string username;

cout<< "Welcome to Texas Hold'Em!\n1-Play\n2-Quit\n";//menu

while((choice1!=1)&&(choice1!=2)){//Makes sure that user enters correct input```
cin>>choice1;
if ((choice1!=1)&&(choice1!=2)){
cout<<"Invalid Input!\nTry again!\n";
}
}
system ("cls");
if (choice1==2){//End Program
return 0;
}
cout<<"How many players?[2-6]"<<endl;
while((i!=2)&&(i!=3)&&(i!=4)&&(i!=5)&&(i!=6)){//Makes sure that user enters correct input
cin>>i;
if ((i!=2)&&(i!=3)&&(i!=4)&&(i!=5)&&(i!=6)){
cout<<"Invalid Input!\nTry again!\n";
}
}
Player player[i];//creating array of players
player[0].card_generator();
max_i = i;//max_i is nb of players
i--;//since arrays start at 0
system("cls");

player[0].set_final_card(i,max_i);
player[0].print_cards();

if (choice1==1) {//SET NAMES OF ALL PLAYERS
for(i=0; i<max_i; i++){
cout<< "Whats your name?\n";
cin>>username;
player[i].set_name(username);
cout<<"Your name is "<< player[i].print_name()<< " and you have "<< player[i].print_bank()<<"$\n";

tempV=i+1;//used bc arrays start at 0
if(tempV!=max_i){
cout<< "Give PC to player "<< i+2 <<endl;
}
_sleep(3000);
system("cls");
}
}

return 0;
}

void Player::set_final_card(int i, int max_i){
srand(time(NULL));
int tempV = 17;//create temp cards
string tempCards[tempV];
int randNB[tempV];

int check1 = 0, tmp;
while (check1==0){
for(int g=0; g<tempV;g++){

tempCards[g]=cards[rand()%53];
check1=1;
tmp = g - 1;
for(int o=tmp; o!=0; o--){
if (tempCards[g]==tempCards[o]){
check1=0;
}
}

}

}
int p=0,k;
while(p<6){
k=0;
final_card[0][k]=tempCards[p];
k++;
p++;
}
while(p<12){
k=0;
final_card[1][k]=tempCards[p];
k++;
p++;
}
while(p<17){
k=0;
table_cards[k]=tempCards[p];
k++;
p++;
}
}

void Player::card_generator(){
string card_value[13];
card_value[0]="1";
card_value[1]="2";
card_value[2]="3";
card_value[3]="4";
card_value[4]="5";
card_value[5]="6";
card_value[6]="7";
card_value[7]="8";
card_value[8]="9";
card_value[9]="10";
card_value[10]="J";
card_value[11]="Q";
card_value[12]="K";

string card_type[4];
card_type[0]="of hearts";
card_type[1]="of diamonds";
card_type[2]="of clubs";
card_type[3]="of spades";
string card[53];
int x=0;
fill_n(card,53,0);

for (int j=0;j<4;j++){
for (int q=0;q<13;q++){
card[x]=card_value[q]+" "+card_type[j];
cards[x]=card[x];
x++;

}
}
}


If you have any criticism about the code itself even if not directly linked to problem feel free to tell me as I'm doing this to learn :D. Thank you in advance!!

Answer
#include <iostream>
#include <string>
#include <stdlib.h>
#include <ctime>

Be consistent in what you do. Including <stdlib.h> and <ctime> looks strange. Either include <cstdlib> and <ctime>, or include <stdlib.h> and <time.h>.

using namespace std;

Don't do this. This using imports all names from the std namespace, which is several hundreds. Only import those names that you actually need, or, alternatively, write std::time instead of the unqualified time. This makes it perfectly clear that you are referring to the time from the standard library instead of one that you might have defined yourself.

class Player{
    string name;
    int bank=100;
    static string cards[53];
    static string final_card[2][6];
    static string table_cards[5];

The cards should not be represented as strings, but as a separate data type called Card, with properties like suit and rank and a to_string method.

    public:
    void set_name(string a){name=a;}

To make your program fast, pass a as const std::string & instead of a simple string. This will prevent some copying of data. You should give a better name to the parameter, e.g. void set_name(const std::string &name) { this.name = name; }.

    string print_name(){return name;}

This method does not print anything, therefore it must not be called print_name.

    void card_generator();

Methods usually are named with verbs, not with nouns. So generate_cards would be a better name. But what does generate mean here? (I'm not a native English speaker, but would draw_cards describe it accurately?)

    string set_cards(int c){return cards[c];}

A method called set_* usually modifies something. This one doesn't. Why did you name it this way?

    int print_bank(){return bank;}
    void set_final_card(int i, int max_i);

Give better names to the parameters. From reading only this declaration, I have no idea what i and max_i might mean.

    void print_cards(){for(int i=0;i<6;i++){cout<<final_card[0][i]<<endl;}}
};

    string Player::cards[53];
    string Player::final_card[2][6];
    string Player::table_cards[5];

It looks strange that the cards are stored in the Player class, since no poker player should ever have insight to all 52 cards. And why 53? Is there a joker in your game? These three fields should be moved to a class Table. This allows you to have multiple independent tables, which is nice for a big tournament.

int main () {
  int choice1=0, i, max_i, tempV;
  string username;

  cout<< "Welcome to Texas Hold'Em!\n1-Play\n2-Quit\n";//menu

  while((choice1!=1)&&(choice1!=2)){//Makes sure that user enters correct input```

Before reading the choice1 variable, you must initialize it. Since you don't do it, you invoke undefined behavior and everything that the program does after that is unpredictable.

    cin>>choice1;
    if ((choice1!=1)&&(choice1!=2)){
        cout<<"Invalid Input!\nTry again!\n";
    }
  }
  system ("cls");
  if (choice1==2){//End Program
    return 0;
  }
  cout<<"How many players?[2-6]"<<endl;
  while((i!=2)&&(i!=3)&&(i!=4)&&(i!=5)&&(i!=6)){//Makes sure that user enters correct input

Same here. The user hasn't yet entered anything, so how can you check it?

    cin>>i;

Add error handling for every input by enclosing it in an if clause: if (std::cin >> i) {.

    if ((i!=2)&&(i!=3)&&(i!=4)&&(i!=5)&&(i!=6)){
        cout<<"Invalid Input!\nTry again!\n";
    }
  }
  Player player[i];//creating array of players

Don't use arrays, use a std::vector instead. This allows you to easily extend the table to have 10 players. In the end, there should not be a single 6 in your program.

  player[0].card_generator();
  max_i = i;//max_i is nb of players

Why do you call this variable max_i, when the comment says that max_players would be a better name?

  i--;//since arrays start at 0
  system("cls");

  player[0].set_final_card(i,max_i);
  player[0].print_cards();

  if (choice1==1) {//SET NAMES OF ALL PLAYERS
    for(i=0; i<max_i; i++){
        cout<< "Whats your name?\n";
        cin>>username;
        player[i].set_name(username);
        cout<<"Your name is "<< player[i].print_name()<< " and you have "<<                 player[i].print_bank()<<"$\n";

        tempV=i+1;//used bc arrays start at 0
        if(tempV!=max_i){

What does the V in tempV mean?

            cout<< "Give PC to player "<< i+2 <<endl;
        }
        _sleep(3000);
        system("cls");
    }
  }

  return 0;
}

    void Player::set_final_card(int i, int max_i){
    srand(time(NULL));
    int tempV = 17;//create temp cards

This 17 is a magic number. It would be better to write it as 5 + 6 * 2, since that makes it much clearer.

    string tempCards[tempV];
    int randNB[tempV];

    int check1 = 0, tmp;
    while (check1==0){
        for(int g=0; g<tempV;g++){

            tempCards[g]=cards[rand()%53];

The 53 is wrong here. I can only be wrong. When you select from 52 cards with equal probability, it must be % 52.

            check1=1;
            tmp = g - 1;
            for(int o=tmp; o!=0; o--){
                if (tempCards[g]==tempCards[o]){
                  check1=0;
                }
            }
        }
    }