CMPS 420 Section 001 HOMEWORK ASSIGNMENT #2 Assigned Date: Monday, September 21, 1998 Due Date: 10:30am, Friday, October 2, 1998 You are to write a LISP program that helps solve a cryptogram. This program should be fully documented and stored in the file 'hmwk2.lisp' placed in your working directory. Be sure to include the appropriate header documentation as described in the first assignment handout. A cryptogram is a type of puzzle that requires the solver to decode a message. The code is known as a substitution cipher because it consists of substituting one letter for another throughout the message. For example, if we substitute J for F, T for A, and W for L, the word "fall" would be encoded as JTWW. Here is an actual cryptogram for you to solve: "ZJ ZE KLJJLS JF SLAPZI EZVLIJ PIB KL JUFWXUJ P HFFV JUPI JF ENLPO PIB SLAFML PVV BFWKJ" The purpose of this programming exercise, however, is not to solve cryptograms but to write a program to help you solve them. Suppose the preceding cryptogram has been stored in the global variable 'c1'. Here is an example of how our cryptogram-solving program will start out: ->(solve c1) ---------------- ZJ ZE KLJJLS JF SLAPZI EZVLIJ PIB KL JUFWXUJ P HFFV JUPI JF ENLPO PIB SLAFML PVV BFWKJ ---------------- Substitute which letter? When tackling a new cryptogram it helps to look at the shortest words first. In English there are only two one-letter words: "I" and "a", so the tenth word of the cryptogram, P, must be one of those. Suppose we guess that P deciphers to A. Beneath each P in the text we write an A. Substitute which letter? P What does P decipher to? A ---------------- ZJ ZE KLJJLS JF SLAPZI EZVLIJ PIB KL JUFWXUJ P HFFV JUPI JF ENLPO PIB SLAFML PVV BFWKJ A A A A A A A ---------------- Substitute which letter? Next we might look at all the two-letter words and guess that Z deciphers to I. Beneath each Z in the message we write an I. Substitute which letter? Z What does Z decipher to? I ---------------- ZJ ZE KLJJLS JF SLAPZI EZVLIJ PIB KL JUFWXUJ P HFFV JUPI JF ENLPO PIB SLAFML PVV BFWKJ I I AI I A A A A A A ---------------- Substitute which letter? An important constraint on cryptograms that helps to make them solvable is that no letter can decipher to more than one thing, and no two letters can decipher to the same letter. Our program must check to ensure that this constraint is obeyed by any solution we generate. Substitute which letter? Z Z has already been deciphered as I! ---------------- ZJ ZE KLJJLS JF SLAPZI EZVLIJ PIB KL JUFWXUJ P HFFV JUPI JF ENLPO PIB SLAFML PVV BFWKJ I I AI I A A A A A A ---------------- Substitute which letter? K What does K decipher to? A But P already deciphers to A! ---------------- ZJ ZE KLJJLS JF SLAPZI EZVLIJ PIB KL JUFWXUJ P HFFV JUPI JF ENLPO PIB SLAFML PVV BFWKJ I I AI I A A A A A A ---------------- Substitute which letter? At some point we may want to take back a substitution. Suppose that after deciphering P and Z we decide that P shouldn't really decipher to A after all. The program must allow for this: Substitute which letter? undo Undo which letter? P ---------------- ZJ ZE KLJJLS JF SLAPZI EZVLIJ PIB KL JUFWXUJ P HFFV JUPI JF ENLPO PIB SLAFML PVV BFWKJ I I I I ---------------- Substitute which letter? The process continues until we have solved the cryptogram. Instructions Within 'hmwk2.lisp': 1. Set the global variable 'c1' to the string: "ZJ ZE KLJJLS JF SLAPZI EZVLIJ PIB KL JUFWXUJ P HFFV JUPI JF ENLPO PIB SLAFML PVV BFWKJ" 2. Define function 'clear' of no arguments that initializes two global variables 'cipher' and 'decipher' as shown below. This function will be used to initialize our 'solve' function before starting on a new cryptogram. The variable 'cipher' should be set equal to the string: "ABCDEFGHIJKLMNOPQRSTUVWXYZ " and the variable 'decipher' to the string: " " Each letter in 'cipher' has a corresponding letter that it deciphers to (e.g., P deciphers to A). As we solve the cryptogram we will store this information as follows: strings 'cipher' and 'decipher' are parallel, i.e., the deciphered character for a letter at index n in 'cipher' is found at index n in 'decipher'. If the deciphered character is blank (space), then there is no deciphered character specified yet. 3. Define function 'solve' that takes a cryptogram as argument. It should perform the following operations: First it should display the cryptogram (see 'show-solution' below). Then it should ask the user to enter a letter; if the input is a letter, it calls 'substitute-letter' (see below); if the user enters 'undo' it calls function 'undo-letter' (see below); if the input is 'end' it should return T; otherwise it outputs an error message. Finally, if the input was not 'end' it makes a recursive call to itself to continue working on the solution. 4. Define function 'show-solution' that receives the cryptogram text as argument and displays it. Then it outputs the deciphered text beneath it (as shown above); i.e., for every letter in cryptogram for which there is a substitute (in 'decipher') it outputs this substitute; for letters that have not been substituted yet, it outputs blanks in the corresponding place. (Hint: You may find functions 'map', 'elt', and 'position' useful.) 5. Define function 'substitute-letter' which takes a letter as argument. If the letter is substituted/deciphered already, it outputs an error message and returns. Otherwise it asks the user to enter a substitute letter; if this letter is already used, it outputs an error message and returns; otherwise it updates 'decipher' accordingly. 6. Define function 'unsubstitute-letter' takes a letter as argument. If the letter is substituted already, it updates 'decipher' accordingly (sets corresponding character to blank). Otherwise it outputs an error message and returns. 7. Feel free to define additional help functions for any of the above to improve code readability and maintainability. Bonus Points For extra bonus do the following: 1. In the example shown above, P deciphers to A, and Z deciphers to I. Solve the cryptogram. 2. Function 'show-solution' should split the cryptogram text and the deciphered text into lines of 60 characters long, so that the solution may be clearly displayed.