noam hezrony noam hezrony - 1 month ago 9
C++ Question

i need help making this little c++ program work

Holy digits Batman! The Riddler is planning his next caper somewhere on Pennsylvania Avenue. In his usual sporting fashion, he has left the address in the form of a puzzle. The address on Pennsylvania is a four-digit number where:
• All four digits are different
• The digits in the thousandths place is three times the digit in the tens place
• The number is odd
• The sum of the digits is 27
Write a program that uses a loop (or loops) to find the address where the Riddler plans to strike.

I'm not so sure where the program is going wrong. any help will be appreciated.

#include <iostream>
using namespace std;

void splitAddress(int address, int thou, int hund, int tens, int ones) {
while (address >= 1000) {
address = address - 1000;
thou++;
}
while (address >= 100) {
address = address - 100;
hund++;
}
while (address >= 10) {
address = address - 10;
tens++;
}
while (address >= 1) {
address = address - 1;
ones++;
}
}
void areIntsTheSame(int address, int thou, int hund, int tens, int ones) {
if (thou == hund || thou == tens || thou == ones ||
hund == tens || hund == ones || tens != ones) {
address--;
}
}
void thou3tens(int address, int thou, int tens) {
if (thou != 3 * tens) {
address--;

}
void evenOrOdd(int address) {
if (address % 2 == 0) {
address--;
}

void Sum27(int address, int thou, int hund, int tens, int ones) {
if ((thou + hund + tens + ones) != 27) {
address--;


int main() {
int address = 9999;
int thou = 0;
int hund = 0;
int tens = 0;
int ones = 0;

splitAddress(address);
areIntsTheSame(address);
thou3tens(address);
evenOrOdd(address);
Sum27(address);

cout << "the address is " << address << endl;

system("pause");
return 0;
}


thanks in advance.

Answer

I think, it's quite easy to generate an int and then check if it matches the rules. But the address can be found faster if you consider some logical consequences of the rules:

Digit 4: is odd
Digit 3: is either 1 or 2 or 3! 
Digit 2: is even!
Digit 1: is Digit 3 multiplied by 3.

Of course, if you now generate an int by these rules, it's really hard to check its digits, so you could consider using a container like std::string instead. But this will get quite ugly, because you always need to add (and subtract) '0', in order to work with the digit as a digit. So I decided to go with std::vector<int> for your problem.

Before starting, I made a function that returns a random integer in a given range:

#include <random>

int random(int first, int last){
    std::random_device now;
    std::mt19937 engine(now());
    std::uniform_int_distribution<int> r(first,last);
    return r(engine);
}

With this, I implemented the "generator"

std::vector<int> generate_adress(){
    std::vector<int> address(4);
    address[3] = (random(0, 4) * 2) + 1; //last digit: odd number
    address[2] = random(1, 3);           //second digit: 1 or 2 or 3
    address[1] = random(0, 4) * 2;       //third digit: even number
    address[0] = address[2] * 3;         //last digit: second digit * 3

    return address;
}

With this, the only 2 things missing, are:

  • The digits must be 27 added together.

  • The digits need to be unique.

and that's done quite easily:

bool sum27(std::vector<int> address){
    int sum = address[0] + address[1] + address[2] + address[3];
    return sum == 27;
}

bool unique_digits(std::vector<int> address){
    for (int i = 0; i < address.size(); ++i){
        for (int j = 0; j < i; ++j){
            if (address[j] == address[i]) return false;
        }
    }
    return true;
}

I wrapped these 2 up into one convenient function:

bool valid_address(std::vector<int> address){
    return sum27(address) && unique_digits(address);
}

Now let's go to main() function and use the functions:

int main(){

    int ctr = 0;

    bool done = false;
    while (!done){
        ++ctr;
        std::vector<int> address = generate_adress();
        std::cout << "Adress #" << ctr << ": ";
        for (int i : address) std::cout << i; //print out address

        if (valid_address(address)){
            std::cout << " That's the address!" << std::endl;
            done = true;
        }
        else{
            std::cout << " not correct...\n";
        }
    }
    return 0;
}

Here is a run of the code:

Adress #72: 3617 not correct...
Adress #73: 6227 not correct...
Adress #74: 6823 not correct...
Adress #75: 6421 not correct...
Adress #76: 9831 not correct...
Adress #77: 9033 not correct...
Adress #78: 9439 not correct...
Adress #79: 9833 not correct...
Adress #80: 3815 not correct...
Adress #81: 3611 not correct...
Adress #82: 3415 not correct...
Adress #83: 6829 not correct...
Adress #84: 9637 not correct...
Adress #85: 3019 not correct...
Adress #86: 9635 not correct...
Adress #87: 6423 not correct...
Adress #88: 3613 not correct...
Adress #89: 6827 not correct...
Adress #90: 9233 not correct...
Adress #91: 3615 not correct...
Adress #92: 9639 not correct...
Adress #93: 9738 That's the address!

only 93 tries is quite good. If you would generate the address completely random, it takes way more time (obviously):

Adress #10054: 2333 not correct...
Adress #10055: 4057 not correct...
Adress #10056: 5753 not correct...
Adress #10057: 3901 not correct...
Adress #10058: 1149 not correct...
Adress #10059: 3029 not correct...
Adress #10060: 2378 not correct...
Adress #10061: 7777 not correct...
Adress #10062: 6870 not correct...
Adress #10063: 0187 not correct...
Adress #10064: 1720 not correct...
Adress #10065: 6101 not correct...
Adress #10066: 9738 That's the address!

10000 tries, though. Anyway, here's the full code:

#include <string>
#include <iostream>
#include <random>
#include <vector>

int random(int first, int last){
    std::random_device now;
    std::mt19937 engine(now());
    std::uniform_int_distribution<int> r(first,last);
    return r(engine);
}

std::vector<int> generate_adress(){
    std::vector<int> address(4);
    address[3] = (random(0, 4) * 2) + 1; //last digit: odd number
    address[2] = random(1, 3);           //second digit: 1 or 2 or 3
    address[1] = random(0, 4) * 2;       //third digit: even number
    address[0] = address[2] * 3;         //last digit: second digit * 3

    return address;
}

bool sum27(std::vector<int> address){
    int sum = address[0] + address[1] + address[2] + address[3];
    return sum == 27;
}

bool unique_digits(std::vector<int> address){
    for (int i = 0; i < address.size(); ++i){
        for (int j = 0; j < i; ++j){
            if (address[j] == address[i]) return false;
        }
    }
    return true;
}
bool valid_address(std::vector<int> address){
    return sum27(address) && unique_digits(address);
}

int main(){

    int ctr = 0;

    bool done = false;
    while (!done){
        ++ctr;
        std::vector<int> address = generate_adress();
        std::cout << "Adress #" << ctr << ": ";
        for (int i : address) std::cout << i; //print out address

        if (valid_address(address)){
            std::cout << " That's the address!" << std::endl;
            done = true;
        }
        else{
            std::cout << " not correct...\n";
        }
    }
    return 0;
}