Case Statement does not execute - c++

This is a growing source of irritation for me at the moment, when I press the corresponding button for the cases (they're initialized above) they don't actually execute and I'm stuck in the menu.
I'm sure this is ridiculously simple and I'm just not seeing it.
Edit: Added more, upon request
const int POKER = 1;
const int EVAL = 2;
const int EXIT = 3;
const char FIVE_CARD = 'a';
const char TEXAS = 'b';
const char OMAHA = 'c';
const char SEVEN_CARD = 'd';
const char GO_BACK = 'e';
const char MENU[] = "\nPlease choose an option from the following:\n"
"1) Play Poker\n2) Set Evaluation Method\n3) Quit\n: ";
const char POKER_MENU[] = "\nPlease choose your game:\n"
"a) 5 Card Draw\nb) Texas Hold 'Em\nc) Omaha High\n"
"d) 7 Card Stud\ne) Go back\n: ";
int main()
{
int choice = 0;
char poker_choice;
do
{
choice = askForInt(MENU, EXIT, POKER);
switch(choice)
{
case POKER :
do
{
choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
switch(poker_choice)
{
case FIVE_CARD :
std::cout << "Not implemented yet" << std::endl;
break;
case TEXAS :
std::cout << "Not implemented yet" << std::endl;
break;
case OMAHA :
std::cout << "Not implemented yet" << std::endl;
break;
case SEVEN_CARD :
std::cout << "Not implemented yet" << std::endl;
break;
case GO_BACK :
break;
}
}while(poker_choice != GO_BACK);
case EVAL :
std::cout << "Not implemented yet" << std::endl;
break;
case EXIT :
break;
}
}while(choice != EXIT);

choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
should be
poker_choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);

Since you mentioned this is inside a method,
There are few things to check here;
Once inside the method, just print poker_choice and see if your the value is getting passed correctly.
Check if all the cases FIVE_CARD, TEXAS are declared as constants of the same data type.

Your error seems to be on this line:
choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
You test poker_choice in your switch but you assign the value to choice.
It should be:
poker_choice = askForChar(POKER_MENU, GO_BACK, FIVE_CARD);
// ^^^^^^
switch(poker_choice)
// ...

Related

Using var for a switch case

I have to do a C++ program to manage bank accounts. But i'm stuck. I need to display the different accounts, to select one and do some stuff on the selected account. I'm doing the choice in a switch case but i would like the "case" to be dynamic (an other part of the program is made for adding account)
switch (choixMenu)
{
case 1:
//Consulter un compte
do {
cout << endl << " ----------------------- CONSULTATION -----------------------" << endl << endl;
cout << "Choisir le compte a consulter : \n" << endl;
while (nCompte != NULL) {
int numCompte = 1;
int *ptr (0);
ptr = &numCompte;
cout << numCompte << " - " << nCompte << cid << endl;
numCompte++;
switch (choixConsul) {
case ptr :
}
}
cin >> choixMenu;
if (choixMenu != 1 && choixMenu != 2 && choixMenu != 3)
{
cout << "Choix invalide !" << endl;
}
} while (choixConsul != 3);
(compte = account)
Is there any way to do the case with a var? A loop to display the different account and a case in a loop to select every account?
Thanks for help! :)
A dynamic solution is to use tables:
struct Menu_Entry
{
std::string option_text;
void (*p_action_function)();
}
std::vector<Menu_Entry> menu;
With a table driven system, you could have one function that displays all the selections, then dereferences a function pointer associated with the menu choice.
Several menus can be displayed and processed by passing a vector of menu selections to the menu processing function.
The std::string could be replaced with an array of characters in order to allow for static constant data.

GNU argp "too few arguments"

My program is supposed to take two required arguments, and three optional arguments, like follows
ATE <input file> <output file> [--threads] [--bass] [--treble]
(note, I haven't figured out how to take <required> arguments yet, so input and output file is defined in the code as -i input_file and -o output_file)
I'm using the GNU library argp to parse the command line arguments, my file is based off the third example.
I run my program using the following command
$ ./ATE -i input_file.pcm -o output_file.pcm
Too few arguments!
Usage: ATE [OPTION...]
-p AMOUNT_OF_THREADS -b BASS_INTENSITY -t TREBLE_INTENSITY
input_file.pcm output_file.pcm
Try `ATE --help' or `ATE --usage' for more information.
threads: 2, bass: 4, treble: 4
opening file input.pcm
RUNNING!
done, saving to out.pcm
When running my program, I get "too few arguments", even though argp succesfully parsed the input and output option, as you can see in the output.
Printing out the number of arguments in parse_opt, cout << state->arg_num << endl; gives me 0's at every call.
The code is a little long, but it's completely self-contained so you can compile it to see for yourself.
commands.cpp
using namespace std;
#include <stdlib.h>
#include <argp.h>
#include <iostream>
#include <string>
#include <errno.h>
struct arguments {
string input_file;
string output_file;
int threads;
int bass;
int treble;
};
static char doc[] = "Parallequaliser - a multithreaded equaliser application written in c++";
static char args_doc[] = "-p AMOUNT_OF_THREADS -b BASS_INTENSITY -t TREBLE_INTENSITY input_file.pcm output_file.pcm";
static struct argp_option options[] = {
{"input_file", 'i', "IN_FILE", 0, "an input file in pcm format"},
{"output_file", 'o', "OUT_FILE", 0, "an output file in pcm format"},
{"threads", 'p', "AMOUNT_OF_THREADS", OPTION_ARG_OPTIONAL, "amount of threads, min 2"},
{"bass", 'b', "BASS_INTENSITY", OPTION_ARG_OPTIONAL, "bass intensity, from 0 to 7"},
{"treble", 't', "TREBLE_INTENSITY", OPTION_ARG_OPTIONAL, "treble intensity, from 0 to 7"},
{0}
};
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
struct arguments *arguments = (struct arguments *) state->input;
switch (key) {
case 'p':
if (arg == NULL) {
arguments->threads = 4;
} else {
arguments->threads = strtol(arg, NULL, 10);
}
break;
case 'b':
if (arg == NULL) {
arguments->bass = 4;
} else {
arguments->bass = strtol(arg, NULL, 10);
}
break;
case 't':
if (arg == NULL) {
arguments->treble = 4;
} else {
arguments->treble = strtol(arg, NULL, 10);
}
break;
case 'i':
if (arg == NULL) {
cout << "You forgot to specify the input file using the -i input_file.pcm option" << endl;
} else {
arguments->input_file = (string) arg;
}
break;
case 'o':
if (arg == NULL) {
cout << "You forgot to specify the out file using the -i output_file.pcm option" << endl;
} else {
arguments->output_file = (string) arg;
}
break;
case ARGP_KEY_ARG:
cout << "Key arg... " << key << endl;
if (state->arg_num > 5){
cout << "Too many arguments!" << endl;
argp_usage(state);
}
break;
case ARGP_KEY_END:
if (state->arg_num < 2){
cout << "Too few arguments!" << endl;
argp_usage(state);
}
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static struct argp argp = { options, parse_opt, args_doc, doc };
int main (int argc, char **argv) {
struct arguments arguments;
arguments.threads = 2;
arguments.bass = 4;
arguments.treble = 4;
argp_parse(&argp, argc, argv, ARGP_NO_EXIT, 0, &arguments);
cout << "threads: " << arguments.threads << ", bass: " << arguments.bass << ", treble: " << arguments.treble << endl;
cout << "opening file " << arguments.input_file << endl;
cout << "RUNNING!" << endl;
cout << "done, saving to " << arguments.output_file << endl;
return 0;
}
The options don't count as "arguments" for the context of the argp parser.
When running ./ATE -i input_file.pcm -o output_file.pcm, you have "too few arguments" because you reach ARGP_KEY_END, the end of the arguments, with no arguments left. arg_num represents the "stand-alone" arguments : the number of ARGP_KEY_ARG arguments that have been processed. You don't have any.
To make sure you have the two required arguments as you initialy wanted, check that you don't reach ARGP_KEY_END without having seen two arguments (like you are already doing : the too few arguments would mean you don't have your two filenames). The case ARGP_KEY_ARG is where you get the values of the arguments.

Why can't I redefine this variable in C++?

char x;
bool tf;
void IsNumber(char x)
{
switch (x)
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
bool tf(true);
break;
default:
bool tf(false);
break;
}
}
int main(int argc, const char * argv[])
{
using namespace std;
cout << "Test if a character is a number: " << endl;
char x;
cin >> x;
IsNumber((char) x);
if (bool tf = true)
cout << "True" << endl;
if (bool tf = false)
cout << "False" << endl;
return 0;
}
I am getting an error after the default: saying I can't redefine the variable. Also, it says, at the bottom, that I the variable tf isn't a variable. I am really new to C++, I only know python can someone help me out?
New code giving me an error:
#include <iostream>
bool tf;
tf = true;
bool IsNumber(char x)
{
switch (x)
{
case '1':
You're trying to declare two variables with the same name in the same scope. The switch statement itself defines a scope, but each case clause does not. If you want a scope within a case clause, then you'll have to provide one yourself:
case '0':
{
bool tf(true);
break;
}
Although it's not clear what good that is; you're declaring a local variable then ignoring it. Perhaps you meant to set the global variable:
case '0':
tf = true;
break;
so you could then check it with
if (tf) // NOT if (bool tf = true) - that also declares a new local variable
or, less freakily, perhaps you want to return a value:
bool IsNumber(char x) {
switch (x) {
case '0':
// and so on
return true;
default:
return false;
}
}
and test it with
if (IsNumber(x)) {
cout << "True" << endl;
} else {
cout << "False" << endl;
}
or, if verbosity isn't your thing
cout << (IsNumber(x) ? "True" : "False") << endl;
or even
cout << boolalpha << IsNumber(x) << endl;
You should probably take some time to read an introductory book until you're comfortable with the basics such as scopes, declarations and definitions. Here are some recommendations.
You haven't assigned anything to tf, for comparison operators we want =='s instead of just the ='s.
if (tf == true) {
}
You can only define a variable one you can assign it as many times as you need.
bool tf = false
means I am define a variable and assigning it
if I just want to assign it later
tf = false
if I want to do a conditional test
if (tf){do stuff}
You have x defined at the very top as a global variable, and then try and define it again in main. You have to pick one or the other, or rename one. What you probably want to do is get rid of the one in main.
You also have your bools compared as = instead of how they should be like ==.
Edit: You actually don't need the comparison in there at all.
if(tf){
cout << "True\n"
}
else cout << "False\n"
That will see if tf is true and output true and if not, output false.

How do I select a range of values in a switch statement?

When I try to compile I get this error:
1>------ Build started: Project: snake, Configuration: Debug Win32 ------
1> exercise.cpp
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(13): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(16): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(19): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(22): error C2059: syntax error : '>='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(25): error C2059: syntax error : '>'
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(28): error C2059: syntax error : '=='
1>c:\users\robin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(34): warning C4065: switch statement contains 'default' but no 'case' labels
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Code:
#include <iostream>
using namespace std;
int main(){
int score;
//Vraag de score
cout << "Score:";
cin >> score;
//Switch
switch(score){
case >= 100:
cout << "a";
break;
case >= 50:
cout << "b";
break;
case >= 25:
cout << "c";
break;
case >= 10:
cout << "d";
break;
case > 0:
cout << "e";
break;
case == 0:
cout << "f";
break;
default:
cout << "BAD VALUE";
break;
}
cout << endl;
return 0;
}
How can I fix this problem? It's a console application, Win32 and my IDE is Windows Enterprise C++ 2010.
I'm learning from Beginning C++ Through Game Programming.
Some compilers support case ranges like case x ... y as an extension to the C++ language.
Example:
#include <iostream>
using namespace std;
int main(){
int score;
//Vraag de score
cout << "Score:";
cin >> score;
//Switch
switch(score){
case 0:
cout << "a";
break;
case 0 ... 9:
cout << "b";
break;
case 11 ... 24:
cout << "c";
break;
case 25 ... 49:
cout << "d";
break;
case 50 ... 100:
cout << "e";
break;
default:
cout << "BAD VALUE";
break;
}
cout << endl;
return 0;
}
GCC 4.9, Clang 3.5.1 and Intel C/C++ Compiler 13.0.1 seem to support it (tried on http://gcc.godbolt.org/). On the other hand, Visual C++ 19 doesn't (tried on http://webcompiler.cloudapp.net/).
In C++ case labels are constant expressions, not expressions in general. You need a chain of if-then-else statements to do what you are trying to do.
Alternatively, you can enumerate the values in the switch. This runs marginally faster (though it does not matter in cases like yours), but it is considerably less readable:
switch(score) {
case 0: cout << "f"; break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10: cout << "e"; break;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25: cout << "c"; break;
// ...and so on, you get the idea...
}
You can fix this problem by using a series of if/else if statements. Switch/case cannot be used like this in C++.
It can be done using a std::map with switch:
enum Interval {
One,
Two,
Three,
NotFound };
// [0,10[ is One, [10,30[ is Two, [30,55[ is Three
std::map<int,Interval> imap {
{ { 0, One },
{ 10, Two },
{ 30, Three },
{ 55, NotFound } };
Interval ivalue = NotFound;
auto f = imap.lower_bound( value );
if( f != imap.end() ) ivalue = f->second;
switch( ivalue ) {
case One : ...
case Two : ...
case Three : ...
default: ...
}
Switch-case is not a great option for testing ranges. The best option is to use several if :
if (score<0) cout << "BAD VALUE";
if (score == 0) cout << "f";
if (score>0 && score<10) cout << "e";
if (score>=10 && score <25) cout << "d";
if (score>=25 && score <50) cout << "c";
if (score>=50 && score <100) cout << "b";
If running time is an issue, the following solution is faster :
if (score == 0) cout << "f";
else if (score<10) cout << "e";
else if (score <25) cout << "d";
else if (score <50) cout << "c";
else if (score <100) cout << "b";
else if (score>=100) cout << "a";
else cout << "BAD VALUE";
There's a GCC extension that does exactly what you want.
In C++ a switch statement can only match constant integer values:
switch (i)
{
case 1:
//... stuff
break;
case 2:
//... stuff
break;
default:
//... stuff
}
The standard does not allow for this:
6.4.2 The switch statement [stmt.switch]
[...] Any statement within the switch statement can be labeled with one or more case labels as follows:
case constant-expression :
where the constant-expression shall be an integral constant expression (5.19).
In other words, you can only use case-values that expand into a single, integral, "hard" compile time constant (e.g. case 5+6:, enum {X = 3}; ... case X*X:).
The way around this is to use if-statements. E.g., to replace
switch (x)
case 0..100:
you'd instead
if (x>=0 && x<=100)
.
std::map::upper_bound + C++11 lambdas
https://stackoverflow.com/a/35460297/895245 mentioned lower_bound, but we can also get rid of the enum there with lambdas (or inheritance if you don't have it).
#include <functional>
#include <iostream>
#include <map>
int main() {
std::string ret;
const std::map<int,std::function<void()>> m{
{0, [&](){ ret = "too small"; }},
{2, [&](){ ret = "[0,2)"; }},
{5, [&](){ ret = "[2,5)"; }},
{7, [&](){ ret = "[5,7)"; }},
};
const auto end = m.end();
for (auto i = -1; i < 8; ++i) {
auto it = m.upper_bound(i);
if (it == end) {
ret = "too large";
} else {
it->second();
}
std::cout << i << " " << ret << std::endl;
}
}
Output:
-1 too small
0 [0,2)
1 [0,2)
2 [2,5)
3 [2,5)
4 [2,5)
5 [5,7)
6 [5,7)
7 too large
Usage inside methods with static
To use this pattern efficiently inside classes, initialize the lambda map statically, or else you pay n log(n) every time to build it from scratch.
Here we can get away with the {} initialization of a static method variable: Static variables in class methods , but we could also use the methods described at: static constructors in C++? I need to initialize private static objects
It was necessary to transform the lambda context capture [&] into an argument, or that would have been undefined: const static auto lambda used with capture by reference
Example that produces the same output as above:
#include <functional>
#include <iostream>
#include <map>
#include <string>
class RangeSwitch {
public:
void method(int x, std::string &ret) {
static const std::map<int,std::function<void(std::string&)>> m{
{0, [](std::string &ret){ ret = "too small"; }},
{2, [](std::string &ret){ ret = "[0,2)"; }},
{5, [](std::string &ret){ ret = "[2,5)"; }},
{7, [](std::string &ret){ ret = "[5,7)"; }},
};
static const auto end = m.end();
auto it = m.upper_bound(x);
if (it == end) {
ret = "too large";
} else {
it->second(ret);
}
}
};
int main() {
RangeSwitch rangeSwitch;
std::string ret;
for (auto i = -1; i < 8; ++i) {
rangeSwitch.method(i, ret);
std::cout << i << " " << ret << std::endl;
}
}
That's simply not how switch works. It only takes single values. You'll have to use if-elseif blocks
I had the same problem with a score based problem and while the " if/elseif "statements were good to use, for intervals i found that the best option (for me at least because i like how it looks and it's easier for me as a beginner to see my mistakes) is " 1 ... 10 ". but don't forget to use a space between the number and the dots or the program will think that your interval is a number and u will get an error "2 many decimal dots...". Hope it helps.
int score;
int main()
{
cout<<"Enter score"<<endl;
cin>>score;
switch(score){
case 100:
cout<<"Your score is Perfect"<<endl;
break;
case 90 ... 99:
cout<<"You got A"<<endl;
break;
case 80 ... 89:
cout<<"You got B"<<endl;
break;
case 70 ... 79:
cout<<"You got C"<<endl;
break;
case 60 ... 69:
cout<<"You got D"<<endl;
break;
case 50 ... 59:
cout<<"You got E"<<endl;
break;
case 0 ... 49:
cout<<"You got F"<<endl;}
}
Switch case statements are a substitute for long if statements that compare a variable to several "integral" values ("integral" values are simply values that can be expressed as an integer, such as the value of a char). The condition of a switch statement is a value. The case says that if it has the value of whatever is after that case then do whatever follows the colon. The break is used to break out of the case statements.
Therefore, you cannot use such conditional statements in case.
The selective structure: switch
This is what worked for me. dividing the mark by 10 and then setting case 10 and 9 to display an "A"(this will display a "A" for any value between 90-100. Then case 8 to display "B", then case 7 will display a "C" for the values from 70-79 and so on.
#include <iostream>
using namespace std;
main ()
{
int mark;
cout << "enter your mark: ";
cin >> mark;
switch (mark/10)
{
case 10: case 9: cout << "A"; break;
case 8: cout << "B"; break;
case 7: cout << "C"; break;
case 6: cout << "D"; break;
case 5: cout << "PASS"; break;
default: cout << "FAIL"; break;
}
}
You can do the following:
//summarize the range to one value
If score < 0
score = -1
switch(score){
case 1:
//...
break;
case 2:
//...
break;
case -1: //complete neg. range
//...
break;
//...
}
Something like this?
case 'A'..'Z' where a not in ['I','L','O']:
Unfortunately no compiler I know of implements that particular extension, though GCC has can do ranges as other answers pointed out. For portability you can cut and paste this DWTFYW licensed snippet. If you're using a custom enum you might resort to code generation to make something similar.
#define CASE_NUMBER \
case'0':case'1':case'2':case'3':case'4':\
case'5':case'6':case'7':case'8':case'9'
#define CASE_ALPHA_LOWER \
case'a':case'b':case'c':case'd':\
case'e':case'f':case'g':case'h':\
case'i':case'j':case'k':case'l':\
case'm':case'n':case'o':case'p':\
case'q':case'r':case's':case't':\
case'u':case'v':case'w':case'x':\
case'y':case'z'
#define CASE_ALPHA_UPPER \
case'A':case'B':case'C':case'D':\
case'E':case'F':case'G':case'H':\
case'I':case'J':case'K':case'L':\
case'M':case'N':case'O':case'P':\
case'Q':case'R':case'S':case'T':\
case'U':case'V':case'W':case'X':\
case'Y':case'Z'
#define CASE_ALPHA CASE_ALPHA_UPPER:CASE_ALPHA_LOWER
#define CASE_ALPHANUM CASE_ALPHA:CASE_NUMBER
If you access to GHCI such as the online version at https://ghc.io/ you might just generate what you need and paste that into a header e.g.
foldl (++) "" ["case" ++ show x ++ ":" | x <- ['A'..'Z'], not $ x `elem` ['I','L','O']]
Here's a way which I hope is expressive and simple to follow.
You may be surprised by how far gcc/clang etc can optimise the code it generates. I would expect it to be at least as efficient as a switch/case.
#include <iostream>
template<class Value>
struct switcher
{
constexpr switcher(Value const& value) : value_(value) {}
constexpr switcher(Value const& value, bool enabled) : value_(value), enabled(enabled) {}
template<class From, class To, class F>
constexpr auto in_range(From&& from, To&& to, F&& f)
{
if (enabled and (from <= value_ and value_ <= to))
{
f();
return switcher(value_, false);
}
else {
return *this;
}
};
template<class F>
constexpr auto otherwise(F&& f)
{
if (enabled)
f();
}
Value const& value_;
const bool enabled = true;
};
template<class Value>
constexpr auto decision(Value const& value)
{
return switcher<Value>(value);
}
void test(int x)
{
decision(x)
.in_range(0, 10, [&] { std::cout << x << " maps to option A\n"; })
.in_range(11, 20, [&] { std::cout << x << " maps to option B\n"; })
.otherwise([&] { std::cout << x << " is not covered\n"; });
}
int main(int argc, char **argv) {
test(5);
test(14);
test(22);
}
A potentially useful insight is that switch accepts an expression, so you can fold multiple input values down to one switch case. It's a big ugly, but for consideration:
switch (score / 10)
{
case 10:
cout << "a";
break;
case 9: case 8: case 7: case 6: case 5:
cout << "b";
break;
case 4: case 3:
cout << "c";
break;
case 2:
if (score >= 25)
{
cout << "c";
break;
}
// else fall through...
case 1:
cout << "d";
break;
case 0:
cout << (score > 0 ? "e" : "f");
break;
default:
cout << "BAD VALUE";
break;
}
Of course, you could have divided by 5 and had case 4: (for 20-24) vs case 5: (25-29) rather than an if inside case 2:, but /10 is arguably more intuitive.
I know this is an old questiion, but since switch statements are in fact wrappers around labels, I find goto may be of (good) use here.
int value = 40;
if (value < 10) {
std::cout << "value < 10" << std::endl;
goto end;
}
if (value < 50) {
std::cout << "value < 50" << std::endl;
goto end;
}
if (value > 30) {
std::cout << "value > 30" << std::endl;
goto end;
}
end:
// resume
This way, you can omit all the elses and keep it compact.
You ought to be careful when using goto though (in general).

I'm in need of help checking my code. Any reviewing is greatly apreciated [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
This is the driver code provided by my instructor, It isn't meant to be edited by me.
PlayingCardTest.cpp:
#include <iostream>
#include "PlayingCard.h"
PlayingCard makeValidCard(int value, int suit);
int main()
{
// Create a playing card
PlayingCard card1;
// Test the default constructor and GetCardCode
std::cout << "Testing default constructor. Expect card code to be 00\n card code is :";
std::cout << card1.getCardCode() << std::endl << std::endl;
// Test the setter and getter
std::cout << "Seting card to 'AH' using SetValue and SetSuit" << std::endl;
card1.setCard('A', 'H');
std::cout << "GetValue returns :" << card1.getValue() << std::endl;
std::cout << "GetSuit returns :" << card1.getSuit() << std::endl << std::endl;
// Test overloaded constructor
PlayingCard tenOfSpades('T', 'S');
std::cout << "Testing overloaded constructor. Expect card code to be TS\n card code is :";
std::cout << tenOfSpades.getCardCode() << std::endl << std::endl;
// Test IsValid with valid cards
std::cout << "Testing valid card codes.\n"
<< "Expect isValid to return true for all (except perhaps Jokers.)"
<< std::endl;
// Create and test valid cards
int validCards = 0; // cards that return true for IsValid
int invalidCards = 0; // cards that return false for IsValid
// Create and test four suits plus the jokers
for(int suit = 1; suit <= 5; suit++)
{
// Create and test ace, 2 - 9, Jack, Queen, and King
for(int value = 1; value <= 13; value++)
{
PlayingCard aCard = makeValidCard(value, suit);
std::cout << "Card Code: " << aCard.getCardCode() << " IsValid :";
if (aCard.isValid())
{
validCards++;
std::cout << "true" << std::endl;
}
else
{
invalidCards++;
std::cout << "false" << std::endl;
}
// suit 5 is just for creating the two Jokers
if (suit == 5 && value >= 2)
break;
}
}
std::cout << "IsValid returned false for " << invalidCards << " card codes" << std::endl;
std::cout << "IsValid returned true for " << validCards << " card codes" << std::endl;
std::cout << std::endl;
// Test IsValid with invalid cards
// Create and test invalid cards
std::cout << "Testing invalid card codes; isValid should return false for all." << std::endl;
validCards = 0;
invalidCards = 0;
// Loop through all possible ASCII character codes for card codes
for(int suit = 0; suit <= 255; suit++)
for(int value = 0; value <= 255; value++)
{
// Only check card codes that are not valid
PlayingCard aCard = makeValidCard(value, suit);
if (aCard.getCardCode() == "00")
{
if (aCard.isValid())
{
std::cout << "value :" << value << " suit :" <<suit << " IsValid :";
std::cout << "true" << std::endl;
validCards++;
}
else
{
invalidCards++;
}
}
}
std::cout << "IsValid returned false for " << invalidCards << " card codes" << std::endl;
std::cout << "IsValid returned true for " << validCards << " card codes" << std::endl;
return 0;
}
/******************************************************/
/* Test Functions */
/******************************************************/
PlayingCard makeValidCard(int iValue, int iSuit)
{
char value = '0';
char suit = '0';
switch (iValue)
{
case 1:
value = 'A';
break;
case 10:
value = 'T';
break;
case 11:
value = 'J';
break;
case 12:
value = 'Q';
break;
case 13:
value = 'K';
break;
default:
if ((iValue >= 2) && (iValue <= 9))
value = '0' + iValue;
break;
}
switch (iSuit)
{
case 1:
suit = 'D';
break;
case 2:
suit = 'S';
break;
case 3:
suit = 'C';
break;
case 4:
suit = 'H';
break;
// Special case for the Joker
case 5:
if(iValue == 1)
{
value = 'Z';
suit = 'B';
}
else if(iValue == 2)
{
value = 'Z';
suit = 'R';
}
else
{
value = '0';
suit = '0';
}
break;
}
PlayingCard testCard(value, suit);
return testCard;
}
This is my header file, PlayingCard.h:
#ifndef PLAYINGCARD_H_INCLUDED
#define PLAYINGCARD_H_INCLUDED
class PlayingCard
{
private:
char suit, value;
public:
PlayingCard(){suit = '0'; value = '0';}
PlayingCard(char myValue, char mySuit);
char getValue() {return value;}
char getSuit() {return suit;}
std::string getCardCode();
bool setCard(char myValue, char mySuit);
bool isValid();
#endif // PLAYINGCARD_H_INCLUDED
And this is my class implementation file, PlayingCard.cpp:
#include "PlayingCard.h"
PlayingCard::PlayingCard (char myValue, char mySuit)
{
char aValue[13] ('2','3','4','5','6','7','8','9','T','J','Q','K','A'))
char aSuit[4] {'D','H','C','S']
for(count = 0; count <= 12; count++)
{
if (myValue = aValue[count])
{
for (count2 = 0; count2 <= 3; count2++)
{
if (mySuit = aSuit[count2++])
{
suit = mySuit;
value = myValue;
}
}
}
}
}
bool PlayingCard::setCard(char myValue, char mySuit)
{
char aValue[13] ('2','3','4','5','6','7','8','9','T','J','Q','K','A'))
char aSuit[4] {'D','H','C','S']
for(count = 0; count <= 12; count++)
{
if (myValue = aValue[count])
{
for (count2 = 0; count2 <= 3; count2++)
{
if (mySuit = aSuit[count2++])
{
suit = mySuit;
value = myValue;
}
else
{
return false;
}
}
}
}
}
string PlayingCard::getCardCode()
{
return suit + value;
}
bool PlayingCard::isValid()
{
char aValue[13] ('2','3','4','5','6','7','8','9','T','J','Q','K','A'))
char aSuit[4] {'D','H','C','S']
for(count = 0; count <= 12; count++)
{
if (myValue = aValue[count])
{
for (count2 = 0; count2 <= 3; count2++)
{
if (mySuit = aSuit[count2++])
{
return true;
}
else
{
return false;
}
}
}
}
}
And this is the compiler errors I'm getting. I'm not sure what to do, it looks like they are in the file I shouldn't edit. I would really appreciate help you can give.
PlayingCardTest.cpp|103|error: 'PlayingCard PlayingCard::makeValidCard(int, int)' cannot be overloaded|
PlayingCardTest.cpp|5|error: with 'PlayingCard PlayingCard::makeValidCard(int, int)'|
PlayingCardTest.cpp|169|error: expected '}' at end of input|
PlayingCardTest.cpp|169|error: expected unqualified-id at end of input|
||=== Build finished: 4 errors, 0 warnings ===|
You are missing }; at the end of your header file.
First round of comments:
Style nit: order sections "public", "protected", then "private". Private section should not go before public. This is not technically required, but is fairly standard practice.
Style nit: declare each variable using a separate statement, each on its own line. Using commas is a good way to get in trouble (e.g. when declaring pointer types) and is poor style.
Use an initialization list in the constructor rather than using the assignment operator.
You should include "<string>" in your header to use std::string.
Second round of comments:
You are initializing your arrays weirdly; you should use {} as the brackets.
You do not need to specify the size of the arrays in the initialization.
Style nit: do not use magic constants like "12" in your code. Instead, assign them to a variable such as value_length or value_count, and use the named variable.
Did you mean to do an equals comparison ("==") or an assignment ("=") in your if-statement? If you meant to do an assignment, you should probably move it outside of the if.
Third round of comments:
You unnecessarily duplicate code between your non-default constructor and your setCard function. You should be able to share code between those two functions. Since setCard is not a virtual function, you should be able to simply call it from your constructor.
Your setCard logic seems fairly complicated. Most "set" functions are much more trivial than that. You should consider adding documentation explaining the logic of what it is trying to do.
The "getValue()", "getCardCode()", "getSuit()", and "isValid()" functions should be declared "const".
Fourth round of comments:
Since your professor does "PlayingCard card = makeValidCard(....)", it is clear that he wants your card class to support assignment. Since your "setCard()" function and your non-default constructor do something other than simply set the attributes, it would make sense to provide a "PlayingCard& operator=(const PlayingCard&);" assignment operator as well as a "PlayingCard::PlayingCard(const PlayingCard&)" copy constructor. If you do not provide these, it is good practice to add a comment to the effect that copying using the default assignment / copy has been intentionally allowed.