Search code examples
cs50vigenere

CS50x 2019 pset2: Vigenère does not fully work


I am currently working on the pset2 of CS50x 2019, specifically on Vigenère. The CS50 Gradebook shows me 93% finished after uploading it to GitHub.

I have already tried some other code snippets that you can find online but they did not seem to work.

Here is the part of my program that creates the ciphertext:

    string k = argv[1];
    // Get the plaintext and print out the ciphertext
    string s = get_string("plaintext: ");
    printf("ciphertext: ");

    // Iterate through plaintext letter by letter
    for (int i = 0, n = strlen(s) ; i < n; i++)
    {
        int key = tolower(k[i % strlen(k)]) - 'a';

        // Check if the letter is lowercase, uppercase or neither and print out the rotated character
        if (islower(s[i]))
        {
            printf("%c", (((s[i] - 'a') + key) % 26) + 'a');
        }
        else if (isupper(s[i]))
        {
            printf("%c", (((s[i] - 'A') + key) % 26) + 'A');
        }
        else
        {
            printf("%c", s[i]);
        }
    }

    printf("\n");
    return 0;

There are some examples in the documentation which you can test out with your code.

The following example does not work with my code:

$ ./vigenere bacon
plaintext:  Meet me at the park at eleven am
ciphertext: Negh zf av huf pcfx bt gzrwep oz

My output is:

$ ./vigenere bacon
plaintext: Meet me at the park at eleven am
ciphertext: Negh ne og tjs qaty bt syfvgb bm

As you can see, the first 4 characters are correct but the remaining are not.


Solution

  • This int key = tolower(k[i % strlen(k)]) - 'a'; is a problem.

    From the spec:

    Remember also that every time you encipher a character, you need to move to the next letter of k, the keyword (and wrap around to the beginning of the keyword if you exhaust all of its characters). But if you don’t encipher a character (e.g., a space or a punctuation mark), don’t advance to the next character of k!

    The bottom line is: since plaintext and key run at different "rates" you cannot use the same index (in this case i) for both. The program should crawl plaintext one character at a time, as is done here. But it needs a separate way to control the character in key so you can 1) skip spaces/punctuation and 2) wrap around. Another variable for the key index would be one way to solve it. There may be other problems in the code, but this is a fundamental flaw.