Generating a random 4 character string and then cracking it

Hey, I'm just coming over to C++ from Python (where stuff like this is incomprehensibly simple) and am trying to figure out how to approach this problem.

I want to generate a string of uppercase characters of length 4. This string, P, will then be passed as a parameter to CrackP(), which will use four loops to try every possible combination of uppercase letters AAAA to ZZZZ until P has been cracked. CrackP() will also return the number of attempts N needed to crack P. Here is my current 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
#include <iostream>
#include <string>



const char Characters[26] =
        {
                'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N',
                'O', 'P', 'Q', 'R', 'S', 'T', 'U',
                'V', 'W', 'X', 'Y', 'Z'
        };

std::string P;

int GenChar()
{

};

int CrackP() 
{
    
};


int main()
{
    std::cout << "Attempting to crack...\n";
    std::cout << Characters;

    return 0;
}




I'm not asking for a complete solution, but since I'm new to C++ and know almost nothing about its standard library, being pointed in the right direction would be nice.
Last edited on

Here's some notes:

1. Global variables are usually frowned upon in C++ and Python. I would move your string P to main(). To pass parameters to a function, you do something like this:

1
2
3
4
5
6
7
8
9
int CrackP(std::string P) 
{

}
int main()
{
    std::string P;
    CrackP(P);
}


2. Randomness is a bit more complicated to set up in C++ than Python, but you can make the end result almost as nice.
You can use the old method, rand() in <cstdlib>, for most simple purposes, but for modern C++ randomness, you want to use the <random> functionality.

Here's how to do generate a random number between 0 and 25, inclusive, using rand()
1
2
3
4
5
6
7
8
9
#include <cstdlib>
#include <ctime>

int main()
{
    srand(time(nullptr)); // set random seed (based on current computer time)
    
    int rand_rum = rand() % 26; // [0, 25] range
}


Here's how you would create a random number using C++11 <random>.

1
2
3
4
5
6
7
8
9
#include <random>

int main()
{
    std::default_random_engine generator;
    std::uniform_int_distribution<int> random_number(0, 25);

    int rand_rum = random_number(generator); // [0, 25] range
}



3. For loops

1
2
3
for i in range(0, 26):
   for j in range(0, 26):
        // stuff 


is equivalent to

1
2
3
4
5
6
7
for (int i = 0; i < 26; i++)
{
    for (int j = 0; j < 26; j++)
    {
        // stuff
    }
}


4. Function definitions do not need semi-colons at the end of them. They can be removed.

1
2
3
4
int GenChar()
{

} // no semi-colon  


Edit: Reading your post again, I realize you never actually said you wanted to randomly generate anything. But anyway, it's available if you choose to do so.
Last edited on
@Ganado, this is great. I actually do want to randomly generate a string. How can I loop over my character array to do so?
Might be a good idea to create a function to create a random upper char
Based on Ganado's code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char RandomUpperChar()
{
  const string characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  static std::default_random_engine generator;
  static std::uniform_int_distribution<int> random_number(0, 25);

  int rand_num = random_number(generator); // [0, 25] range

  return characters[rand_num];

  // OR

  //return rand_num + 'A';
}
@Thomas1965

I used that code example, and on execution, I see the following output:

0

This is unexpected behavior. When I change the value of the first parameter in `random_number`, the output then becomes some single character in the string `character` depending on the first parameter in `random_number`.

For example, the following code produces "R" as the output:

<int> random_number(3, 25);

Do you know why this is happening?


Last edited on
you need to seed the engine.

in your fist case, ¿are you sure that you see a 0 (zero)? post your full code in that case.
Yes, I get the value 0. Here is the full 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
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <random>


std::string P;

int GenChar()
{

};

int CrackP()
{

};
char RandomUpperChar()
{
    const std::string characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    srand(time(nullptr)); // set random seed (based on current computer time)
    static std::default_random_engine generator;
    static std::uniform_int_distribution<int> random_number(0, 25);

    int rand_num = random_number(generator); // [0, 25] range
    std::cout << characters[rand_num];
    std::cout << rand_num;
    return characters[rand_num];

    // OR

    //return rand_num + 'A';
}

int main()
{
    RandomUpperChar();
    return 0;
}
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
#include <iostream>
#include <string>
#include <random>

const std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
const std::size_t NCHARS = 6 ; // adjust as required (to about less than 8 or so)
// (caveat: obvious combinatorial explosion for larger values)

#define NDEBUG // uncomment to trace the progress (use a very small value for NCHARS)

std::string random_string( std::size_t sz )
{
    static std::mt19937 twister( std::random_device{}() ) ;
    static std::uniform_int_distribution<std::size_t> distrib( 0, alphabet.size() - 1 ) ;

    std::string result ;
    while( result.size() < sz ) result += alphabet[ distrib(twister) ] ;
    return result ;
}

bool is_cracked( const std::string& candidate )
{
    static const std::string target = random_string(NCHARS) ;
    /* [[maybe_unused]] */ static const auto& unused = std::cout << "target: '" << target << "'\n" ;

    #ifndef NDEBUG
        std::cout << "candidate: '" << candidate << "'\n" ;
    #endif // NDEBUG

    return candidate == target ;
}

// brute force (try all possibilities in lexicographic order)
bool try_crack( std::string prefix = "" )
{
    if( prefix.size() == NCHARS ) return is_cracked(prefix) ;

    prefix += ' ' ; // add one more character to prefix
    for( char c : alphabet )
    {
        prefix.back() = c ; // one by one, try every possible character
        if( try_crack(prefix) )
        {
            if( prefix.size() == NCHARS ) std::cout << " found: '" << prefix << "'\n" ;
            return true ;
        }
    }

    return false ;
}

int main()
{
    try_crack() ;
}

http://coliru.stacked-crooked.com/a/7cf1d6cb1fc48a2a

JLBorges,

I don't want to copy code. I'm asking for pointers on mine.
There are several pointers that can be picked up if you care to read the code.

If that is something that you do not want to do, just ignore my post.
I guess your Zero is actually O
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
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <random>

using namespace std;

char RandomUpperChar()
{
  const string characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  static std::default_random_engine generator;
  static std::uniform_int_distribution<int> random_number(0, 25);

  int rand_num = random_number(generator); // [0, 25] range

  return characters[rand_num];
}

int main()
{
  for (int i = 0; i < 15; i++)
  {
    cout << RandomUpperChar() << "\n";
  }
}


A
O
O
P
U
H
N
P
K
P
J
V
C
K
H


Might be easier to stick to rand() for the beginning. Just remember to call srand only once.
> #define NDEBUG // uncomment to trace the progress
that should be comment to trace the progress.

1
2
3
4
bool is_cracked( const std::string& candidate )
{
    static const std::string target = random_string(NCHARS) ;
    /* [[maybe_unused]] */ static const auto& unused = std::cout << "target: '" << target << "'\n" ;
awful trick to have that where it doesn't belong.
Last edited on
Topic archived. No new replies allowed.