It seems that what you're really attempting to do is to classify numbers. Further, these classifications are all mutually exclusive. That is, any given number can't pass both the sameDigitsTest
and also the increasingTest
.
So with that said, there are a couple different ways to approach this, depending on what you're really trying to do:
Consolidate into a single boolean function
One would be to put everything into single function isBouncy
:
bool isBouncy(int number) {
if (sameDigitsTest(number) || decreasingTest(number) ||
increasingTest(number) )
return false;
return bouncyTest(number);
}
I'm leaving in all of the other tests because I'm assuming it's much faster to do those other rejecting tests first and then only call the presumably much more computationally complex bouncyTest
with possible candidate numbers. I'm also assuming that in the end, the only thing of interest is whether the number is bouncy or not and that you're not really interested in the other classifications.
Create a single classifier function
If that's not the case, and you actually want to keep the classifications, you should use an enum
or even better a C++11 enum class
instead of a raw int
.
enum class NumberClassification { BORING, SAMEDIGITS, DECREASING, INCREASING, BOUNCY };
NumberClassification classify(int number) {
if (sameDigitsTest(number))
return NumberClassification::SAMEDIGITS;
if (decreasingTest(number))
return NumberClassification::DECREASING;
if (increasingTest(number))
return NumberClassification::INCREASING;
if (decreasingTest(number))
return NumberClassification::BOUNCY;
return NumberClassification::BORING;
}
As you can see, however, this maintains the same repeating if
structure as your original code.
Use a collection of test functions
Another option would be to use a collection of test functions. In plain old C we would use an array, but we can do better in C++ by using a std::vector
:
static std::vector<int (*)(int)> tests{ sameDigitsTest, decreasingTest,
increasingTest, bouncyTest };
int classify(int number) {
for (unsigned i = 0; i < tests.size(); ++i)
if (tests[i](number))
return i+1;
return 0;
}
Create a C++ object
Yet another option would be to create an object to encapsulate all of this into an object. A very rudimentary approach might be something like this:
class Classifier {
public:
Classifier(int number) : n(number), classification(classify(n)) {}
bool isBouncy() const {
return classification == 4; // 4 is the bouncyTest
}
private:
static std::vector<int (*)(int)> tests;
int n;
int classification;
static int classify(int &number) {
for (unsigned i = 0; i < tests.size(); ++i)
if (tests[i](number))
return i+1;
return 0;
}
};
std::vector<int (*)(int)> Classifier::tests{ sameDigitsTest, decreasingTest,
increasingTest, bouncyTest };
You could use it like this:
Classifier c(234);
if (c.isBouncy())
bouncyCounter++;
Of course this isn't a very good class because one can't add new tests and there is not a strong linkage between the classification and the number returned by classify
. One could improve both by adding to this class, but I'll leave that for you to explore.
variable
is not a good name for a variable \$\endgroup\$