PROGRAM ANAGRM C Author: T. R. Wyant C Date: 20-Jul-1990 C Remarks: C ANAGRM is a program that translates anagrams into normal C English words. It is driven by a dictionary of about C 88000 words, grouped by length and arranged in C alphabetical order by their 'cannonical' anagrams (the C 'cannonical' anagram of a word is formed by arranging C the letters of that word in alphabetical order). To find C the words corresponding to a given anagram, it is C converted to canonical form, and a binary search is C performed on the desired list. C C The (bizarre) algorithm chosen for the implementation C requires some comment. Putting all the words in one C indexed file (with the record being composed of the C 'canonical' anagram followed by one or more words) was C more straightforward computationally, but the resulting C dictionary was huge, and 'standard' Fortran-77 doesn't C support indexed file I/O anyway. With the algorithm C chosen the implementation asks little of the underlying C system, and is therefore more portable (at least in C principle). The cost of portability in this case is C time; opening a file per anagram is blindingly slow C (though you don't much notice it when the input is from C the keyboard). With many LUNs at your disposal, you C could open ALL the files right away, and just select the C LUN based on the length of the word. But I didn't feel C like managing the LUNS, and it would require lots of C open file quota (under VMS) or file buffers (under RSX, C chewing up precious address space). C PARAMETER LUNANA = 1 ! LUN for anagram file. PARAMETER LUNTI = 5 ! LUN for terminal input. PARAMETER LUNTO = 6 ! LUN for terminal output. INTEGER*2 WRDSIZ ! Size of words handled. PARAMETER (WRDSIZ = 32) LOGICAL*1 ANABYT(WRDSIZ) ! Anagram, as bytes. INTEGER*2 ANASIZ ! Anagram record size. CHARACTER*(WRDSIZ) ANAWRD ! Anagram word. LOGICAL*1 CLRBYT(WRDSIZ) ! Word to look up, as bytes. CHARACTER*(WRDSIZ) CLRWRD ! Word to look up. LOGICAL*1 FANBYT(WRDSIZ) ! Anagram file anagram, as bytes. CHARACTER*(WRDSIZ) FANWRD ! Anagram file anagram. LOGICAL*1 FILBYT(WRDSIZ) ! Anagram file record, as bytes. CHARACTER*40 FILNAM ! Anagram file name. CHARACTER*(WRDSIZ) FILWRD ! Anagram file record. INTEGER*4 RECHI ! High record. INTEGER*4 RECLO ! Low record. INTEGER*4 RECTRY ! Record to try. INTEGER*2 WRDLEN ! Length of word. EQUIVALENCE (CLRWRD, CLRBYT) EQUIVALENCE (ANAWRD, ANABYT) EQUIVALENCE (FILWRD, FILBYT) EQUIVALENCE (FANWRD, FANBYT) C Disable 'No such file' and 'illegal record' error reporting. CALL ERRSET (29, , .FALSE., , .FALSE.) CALL ERRSET (39, , .FALSE., , .FALSE.) C Find out what anagam we're trying for. 1000 CONTINUE CLOSE (UNIT=LUNANA) WRITE (LUNTO, 1010) ' ' 1010 FORMAT (8A) WRITE (LUNTO, 1010) '$Enter anagram to look up: ' READ (LUNTI, 1010, END=9900) CLRWRD IF (CLRWRD .EQ. ' ') GO TO 1000 C Convert it to its 'canonical' anagram. CALL MAKANA (WRDSIZ, CLRBYT, WRDLEN, ANABYT) IF (WRDLEN .LE. 0) GO TO 1000 C Form the name of the desired dictionary file. WRITE (FILNAM, 1610) WRDLEN 1610 FORMAT ('ANA', I2.2, '.DIC') C Open the dictionary file. OPEN (UNIT=LUNANA, FILE=FILNAM, 1 ORGANIZATION='SEQUENTIAL', ACCESS='DIRECT', 2 STATUS='OLD', READONLY, SHARED, FORM='FORMATTED', 3 ERR=9000) C Set the starting records for the binary search. RECHI = 65536 ! Must start at 2**n (n=16 in this case) RECLO = 0 ! Start at illegal record. C Calculate the next record to try. 1800 CONTINUE RECTRY = (RECLO + RECHI)/2 C If it didn't change, the search has ended unsuccessfully. IF (RECTRY .EQ. RECLO) GO TO 9000 C Read the desired record from the dictionary. READ (UNIT=LUNANA, REC=RECTRY, FMT=1010, ERR=1860) FILWRD C Convert it to its 'canonical' anagram. CALL MAKANA (WRDSIZ, FILBYT, WRDLEN, FANBYT) C If it's a match, the search has ended successfully. IF (FANWRD .EQ. ANAWRD) GO TO 2000 C If it's too small, C take the upper half of the range C and try again. IF (FANWRD .LT. ANAWRD) THEN RECLO = RECTRY GO TO 1800 END IF C If it's too large (or if we couldn't read the record) C take the lower half of the range C and try again. 1860 RECHI = RECTRY GO TO 1800 C Come here when we find our anagram in the dictionary. 2000 CONTINUE C If we're not on the first record in the file C back up, and see if the previous record matches, also. C If so, back up and match again, until either a mismatch C or we arrive at record 1. This nonsense is necessary C because more than one word may have the same anagram, and C the binary search is not guaranteed to find the first C match in a range. IF (RECTRY .GT. 1) THEN RECTRY = RECTRY - 1 READ (UNIT=LUNANA, REC=RECTRY, FMT=1010) FILWRD CALL MAKANA (WRDSIZ, FILBYT, WRDLEN, FANBYT) IF (FANWRD .EQ. ANAWRD) GO TO 2000 RECTRY = RECTRY + 1 END IF C Print the 'matched' message. WRITE (UNIT=LUNTO, FMT=1010) ' Success - ', 1 CLRWRD(:WRDLEN), ' has the following anagram(s):' 2040 CONTINUE C Read and print words from the dictionary, until either C the anagram no longer matches the target or C we fall off the end of the file. C Then, go prompt for another anagram. READ (UNIT=LUNANA, REC=RECTRY, FMT=1010, ERR=1000) FILWRD CALL MAKANA (WRDSIZ, FILBYT, WRDLEN, FANBYT) IF (FANWRD .NE. ANAWRD) GO TO 1000 RECTRY = RECTRY+1 WRITE (UNIT=LUNTO, FMT=1010) ' ', FILWRD(:WRDLEN) GO TO 2040 C Come here if we can't find a match for the anagram. C Tell the user of our miserable failure, and C go prompt for another word (maybe he'll get lucky next time). 9000 WRITE (UNIT=LUNTO, FMT=1010) ' Error - ', CLRWRD(:WRDLEN), 1 ' has no known anagrams.' GO TO 1000 C Come here when we have no more words to look up. C Close the input file and exit. 9900 CONTINUE CLOSE (UNIT=LUNANA) CALL EXIT END