bool and vector functions help

Pages: 12
Oct 31, 2020 at 2:33am
A user should be able to input a 4-digit number that satisfies the following:
--each digit is unique
--the tens place is three times the thousands place
--an odd number
--the sum of each digit is 27

the different_number(int number) function is a bit wonky.
sometimes when I enter 1231, the program accepts instead of giving an error message

I also want to use the vector function if it's a better way. Maybe I can use it in different_numbers, three_times, and sum_number

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

#include <iostream>
#include <cmath>
#include <string>
#include <vector>

using namespace std;

void Ch3_Programming_Project_13();

vector<int> separate_number(int number);

bool different_numbers(int number);
bool three_times(int number);
bool odd_number(int number);
int sum_number(int number);
int inputInteger(string prompt, int startRange, int endRange);

int main(){
    Ch3_Programming_Project_13();
    return 0;
}
  
void Ch3_Programming_Project_13(){
    // correct answer is 9738 || 9837

    int address_number = inputInteger("Guess an address number: ", 1000,9999);

    while (!different_numbers(address_number) || !three_times(address_number) || !odd_number(address_number) || sum_number(address_number) != 27){
        cout << "Sum of the guess: " << sum_number(address_number) << endl << endl;

        // just to check
        if (!different_numbers(address_number)) 
            cout << "Each digit must be unique" << endl;
        if (!three_times(address_number))
            cout << address_number << " != tens*3==thousands" << endl;
        if(!odd_number(address_number)) 
            cout << address_number << " != odd number" << endl;
        if (sum_number(address_number) != 27) 
            cout << "Sum of the guess must be 27" << endl << endl;

        cout << "Incorrect guess." << endl << endl;
        address_number = inputInteger("Guess an address number: ", 1000,9999);
    }
    
    cout << "Sum of the guess: " << sum_number(address_number) << endl;
    cout << "The correct address number: " << address_number << endl;
}

// this could be used for different_numbers, three_times, and sum_number
vector<int> separate_number(int number){
    vector<int> temp_arr;
    temp_arr[0] = (number / 100) % 10; // ones
    temp_arr[1] = (number / 10) % 10;  // tens
    temp_arr[2] = number % 10;         // hundreds
    temp_arr[3] = number / 1000;       // thousands

    return temp_arr;
}

// different_numbers is a bit wonky.
bool different_numbers(int number){
    int temp_arr[4];
    temp_arr[0] = (number / 100) % 10; // ones
    temp_arr[1] = (number / 10) % 10;  // tens
    temp_arr[2] = number % 10;         // hundreds
    temp_arr[3] = number / 1000;       // thousands

    return temp_arr[0] != temp_arr[1] != temp_arr[2] != temp_arr[3];
}

bool three_times(int number){
    // find thousands place
    int thousands = number / 1000;
    // find tens place
    int tens = (number / 10) % 10;

    return tens*3==thousands;
}

bool odd_number(int number){
    return number%2==0;
}

int sum_number(int number) {
	int sum_number = 0;
	while (number > 0) {
		sum_number += number % 10;
		number /= 10;
	}
    
	return sum_number;
}

int inputInteger(string prompt, int startRange, int endRange) {

    int input;
    do {
        cout << prompt;
        if (!(cin >> input)) {
            cout << "ERROR-3A: Invalid input. Must be an integer type.\n";
            cin.clear();
            cin.ignore(999, '\n');
        }
        else if (!(input >= min(startRange, endRange) && input <= max(startRange, endRange)))
            cout << "ERROR-3A: Invalid input. Must be from " << startRange << "..." << endRange << ".\n";
        else
            break;
    } while (true);
    return input;
}

Last edited on Oct 31, 2020 at 2:42am
Oct 31, 2020 at 4:46am
I am not sure line 69 does what you think it does.
Its late and I get mixed up on the rules for weird expression evaluations, but if its not working, try writing it another way.

yes, you can split the number one time and reuse that work. I am not sure ones tens hundreds and thousands are all exactly right, though.
ones is x %10
... you have them out of order.
Last edited on Oct 31, 2020 at 4:48am
Oct 31, 2020 at 5:39am
@jonnin thank you for your response.

Thank you for pointing out that the digit separation was a bit off.

I've changed the line 69 into the following:
1
2
3
4
5
6
return temp_arr[0] != temp_arr[1] || 
           temp_arr[0] != temp_arr[2] || 
           temp_arr[0] != temp_arr[3] ||
           temp_arr[1] != temp_arr[2] ||
           temp_arr[1] != temp_arr[2] ||
           temp_arr[2] != temp_arr[3];

^I've also tried other variations. it's not working.

I also just realized that my odd_number function is incorrect. I changed the return to:
 
return number%2!=0;


Let's say I want to split the number once and just reuse the work, how do I go about that? I've tried the following, but i got an error:
 
for(auto i : separate_number(address_number)) cout << i << " " ;
Last edited on Oct 31, 2020 at 5:40am
Oct 31, 2020 at 5:58am
FWIW: Obviously not yours but I had a play around with this. According to this there is only one number that satisfies all the conditions.

Substituting C-arrays for <vector>'s is very easy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>

int main()
{
    const int NO_OF_DIGITS{4};
    int digits[NO_OF_DIGITS];
    
    int digit;
    bool acceptable_number = false;
    
    int sum_of_digits{0};
    
    int checker[10];
    
    while(std::cout << "Enter 4 digit number: " && acceptable_number == false)
    {
        std::cin >> digit;
        
        acceptable_number = true;
        if(digit < 1000 or digit > 9999 )
        {
            acceptable_number = false;
            std::cout << "Not a 4-digit number\n";
        }
        
        for(int i = 0; i < 10; i++)
        checker[i] = -1;
        
        sum_of_digits = 0;
        for(int i = 0; i < NO_OF_DIGITS; i++)
        {
            digits[i] = digit % 10;
            
            sum_of_digits += digits[i];
            
            if(checker[digits[i]] >= -1)
                checker[ digits[i] ] = -74;
            else
            {
                acceptable_number = false;
                std::cout << "Digits duplicated\n";
            }
            
            digit /= 10;
        }
        
        // DISPLAY DIGITS
        for(int i = NO_OF_DIGITS - 1; i >= 0; i--)
        std::cout << digits[i] << ' ';
        
        if(digits[1] != 3*digits[3])
        {
            acceptable_number = false;
            std::cout << "10's != 3*1000's\n";
        }
        
        if(digits[0] % 2 == 0)
        {
            acceptable_number = false;
            std::cout << "Not an oddnumber\n";
        }
        
        if(sum_of_digits != 27)
        {
            acceptable_number = false;
            std::cout << "Digit sum != 27\n";
        }
        
        if(acceptable_number == true)
            std::cout << "Number accepted\n";
        else
            std::cout << "Number rejected ... Try again\n";
    }
    
    return 0;
}
Oct 31, 2020 at 8:47am
--the tens place is three times the thousands place



From the given 2 correct answers (9738 || 9837), do you mean the thousands place is three times the tens place (9 is 3x 3)?
Oct 31, 2020 at 9:14am
1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;

int main()
{
   int n;
   cout << "Enter a four-digit number: ";   cin >> n;
   cout << ( n == 3897 ? "Yes" : "No" );
}


It would be a lot more interesting if there were 5 digits.
Last edited on Oct 31, 2020 at 9:17am
Oct 31, 2020 at 9:35am
--the tens place is three times the thousands place

9738 isn't allowed because it's an even number, so 9837 is the sole answer with that way of looking at the '3 times' test.

The alternative, which my interpretation codes, gives the sole answer of 3897.
( tens_place = 3 * thousands_place, ie 3897 ie 9 = 3*3 )
Oct 31, 2020 at 9:39am
It definitely would be more fun with 5 (or more) digits!
Oct 31, 2020 at 10:10am
cout << ( n == 3897 ? "Yes" : "No" ); How cruel is that for a one-liner? :)
Oct 31, 2020 at 10:14am
Fulfillls the requirement for testing the entered number! :)
Oct 31, 2020 at 10:46am
To return to the original OP post:

return temp_arr[0] != temp_arr[1] != temp_arr[2] != temp_arr[3];
I can't actually work out what that will return ... but it definitely isn't right!

I suspect the quickest way would just be to construct a set (hence, no duplicates) and check that its size was 4. Something like
return set<int>( temp_arr, temp_arr+4 ).size() == 4;
Alternatively, keep a bool or int array (as @againtry's code) to tick off the digits already used.
Last edited on Oct 31, 2020 at 11:08am
Oct 31, 2020 at 11:14am
I tried it and there is nothing useful.
IIRC the word is transitive and the string of != 's doesn't make it. set's solve that.
Oct 31, 2020 at 11:16am
BTW I tried 5 digit numbers under the same rules and there were no acceptable numbers which is a surprise.
Oct 31, 2020 at 11:35am
5-digit ones (I think!)
83691
63891
83295
63495
43695
23895
63297
23697
92763
72963
32967
92367
42867
82467
32769
72369
61839
81639
Might be some more. These were done by hand.
Oct 31, 2020 at 11:36am
For an alternative 'take':

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <cctype>
#include <iterator>

int main()
{
	enum errs {OK = 0, DUPDIG, TOOFEW, TOOMANY, NOTNUM, BADNUM, NOTODD, BADTENS};
	const char* errmsg[] {"OK!", "Duplicate digit", "Too few digits", "Too many digits", "Not a number", "Incorrect digit sum", "Not an odd number", "Tens not 3 times thousands"};
	constexpr size_t nodigits {4};
	constexpr size_t total {27};

	char ch {};
	int digits[nodigits] {};
	size_t sum {}, nod {};
	int err {OK};

	static_assert (BADTENS == std::size(errmsg) - 1);

	std::cout << "Enter number to check: ";

	for (bool dup[10] {}; !err && (ch = std::cin.get()) != '\n' && nod < nodigits && std::isdigit(ch); dup[digits[nod++]] = true) {
		sum+= (digits[nod] = ch - '0');
		err = dup[digits[nod]] == true;
	}

        err += (!err && ch == '\n' && nod < nodigits) * TOOFEW;
	err += (!err && std::isdigit(ch) && nod == nodigits) * TOOMANY;
	err += (!err && (ch != '\n' || nod != nodigits)) * NOTNUM;
	err += (!err && sum != total) * BADNUM;
	err += (!err && digits[nodigits - 1] % 2 == 0) * NOTODD;
	err += (!err && digits[nodigits - 4] != 3 * digits[nodigits - 2]) * BADTENS;

	std::cout << errmsg[err] << '\n';
}

Last edited on Oct 31, 2020 at 1:54pm
Oct 31, 2020 at 12:21pm
I found my blooper, the limits weren't reset to extend to 5 digits .


23697
23895
32769
32967
42867
43695
61839
63297
63495
63891
72369
72963
81639
82467
83097
83295
83691
92367
92763
Program ended with exit code: 0
Oct 31, 2020 at 12:26pm
The error messages beat spag-code. try-catch exceptions would be the pinnacle.

Maybe 4-digit numbers are the only ones that give a single answer - 3, 2 and 1 won't give 27.
Oct 31, 2020 at 12:33pm
FWIW:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>

int main()
{
    const int NO_OF_DIGITS{5};
    int digits[NO_OF_DIGITS];
    
    int digit;
    bool acceptable_number = false;
    
    int sum_of_digits{0};
    
    int checker[10];
    
    for(int it = 10235; it < 98765; it+=2)
    {
        digit = it;
        acceptable_number = true;
        
        for(int i = 0; i < 10; i++)
        checker[i] = -1;
        
        sum_of_digits = 0;
        for(int i = 0; i < NO_OF_DIGITS; i++)
        {
            digits[i] = digit % 10;
            
            sum_of_digits += digits[i];
            
            if(checker[digits[i]] >= -1)
                checker[ digits[i] ] = -2;
            else
                acceptable_number = false;
            
            digit /= 10;
        }
        
        if(digits[1] != 3*digits[3])
            acceptable_number = false;
        
        //if(digits[0] % 2 == 0)
            //acceptable_number = false;
        
        if(sum_of_digits != 27)
            acceptable_number = false;
        
        if(acceptable_number == true)
            std::cout << it << '\n';
    }
    
    return 0;
}
Last edited on Oct 31, 2020 at 12:37pm
Oct 31, 2020 at 3:04pm
Looking at 4, 5, 6, 7, 8 & 9 digits, and allowing leading 0, the count of the numbers that satisfy the conditions are:


4 digits have 1 number(s)
5 digits have 20 number(s)
6 digits have 168 number(s)
7 digits have 456 number(s)
8 digits have 0 number(s)
9 digits have 0 number(s)


Based upon my previous code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <cctype>
#include <iterator>
#include <string>
#include <sstream>
#include <iomanip>
#include <vector>
#include <cmath>

int main()
{
	enum errs { OK = 0, DUPDIG, TOOFEW, TOOMANY, NOTNUM, BADNUM, NOTODD, BADTENS };
	const char* errmsg[] {"OK!", "Duplicate digit", "Too few digits", "Too many digits", "Not a number", "Incorrect digit sum", "Not an odd number", "Tens not 3 times thousands"};
	constexpr size_t total {27};
	constexpr size_t startnum {1035};

	constexpr size_t maxdigits {9};

	static_assert (BADTENS == std::size(errmsg) - 1);

	for (size_t nodigits = 4; nodigits <= maxdigits; ++nodigits) {
		size_t cnt {};

		for (size_t n = startnum, maxnum = std::pow(10, nodigits) - 1; n < maxnum; n += 2) {
			std::string sno {std::to_string(n)};
			std::stringstream iss;

			iss << std::setw(nodigits) << std::setfill('0') << sno << '\n';
			iss.seekg(0);

			char ch {};
			std::vector<int> digits(nodigits);
			size_t sum {}, nod {};
			int err {OK};

			for (bool dup[10] {}; !err && (ch = iss.get()) != '\n' && nod < nodigits && std::isdigit(ch); dup[digits[nod++]] = true) {
				sum += (digits[nod] = ch - '0');
				err = dup[digits[nod]] == true;
			}

			//err += (!err && ch == '\n' && nod < nodigits) * TOOFEW;
			//err += (!err && std::isdigit(ch) && nod == nodigits) * TOOMANY;
			//err += (!err && (ch != '\n' || nod != nodigits)) * NOTNUM;
			err += (!err && sum != total) * BADNUM;
			//err += (!err && digits[nodigits - 1] % 2 == 0) * NOTODD;
			err += (!err && digits[nodigits - 4] != 3 * digits[nodigits - 2]) * BADTENS;

			if (err == 0) {
				//std::cout << std::setw(nodigits) << std::setfill('0') << n << '\n';
				++cnt;
			}
		}

		std::cout << nodigits << " digits have " << cnt << " number(s)\n";
	}
}

Last edited on Oct 31, 2020 at 4:35pm
Oct 31, 2020 at 6:05pm
Oh, I actually meant: The digit in the thousands place is three times the digit in the tens place
so I think return tens*3==thousands; is right and 9837 is the correct answer

Since I wanted to reuse the vector function, I just used
1
2
auto dif = unique(temp_arr.begin(), temp_arr.end());
    return dif==temp_arr.end();
though the unique doesn't work quite as good as set

I came about this article that shows how to use a function that returns a static array (but i don't know much about pointers)
1
2
3
4
5
6
7
8
9
10
int *sep_num(int number){
    static int temp_arr[4] = {
        (number % 10),       // ones
        (number / 10) % 10,  // tens
        (number / 100) % 10, // hundreds
        (number / 1000)      // thousands
    };

    return temp_arr;
}
^so I used that here:
1
2
3
4
bool different_numbers(int number){  
    int *temp_arr = sep_num(number);
    return set<int>( temp_arr, temp_arr+4 ).size() == 4;
}
but what do you know it tells me that even 1235 is not a unique number

I reused the same function in sum_number:
1
2
3
4
5
6
7
int sum_number(int number) {
    int sum_number = 0;
    int *temp_arr = separate_number(number);
    for(int i = 0; i < 4; i++) sum_number += *(temp_arr + i);
    
	return sum_number;
}


I really just want to practice reusing a function wherever it can be reused. I want to learn how to reuse it in different_numbers first and then three_times
Last edited on Oct 31, 2020 at 6:24pm
Pages: 12