Ceasar Cipher Project - Why do I need this modulo?

In the extensions section for this project it has you create a method for decryption. I copied and pasted most of what I had for encryption, but needed to alter the calculation to get the index of the decrypted character. Here’s my code.

namespace CaesarCipher
{
  class Program
  {
    static void Main(string[] args)
    {
      // Determining if user wants to encrypt or decrypt.
      Console.WriteLine("Chose One: Encrypt / Decrypt");
      string encryptDecrypt = Console.ReadLine();
      string lowerEncryptDecrypt = encryptDecrypt.ToLower();
      if (lowerEncryptDecrypt == "encrypt")
      {
        // Taking user input to encrypt and converting to lower.
        Console.WriteLine("Enter a message to encrypt.");
        string unencryptedMessage = Console.ReadLine();
        string lowerUnencryptedMessage = unencryptedMessage.ToLower();
        // Taking user input for cipher value and parsing as int.
        Console.WriteLine("Enter a value for the cipher.");
        int cipherValue = Int16.Parse(Console.ReadLine());
        // Converting user input to array.
        char[] secretMessage = lowerUnencryptedMessage.ToCharArray();
        // Calling Encrypt() with user input and printing result to console.
        Console.WriteLine(Encrypt(secretMessage, cipherValue));
      } else if (lowerEncryptDecrypt == "decrypt")
      {
        // Taking user input to encrypt and converting to lower.
        Console.WriteLine("Enter a message to decrypt.");
        string msgToDecrypt = Console.ReadLine();
        string lowerMsgToDecrypt = msgToDecrypt.ToLower();
        // Taking user input for cipher value and parsing as int.
        Console.WriteLine("Enter a value for the cipher.");
        int cipherValue = Int16.Parse(Console.ReadLine());
        // Converting user input to array.
        char[] secretMessage = lowerMsgToDecrypt.ToCharArray();
        // Calling Decrypt() with user input and printing result to console.
        Console.WriteLine(Decrypt(secretMessage, cipherValue));
      } else
      {
        Console.WriteLine("That is not a valid choice. Please restart.");
      }
    }
    // Creating encryption method.
    static string Encrypt(char[] secretMessage, int cipherValue)
    {
      // Array to reference letter position.
      char[] alphabet = new char[] {'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'};
      // Empty array to hold encrypted message.
      char[] encryptedMessage = new char[secretMessage.Length];
      // Loop to encrypt each letter (skipping symbols) and add to previously empty array.
      for (int i = 0; i < secretMessage.Length; i++)
      {
        char unencryptedLetter = secretMessage[i];
        if (Char.IsLetter(unencryptedLetter) == true)
        {
          int unencryptedAlphabetPosition = Array.IndexOf(alphabet, unencryptedLetter);
          int encryptedAlphabetPosition = (unencryptedAlphabetPosition + cipherValue) % 26;
          char encryptedLetter = alphabet[encryptedAlphabetPosition];
          encryptedMessage[i] = encryptedLetter;
        } else {
          encryptedMessage[i] = unencryptedLetter;
        }
      }
      // Converting encrypted message array into string and returning outside method.
      string encryptedMessageResult = string.Join("", encryptedMessage);
      return encryptedMessageResult;
    }
    // Creating decryption method.
    static string Decrypt(char[] secretMessage, int cipherValue)
    {
      // Array to reference letter position.
      char[] alphabet = new char[] {'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'};
      // Empty array to hold decrypted message.
      char[] encryptedMessage = new char[secretMessage.Length];
      // Loop to decrypt each letter (skipping symbols) and add to previously empty array.
      for (int i = 0; i < secretMessage.Length; i++)
      {
        char unencryptedLetter = secretMessage[i];
        if (Char.IsLetter(unencryptedLetter) == true)
        {
          int unencryptedAlphabetPosition = Array.IndexOf(alphabet, unencryptedLetter);
          int encryptedAlphabetPosition = (unencryptedAlphabetPosition + (26 - (cipherValue % 26))) % 26;
          char encryptedLetter = alphabet[encryptedAlphabetPosition];
          encryptedMessage[i] = encryptedLetter;
        } else {
          encryptedMessage[i] = unencryptedLetter;
        }
      }
      // Converting decrypted message array into string and returning outside method.
      string encryptedMessageResult = string.Join("", encryptedMessage);
      return encryptedMessageResult;
    }
  }
}

The code works, but I can’t figure out why I need the second modulo on this line.

          int encryptedAlphabetPosition = (unencryptedAlphabetPosition + (26 - (cipherValue % 26))) % 26;

When I use a cipher of 2567 the code works as is, but if I remove the second modulo and use the same cipher I get a index out of bounds error. However running “(1 + (26 - (2567 % 26)))” and “(1 + (26 - (2567 % 26))) % 26” through Google both yield “8”.

Can someone please explain what the second modulo is doing for me?

You’re right, if you use the second modulo thus: (1 + (26 - (2567 % 26))) % 26, by virtue of the parenthesis it is redundant. So the question is, do you need it, or are the parenthesis misplaced?

If it’s not clear why you need an equation, I would try to model it on a smaller scale to see how each operation is derived and how it may vary under different conditions.

It’s not as much that I don’t know why I need the equation for the code, its why the code only runs correctly with the second modulo. I agree with you that the second one should be redundant, but to the code it isn’t. If I leave it redundant, it runs correctly. If I remove that piece that should be redundant, I get errors.

ok! What are the errors then? That should give a clue.

Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
at CaesarCipher.Program.Decrypt(Char secretMessage, Int32 cipherValue) in /home/ccuser/workspace/csharp-caesar-cipher/Program.cs:line 84
at CaesarCipher.Program.Main(String args) in /home/ccuser/workspace/csharp-caesar-cipher/Program.cs:line 38

This was when I used 2567 as cypherValue.

Have you tried commenting out your index operations in the loop and printing out the output with parenthesis vs. without?

The gist is that it’s somehow giving a different result that gives an index out of bounds of the desired array.

That helped. Here’s the code I ran.

      int charPosition = 23; 
      int cipher = 2567;
      Console.WriteLine((charPosition + (26 - (cipher % 26))) % 26);
      Console.WriteLine((charPosition + (26 - (cipher % 26))));

Line 3 prints “4” and line 4 prints “30”.
When you run the math manually with these numbers it shows that the final modulo isn’t actually redundant, but that only shows when using higher value charPositions.

Thanks for helping me think this through!

Glad to be of some use! I always find it fruitful to sandbox math constructs when there is a sliver of a doubt, as adding code on top without being sure is a quickfire recipe for pain… something I know all too well hahaha.