title: Java: Decrypting Caesar Cipher with Unknown Positions
body: <p>Descriptions: I am suppose to come up with a program that will break encrypted messages that used a Caesar Cipher algorithm. Sounds easy enough the problem is you have to figure out what position was used to make the encrypted message in order to decrypt the coded message. 
  So I have a method called <code>public void train(String trainingFileName)</code> that reads in a file with a lot of text in it to determine the frequency of each <code>lowercase alphabetical English character (a - z)</code> that are stored in a <code>double array []</code>. That method works great so it's not necessary to look at unless you want to, but I do use a good majority of that code in the method that I'm having trouble on which is my <code>public int decrypt(String cipherTextFileName, String outputFileName)</code> method. 
  The code works beautifully when the Caesar Cipher is set to 3 positions, but anything else it gives me a lot of problems.
  I have a <code>do-while</code> loop in my <code>public int decrypt(String cipherTextFileName, String outputFileName)</code> method that will decrypt the coded message starting with 0 positions and then using the "distance" formula that I'm using (NOTE: I cannot use any other formula) to find the minimum distance between the <code>knownFrequencies</code> and the <code>observedFreq</code> in my encrypted message. Right now I have my <code>do-while</code> loop set to where if the <code>distance</code> is <code>less than 0.6</code> then stop the loop. In theory when I have the correct number of positions in the Caesar Cipher the distance should be below that value. </p>
  
  <p>Problem: Program works great when <code>numberOfPositions</code> is 3, but when I use an encrypted message that is not using 3 positions in the Caesar Cipher the <code>distance</code> never falls below 1 and while in debug mode when I set the <code>numberOfPositions</code> to what it should be to decrypt the message, the message is still encrypted.</p>
  
  <p>Question: How can I implement this method better so I am not testing my <code>distance</code> on a "hard" value to stop the <code>do-while</code> loop? I tried using <code>Math.min()</code>, but that doesn't work. Why can't I decode a message with the positions of the Caesar Cipher other than 3.</p>
  
  <p>I will show you my code now. If you want to test it on your system. You will need 3 text files. One file has to be long with a bunch of words in it... at least 1000. That file will be read in the <code>train</code> method. You need a file with an encrypted message and another file for the program to write the decrypted message.</p>
  
  <p>Here is an encrypted message first using 3 positions of the Caesar Cipher and then 5 positions.</p>
  
  <p><code>Wkh surjudp zdv krvwhg eb dfwru Slhufh Eurvqdq dqg kdg frpphqwdub iurp pdqb Kroobzrrg dfwruv dqg iloppdnhuv Prylh txrwdwlrqv wkdw ylhzhuv xvh lq wkhlu rzq olyhv dqg vlwxdwlrqv</code></p>
  
  <p><code>Ymj uwtlwfr bfx mtxyji gd fhytw Unjwhj Gwtxsfs fsi mfi htrrjsyfwd kwtr rfsd Mtqqdbtti fhytwx fsi knqrrfpjwx Rtanj vztyfyntsx ymfy anjbjwx zxj ns ymjnw tbs qnajx fsi xnyzfyntsx</code></p>
  
  <p>When decrypted it should say:
  <code>The program was hosted by actor Pierce Brosnan and had commentary from many Hollywood actors and filmmakers Movie quotations that viewers use in their own lives and situations</code></p>
  
  <p>Alright here is the class I wrote (you will need all the imports) and I would like to thank anyone who helps in advance:</p>
  
  <pre><code>public class CodeBreaker {
      public final int NUMBER_OF_LETTERS = 26;
  
      private double[] knownFrequencies = new double[NUMBER_OF_LETTERS];
  
      public double[] getKnownFrequencies() {
          return knownFrequencies;
      }
  
      public void setKnownFrequencies(double[] knownFrequencies) {
  
          this.knownFrequencies = knownFrequencies;
      }
  
      /**
       * Method reads in a file with a lot of text in it and
       * then use that to figure out the frequencies of each character
       *
       * @param trainingFileName
       */
      public void train(String trainingFileName) {
          try {
              Scanner fileIO = new Scanner(new File(trainingFileName));
  
              int total = 0;
              String temp = "";
  
              while (fileIO.hasNext()) {
                  //reading into file and storing it into a string called temp
                  temp += fileIO.next().toLowerCase().replaceAll("[ -,!?';:.]+", "");
                  //converting temp string into a char array
              }
  
              char[] c = temp.toCharArray();
              total += c.length; // how many characters are in text
              int k = (int) 'a'; // int value of lowercase letter 'a'
              int[] counter = new int[NUMBER_OF_LETTERS];
  
              for (int j = 0; j &lt; total; j++) {
                  for (int i = k - k; i &lt; knownFrequencies.length; i++) {
  
                      char[] d = new char[knownFrequencies.length];
  
                      d[i] = (char) (k + i);
  
                      if (c[j] == d[i]) {//checking to see if char in text equals char in d array
  
                          counter[i]++;
  
                          knownFrequencies[i] = (double) counter[i] / total;
                      }
                  }
              }
  
              fileIO.close();
          } catch (FileNotFoundException e) {
              // TODO Auto-generated catch block
              System.err.println(e);
              System.exit(0);
          }
      }
  
  
      /**
       * Main decryption method used to take coded text from a file, figure out the positions in the CaesarCipher
       * and then decode it onto another file.
       *
       * @param cipherTextFileName
       * @param outputFileName
       * @return
       */
      public int decrypt(String cipherTextFileName, String outputFileName) {
          Scanner fileIO;
          int numberOfPositions = 0;
          double distance = 0.000000;
  
          try {
              fileIO = new Scanner(new File(cipherTextFileName));
  
              PrintWriter writer = new PrintWriter(new File(outputFileName));
  
              String temp = "";
  
              while (fileIO.hasNext()) {
                  //reading into file and storing it into a string called temp
                  temp += fileIO.next().toLowerCase().replaceAll(" ", "");
              }
  
              fileIO.close();
  
              do {
                  distance = 0.0;
                  int total = 0;
                  double[] observedFreq = new double[NUMBER_OF_LETTERS];
                  temp = decrypt(temp, numberOfPositions);
                  char[] c = temp.toCharArray(); //store decrypted chars into an array
                  total += c.length; // how many characters are in text
  
                  int k = (int) 'a'; // int value of lowercase letter 'a'
                  int[] counter = new int[NUMBER_OF_LETTERS]; //use to count the number of characters in text
  
                  for (int j = 0; j &lt; total; j++) {
                      for (int i = k - k; i &lt; observedFreq.length; i++) {
                          char[] d = new char[observedFreq.length];
                          d[i] = (char) (k + i);
                          if (c[j] == d[i]) { //checking to see if char in text equals char in d array
                              counter[i]++;
                              observedFreq[i] = (double) counter[i] / total;
                          }
                      }
                  }
  
                  //Formula for finding distance that will determine the numberOfPositions in CaesarCipher
                  for (int j = 0; j &lt; knownFrequencies.length; j++) {
                      distance += Math.abs(knownFrequencies[j] - observedFreq[j]); //This is the part of the code I am having trouble with
                  }
  
                  numberOfPositions = numberOfPositions + 1;
  
              } while (distance &gt; 0.6); //This is the part of the code I am having trouble with
  
              Scanner fileIO2 = new Scanner(new File(cipherTextFileName));
  
              while (fileIO2.hasNextLine()) {
  
                  //reading into file and storing it into a string called temp
                  temp = fileIO2.nextLine();
  
                  writer.println(decrypt(temp, numberOfPositions));
  
              }
              writer.close();
              fileIO2.close();
              System.out.println(distance);
  
          } catch (FileNotFoundException e) {
              // TODO Auto-generated catch block
              System.err.println(e);
              System.exit(0);
          }
          return numberOfPositions;
  
      }
  
      /**
       * CaesarCipher decrypt and encrypt methods
       *
       * @param ciphertext
       * @param numberOfPositions
       * @return
       */
      public String decrypt(String ciphertext, int numberOfPositions) {
          // TODO Auto-generated method stub
          return encrypt(ciphertext, -numberOfPositions);
      }
  
      public String encrypt(String msg, int offset) {
          offset = offset % 26 + 26;
          StringBuilder encoded = new StringBuilder();
          for (char i : msg.toCharArray()) {
              if (Character.isLowerCase(i)) {
                  int j = (i - 'a' + offset) % 26;
                  encoded.append((char) (j + 'a'));
              } else if (Character.isUpperCase(i)) {
                  int h = (i - 'A' + offset) % 26;
                  encoded.append((char) (h + 'A'));
              } else {
                  encoded.append(i);
              }
          }
          return encoded.toString();
      }
  
      // barebones main method to test your code
      public static void main(String[] args) {
          // args[0] contains the filename of the training file
          // args[1] contains the filename of the cipher text file
          // args[2] contains the filename of the output file
          CodeBreaker cb = new CodeBreaker();
          cb.train(args[0]);
          System.out.println(cb.decrypt(args[1], args[2]));
  
      }
  }
  </code></pre>