Java Assignment 1: Secret Codes
CSC 8310, Spring 2001
David Matuszek, Villanova University

What the assignment is about

This is not a large assignment, but it uses a lot of Java features which are probably new to you. I have already done the program design, so you don't have to figure it all out yourself, you just have to code it. (The next assignment will be different!) Don't let the length of this writeup scare you--it's so long because it describes in detail how to write the program.

The object is to write a program that encodes and decodes messages, according to one of two encoding schemes. The first is a simple code, where one letter is replaced by another letter. The second method is a simplified version of the Playfair Cipher (if you would like to see the actual, unsimplified version, http://www.pbs.org/wgbh/nova/decoding/playfair.html has a good explanation). I've simplified it to save you some unnecessary work.

Vocabulary note: Technically, the first of these schemes is a "code," and the second is a "cipher." There isn't a good word for the superclass of codes and ciphers, so I'm using "code" for both.

Each of the encoding schemes uses a keyword; the letters of the keyword are used to create a "code block," an array of characters which is different for the two schemes. Each letter of the alphabet occurs once and only once in the code block. For the simple code, the code block is just an array of 26 letters, containing the alphabet in some scrambled arrangement.

For example, if the keyword is "Villanova", then the simple code is

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
V I L A N O B C D E F G H J K M P Q R S T U W X Y Z

You encode a message by looking up each letter in the normal alphabet (the top row), and replacing it with the corresponding letter in the code block (the bottom row). To decode a message, look up each letter in the bottom row and replace it by the corresponding letter in the top row. The message:

Amazingly few discotheques provide jukeboxes.
would be encoded as:
vhvzdjbgy onw adrlkscnptnr mqkudan etfnikxnr.

The code block for the Playfair cipher is a 5 by 5 array of letters. Since this is only 25 letters, the letter "J" is changed into an "I" anyplace that it occurs. So if the keyword is "Villanova," the code block would look like:

V I L A N
O B C D E
F G H K M
P Q R S T
U W X Y Z

To encode a message, first prepare the message text as follows:

  1. Delete all blanks and punctuation, leaving only letters.
  2. Anyplace there is a double letter (like "tt"), put an 'x' in between them (so "letter" becomes "letxter").
  3. If there are an odd number of letters, add an 'x' at the end.

Encoding and decoding both work the same way:

  1. Take the next two letters of the message and find them in the code block.
  2. If they are in the same row or the same column, just interchange them--for example, "in" becomes "ni." (This is where I've simplified things; you can use the real Playfair technique if you like.)
  3. If they are not in the same row or in the same column, then they are at two corners of a rectangle; use the letters at the other two corners--for example, "am" becomes "nk."

For the above message, you should get:

Amazingly few discotheques provide jukeboxes.
nknynihiukbzbardepmcpwdtrpovabbnyfbecudt
amazinglyfewdiscothequesprovideiukeboxes

When you use the simple code, you can expect to get back exactly the message you started with; you can even keep the spaces and punctuation. When you use the simplified Playfair cipher, the result is messy: spaces and punctuation are lost, and there are some extra xs, but it's still readable.

The easiest thing to do about capital and lowercase letters is just to turn every letter into lowercase. You can do this with: newLetter = Character.toLowerCase(oldLetter);

Program specifications

Please follow these specifications carefully. Use the classes, interfaces, and methods defined below. You can and should define additional "helper" methods of your own, but these should be private.

Your program should define an interface SecretCode. An interface is like a class, but it only declares methods, it does not define them. That is, instead of method definitions that look like int double(int x) { return 2 * x; }, it will have method declarations that look like int double(int x);

SecretCode should declare the following:

Your program should have a second interface, CodeBlock, which will contain the information needed to code or decode messages. It should declare:

CodeBlock should have two implementations, SimpleBlock and PlayfairBlock. Each of these should:

SecretCode should have two implementations, SimpleCode and PlayfairCipher. Each of these implementations should:

The PlayfairCipher class needs an additional method, to prepare the message by removing blanks and punctuation and inserting xs as necessary. I have written this code for you--here it is:

  /**
   * Takes the message and (1) removes all blanks and punctuation,
   * (2) puts an 'x' between all double letters (except "xx"), and
   * (3) adds an 'x' at the end if the string length is odd.
   */
  private String prepareMessage(String message) {
    StringBuffer buffer = new StringBuffer();
    char lastLetter = '*';
    char thisLetter;
    for (int i = 0; i < message.length(); i++) {
      thisLetter = Character.toLowerCase(message.charAt(i));
      if (!Character.isLetter(thisLetter)) continue;
      if (thisLetter == 'j') thisLetter = 'i'; // added 3-1-2001
      if (thisLetter == lastLetter  && lastLetter != 'x')
        buffer.append('x');
      buffer.append(thisLetter);
      lastLetter = thisLetter;
    }
    if (buffer.length() % 2 == 1) buffer.append('x');
    return buffer.toString();
  }

Finally, you need a main class named Encryption that uses these other classes. It must have a main method, whose purpose is just to test out the other classes. It should read in a keyword, use it to create a SimpleCode object, and then read in a few messages (2 or 3 is enough) and use the SimpleCode object to encode and then decode them. Your printout should include the original message, the encoded message, and the decoded message. Then your program should do the same thing again, but this time using the PlayFairCipher.

Turn in a floppy containing:

Due dates:

Last-minute clarifications:

These comments are in response to questions I have received. They are last-minute because that's when students starting asking me questions. If you would like this kind of information sooner, ask questions sooner.

You do not have to:

  • Figure out which I's are really J's when you decode a Playfair cipher.
  • Put blanks back into a decoded Playfair cipher.
  • Remove X's from a decoded Playfair cipher.
  • Keep track of capital and lowercase letters (either case is fine).
  • Remove blanks and punctuation from a simple code (but it's OK if you do).
  • Read any input from the user. (Encryption.main is just used for testing your code, and can have keywords and messages hard-wired into it.)

It turns out that there are no cases of one class extending another, just classes implementing interfaces. I had not noticed this before; it's just the way it worked out. As it says above, SimpleCode and PlayfairCipher should each contain, not extend, a CodeBlock of the appropriate kind; however, if you used extension, you do not need to change it now.

I used a UML program (TogetherJ) to generate the diagram from my code, and mistakenly assumed that it would produce correct output. It produced the wrong kind of arrows to indicate that one class contains an instance of another class. The diagram below has now been corrected.

I have added a line to prepareMessage() to convert J's to I's, so you don't have to worry about this in your code.

I am not granting extensions. Please see my syllabus for an explanation of my policy for late programs.

The following diagram uses UML (Unified Modeling Language) to show the structure of the program you should write. Be warned that the variable and method descriptions in the boxes use UML syntax, not Java syntax, so don't let that confuse you. Other than that, the diagram should be pretty easy to understand--it just repeats what I've already said above.