home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 1156 / Cryptanalysis.sis / crack.opl (.txt) < prev   
Encoding:
EPOC OPL Source  |  2001-10-18  |  45.7 KB  |  1,511 lines

  1.  
  2.  
  3. REM      This program was written by James L. Dean on February 1, 2000.
  4. REM
  5. REM      It implements the algorithm given by George W. Hart in the September
  6. REM 1994 edition of the Communications of the ACM (Volume 37, Number 9).
  7. REM
  8. REM      Edgar Allan Poe used this method to crack simple substitution ciphers
  9. REM around 1839; consider the following from pages 784-785 of David Kahn's The
  10. REM Codebreakers:
  11. REM 
  12. REM           The closest he ever came to doing so was when he
  13. REM           demonstrated how he deduced that a challenge sent him by
  14. REM           G.  W. Kulp, of Lewiston, Pennsylvania, was a false
  15. REM           cryptogram.  He picked out three words in the
  16. REM           cryptogram--MW, LAAM, and MLW.  Since "all English words
  17. REM           of but two letters consist of a vowel and a consonant," he
  18. REM           wrote, MW must be one of 30 words, which he listed. He
  19. REM           then inserted every letter of the alphabet in the middle
  20. REM           of all 30 words in an exhaustive trial process to see
  21. REM           which letters would make a sensible word out of MLW. Here
  22. REM           he found 18, including ash and tho'.  Turning to LAAM, he
  23. REM           observed, that "if MLW be ash, then LAAM will be a word of
  24. REM           this form, s..a, in which the dots represent two unknown
  25. REM           letters of the same kind." He ran through his 18 words in
  26. REM           this way, and found that the only one that gave a possible
  27. REM           meaning for LAAM was h..t, or hoot.  "LAAM is then hoot or
  28. REM           nothing. But the hypothesis of the word hoot is founded
  29. REM           upon that of the word tho'.... We now arrive at a definite
  30. REM           conclusion. Either Mr. Kulp's puzzle is not genuine, or MW
  31. REM           stands for to, MLW for tho', and LAAM for hoot. But it is
  32. REM           evident that this latter cannot be--for in that case both
  33. REM           W and A represent the letter 0. What follows?--why that
  34. REM           Mr. Kulp's puzzle is no puzzle at all. This demonstration
  35. REM           is as absolutely conclusive as any mathematical one could
  36. REM           be. The process of reasoning here employed is that
  37. REM           employed also in the solution of the cyphers."
  38.  
  39. DECLARE EXTERNAL
  40.  
  41. INCLUDE "DATE.OXH"
  42.  
  43. EXTERNAL AddEncipheredWord&:(EncipheredWord$)
  44. EXTERNAL AddPlaintext:(PatternHead&,Pattern&,Plaintext$)
  45. EXTERNAL AddWordNotInWordList:(PatternPtr&)
  46. EXTERNAL FreePattern:(PatternPtr&)
  47. EXTERNAL GetCiphertext:
  48. EXTERNAL GetCiphertextPatterns:
  49. EXTERNAL GetEncipheredChar%:
  50. EXTERNAL GetMaxDistinctLettersPerWord:(EncipheredHead&)
  51. EXTERNAL GetPatternForPlaintextWord:(Pattern&)
  52. EXTERNAL GetWordListChar%:
  53. EXTERNAL GetWordListWord:(PreviousWord$)
  54. EXTERNAL GetWordsMatchingPatterns:
  55. EXTERNAL GoBackward:
  56. EXTERNAL GoForward:(KeepOnlyTheBest%,EncipheredHead&,CiphertextHead&)
  57. EXTERNAL IsLower%:(CurrentChar%)
  58. EXTERNAL IsUpper%:(CurrentChar%)
  59. EXTERNAL Main:
  60. EXTERNAL Malloc&:(NumBytes%)
  61. EXTERNAL OutputSolution:(EncipheredHead&,CiphertextHead&)
  62. EXTERNAL PatternForEncipheredWord&:(EncipheredWord&,EncipheredWordLen%)
  63. EXTERNAL PatternForWord&:(Word&,WordLen%)
  64. EXTERNAL Solve:(NumDistinctWords&,EncipheredHead&,SortedHead&,KeepOnlyTheBest%,CiphertextHead&)
  65. EXTERNAL Sort:
  66. EXTERNAL StrCmp%:(Str1&,Str2&)
  67. EXTERNAL StrICmp%:(Str1&,Str2&)
  68. EXTERNAL ToLower%:(CurrentChar%)
  69. EXTERNAL ToUpper%:(CurrentChar%)
  70.  
  71. CONST AlphabetSize%=27
  72. CONST Apostrophe%=39
  73. CONST Asterisk%=42
  74. CONST EOF%=-1
  75. CONST False%=0
  76. CONST LowercaseA%=97
  77. CONST LowercaseZ%=122
  78. CONST Slash%=47
  79. CONST True%=-1
  80. CONST UppercaseA%=65
  81. CONST UppercaseZ%=90
  82.  
  83. PROC Main:
  84.   GLOBAL Alphabetic%
  85.   GLOBAL CiphertextCharPtr&
  86.   GLOBAL CiphertextHead&
  87.   GLOBAL CiphertextPtr&
  88.   GLOBAL CiphertextTail&
  89.   GLOBAL EncipheredHead&
  90.   GLOBAL EncipheredPtrForMax&
  91.   GLOBAL EncipheredTail&
  92.   GLOBAL FatalError%
  93.   GLOBAL MaxDistinctLettersPerWord
  94.   GLOBAL NumDistinctWords&
  95.   GLOBAL PatternHead&
  96.   GLOBAL SortedHead&
  97.   GLOBAL Word$(255)
  98.   LOCAL ElapsedTime&
  99.   LOCAL EncipheredPtr1&
  100.   LOCAL KeepOnlyTheBest%
  101.   LOCAL NumChars%
  102.   LOCAL SortedPtr&
  103.   LOCAL StartTime&
  104.   LOCAL StopTime&
  105.  
  106.   FatalError%=False%
  107.   ElapsedTime&=0
  108.   PRINT "        Cryptanalysis of Simple Substitution Ciphers with Word Divisions"
  109.   PRINT
  110.   KeepOnlyTheBest%=False%
  111.   GetCiphertext:
  112.   IF NOT FatalError%
  113.     IF CiphertextHead& = 0
  114.       FatalError%=True%
  115.       PRINT "Fatal error:  no ciphertext was entered."
  116.     ENDIF
  117.   ENDIF
  118.   IF NOT FatalError%
  119.     StartTime&=DTNow&:
  120.     GetCiphertextPatterns:
  121.     IF NOT FatalError%
  122.       IF PatternHead& = 0
  123.         FatalError%=True%
  124.         PRINT "Fatal error:  the cipher text contains no words."
  125.       ENDIF
  126.     ENDIF
  127.     IF NOT FatalError%
  128.       GetWordsMatchingPatterns:
  129.       IF NOT FatalError%
  130.         GetMaxDistinctLettersPerWord:(EncipheredHead&)
  131.         IF MaxDistinctLettersPerWord <= 0.0
  132.           FatalError%=True%
  133.           PRINT "Fatal error:  no word in the cipher text matched any pattern in the word list."
  134.         ENDIF
  135.         IF NOT FatalError%
  136.           SortedHead&=Malloc&:(20)
  137.           IF SortedHead& = 0
  138.             FatalError%=True%
  139.             PRINT "Fatal error:  out of memory."
  140.           ELSE
  141.             Sort:
  142.             IF NOT FatalError%
  143.               PRINT "Possible solutions (press a key to exit):"
  144.               Solve:(NumDistinctWords&,EncipheredHead&,SortedHead&,KeepOnlyTheBest%,CiphertextHead&)
  145.               StopTime&=DTNow&:
  146.               ElapsedTime&=DTSecsDiff&:(StartTime&,StopTime&)
  147.             ENDIF
  148.             WHILE SortedHead& <> 0
  149.               SortedPtr&=PEEKL(SortedHead&+16)
  150.               FREEALLOC SortedHead&
  151.               SortedHead&=SortedPtr&
  152.             ENDWH
  153.           ENDIF
  154.         ENDIF
  155.       ENDIF
  156.     ENDIF
  157.     FreePattern:(PatternHead&)
  158.     WHILE EncipheredHead& <> 0
  159.       EncipheredPtr1&=PEEKL(EncipheredHead&+12)
  160.       FREEALLOC PEEKL(EncipheredHead&)
  161.       FREEALLOC EncipheredHead&
  162.       EncipheredHead&=EncipheredPtr1&
  163.     ENDWH
  164.   ENDIF
  165.   WHILE CiphertextHead& <> 0
  166.     CiphertextPtr&=PEEKL(CiphertextHead&+4)
  167.     FREEALLOC PEEKL(CiphertextHead&)
  168.     FREEALLOC CiphertextHead&
  169.     CiphertextHead&=CiphertextPtr&
  170.   ENDWH
  171.   PRINT
  172.   IF ElapsedTime& > 0
  173.     PRINT "Elapsed time:  ";
  174.     PRINT ElapsedTime&;
  175.     IF ElapsedTime& = 1
  176.       PRINT " second"
  177.     ELSE
  178.       PRINT " seconds"
  179.     ENDIF
  180.   ENDIF
  181.   PRINT "Press Enter to exit."
  182.   INPUT Word$
  183. ENDP
  184.  
  185. PROC GetCiphertext:
  186.   EXTERNAL CiphertextCharPtr&
  187.   EXTERNAL CiphertextHead&
  188.   EXTERNAL CiphertextPtr&
  189.   EXTERNAL CiphertextTail&
  190.   EXTERNAL FatalError%
  191.   LOCAL BytePtr&
  192.   LOCAL CiphertextCharNum%
  193.   LOCAL EncipheredText$(255)
  194.   LOCAL NumCiphertextChars%
  195.  
  196.   PRINT "Enter enciphered text followed by a blank line."
  197.   PRINT
  198.   CiphertextHead&=0
  199.   CiphertextTail&=0
  200.   DO
  201.     INPUT EncipheredText$
  202.     IF EncipheredText$ <> ""
  203.       CiphertextPtr&=Malloc&:(8)
  204.       IF CiphertextPtr& = 0
  205.         FatalError%=True%
  206.         PRINT "Fatal error:  out of memory."
  207.       ELSE
  208.         CiphertextCharPtr&=Malloc&:(2+LEN(EncipheredText$))
  209.         IF CiphertextCharPtr& = 0
  210.           FatalError%=True%
  211.           PRINT "Fatal error:  out of memory."
  212.           FREEALLOC CiphertextPtr&
  213.         ELSE
  214.           BytePtr&=CiphertextCharPtr&
  215.           CiphertextCharNum%=1
  216.           NumCiphertextChars%=LEN(EncipheredText$)
  217.           WHILE CiphertextCharNum% <= NumCiphertextChars%
  218.             POKEB BytePtr&,ASC(MID$(EncipheredText$,CiphertextCharNum%,1))
  219.             BytePtr&=BytePtr&+1
  220.             CiphertextCharNum%=CiphertextCharNum%+1
  221.           ENDWH
  222.           POKEB BytePtr&,10
  223.           BytePtr&=BytePtr&+1
  224.           POKEB BytePtr&,0
  225.           POKEL CiphertextPtr&,CiphertextCharPtr&
  226.           POKEL CiphertextPtr&+4,0
  227.           IF CiphertextTail& = 0
  228.             CiphertextHead&=CiphertextPtr&
  229.           ELSE
  230.             POKEL CiphertextTail&+4,CiphertextPtr&
  231.           ENDIF
  232.           CiphertextTail&=CiphertextPtr&
  233.         ENDIF
  234.       ENDIF
  235.     ENDIF
  236.   UNTIL FatalError% OR (EncipheredText$ = "")
  237.   RETURN
  238. ENDP
  239.  
  240. PROC GetCiphertextPatterns:
  241.   EXTERNAL Alphabetic%
  242.   EXTERNAL CiphertextCharPtr&
  243.   EXTERNAL CiphertextHead&
  244.   EXTERNAL CiphertextPtr&
  245.   EXTERNAL CiphertextTail&
  246.   EXTERNAL EncipheredHead&
  247.   EXTERNAL EncipheredTail&
  248.   EXTERNAL FatalError%
  249.   EXTERNAL NumDistinctWords&
  250.   EXTERNAL PatternHead&
  251.   EXTERNAL Word$
  252.   LOCAL CurrentChar%
  253.   LOCAL EndOfFile%
  254.   LOCAL PatternPtr&
  255.   LOCAL WordLength%
  256.  
  257.   PRINT "Getting patterns in enciphered text..."
  258.   NumDistinctWords&=0
  259.   EncipheredHead&=0
  260.   EncipheredTail&=0
  261.   PatternHead&=0
  262.   CiphertextPtr&=CiphertextHead&
  263.   CiphertextCharPtr&=PEEKL(CiphertextHead&)
  264.   DO
  265.     EndOfFile%=False%
  266.     Alphabetic%=False%
  267.     WHILE (EndOfFile% = 0) AND (NOT Alphabetic%)
  268.       CurrentChar%=GetEncipheredChar%:
  269.       IF CurrentChar% = EOF%
  270.         EndOfFile%=True%
  271.       ELSE
  272.         IF CurrentChar% = Apostrophe%
  273.           Alphabetic%=True%
  274.         ELSE
  275.           CurrentChar%=ToLower%:(CurrentChar%)
  276.           IF IsLower%:(CurrentChar%)
  277.             Alphabetic%=True%
  278.           ENDIF
  279.         ENDIF
  280.       ENDIF
  281.     ENDWH
  282.     IF NOT EndOfFile%
  283.       Word$=""
  284.       WordLength%=0
  285.       DO
  286.         Word$=Word$+Chr$(CurrentChar%)
  287.         WordLength%=WordLength%+1
  288.         CurrentChar%=ToLower%:(GetEncipheredChar%:)
  289.       UNTIL (CurrentChar% = EOF%) OR (WordLength% >= 255) OR ((CurrentChar% <> Apostrophe%) AND (NOT IsLower%:(CurrentChar%)))
  290.       PatternPtr&=AddEncipheredWord&:(Word$)
  291.       IF (NOT FatalError%) AND (PEEKL(PatternPtr&+12) = 0)
  292.         AddWordNotInWordList:(PatternPtr&)
  293.       ENDIF
  294.     ENDIF
  295.   UNTIL FatalError% OR (CurrentChar% = EOF%)
  296.   RETURN
  297. ENDP
  298.  
  299. PROC GetWordsMatchingPatterns:
  300.   EXTERNAL Alphabetic%
  301.   EXTERNAL FatalError%
  302.   EXTERNAL PatternHead&
  303.   EXTERNAL Word$
  304.   GLOBAL CharNum%
  305.   GLOBAL LineNum&
  306.   GLOBAL WordList$(81,60)
  307.   LOCAL Pattern&
  308.   LOCAL PreviousWord$(255)
  309.  
  310.   PRINT "Getting words matching the patterns..."
  311.   WordList$(1)="AA/BBLE/COUT/DVE/BCCORDING/EUNT/CROSS/CT/DION/EVITIES/HY/DUA"
  312.   WordList$(2)="LLY/BDDED/DITION/CMINISTRATION/BFTER/BGAIN/FST/CE/CO/BHEAD/B"
  313.   WordList$(3)="ID/CR/BLL/CMOST/CONE/EG/CREADY/CSO/CTHOUGH/CWAYS/BM/CERICA/H"
  314.   WordList$(4)="N/CONG/DUNT/BN/CALYSIS/CD/COTHER/CSWER/CTI/CY/DONE/DTHING/BP"
  315.   WordList$(5)="PARENTLY/DEAR/GED/DROACH/BRE/DA/ES/CMY/COUND/CT/BS/CK/DED/CS"
  316.   WordList$(6)="OCIATION/BT/CTACK/DENTION/BUDIENCE/BVAILABLE/CERAGE/BWAY/AB/"
  317.   WordList$(7)="BACK/CD/CLL/CSED/DIC/ES/BE/CAUTIFUL/CCAME/EUSE/DOME/CD/CEN/C"
  318.   WordList$(8)="FORE/CGAN/DINNING/CHIND/CING/CLIEVE/DOW/CST/CTTER/DWEEN/CYON"
  319.   WordList$(9)="D/BIG/CLL/BLACK/COOD/CUE/BOARD/CDY/COK/CRN/CTH/CY/DS/BRING/C"
  320.   WordList$(10)="OUGHT/DWN/BUILDING/ET/CSINESS/CT/BY/AC/BALL/EED/CME/CN/DNOT/"
  321.   WordList$(11)="CR/DE/DRIED/DS/CSE/ES/CUSE/BENT/EER/ERAL/EURY/CRTAIN/HLY/BHA"
  322.   WordList$(12)="NGE/DRACTER/CIEF/DLD/FREN/COICE/CRISTIAN/CURCH/BITY/BLASS/CE"
  323.   WordList$(13)="AR/FLY/COSE/FD/CUB/BO/CLD/DLEGE/DOR/CME/ES/DING/DMITTEE/EON/"
  324.   WordList$(14)="EUNIST/HTY/DPANY/ELETE/ILY/CNCERNED/DDITIONS/DGRESS/DSIDER/I"
  325.   WordList$(15)="ED/DTINUED/EROL/CRNER/DPS/CST/ES/CULD/FN[T/DNTRIES/GY/FY/DPL"
  326.   WordList$(16)="E/DRSE/ET/CVERED/BUT/AD/BAILY/CRK/CTA/CY/DS/BE/CAD/DL/DTH/CC"
  327.   WordList$(17)="IDED/ESION/CEP/CFENSE/CGREE/CMOCRATIC/CPARTMENT/CSCRIBED/DIG"
  328.   WordList$(18)="N/GED/CTERMINED/CVELOPED/HMENT/BID/DN[T/CFFERENCE/IT/EICULT/"
  329.   WordList$(19)="CRECT/GION/GLY/CSTANCE/ERICT/BO/CES/CING/CNE/D[T/COR/CUBT/CW"
  330.   WordList$(20)="N/BR/CIVE/BUE/CRING/AE/BACH/CRLIER/EY/DTH/CST/BCONOMIC/BDUCA"
  331.   WordList$(21)="TION/BFFECT/GIVE/GS/DORT/GS/BIGHT/CTHER/BLEMENTS/CSE/BND/CGL"
  332.   WordList$(22)="AND/EISH/COUGH/CTIRE/BQUIPMENT/BSPECIALLY/CTABLISHED/BUROPE/"
  333.   WordList$(23)="BVEN/EING/DR/EY/FTHING/CIDENCE/BXAMPLE/CCEPT/CISTENCE/CPECT/"
  334.   WordList$(24)="GED/ERIENCE/CTENT/BYE/DS/AF/BACE/DT/CITH/CLL/CMILY/CR/DM/CTH"
  335.   WordList$(25)="ER/BEAR/CDERAL/CED/DL/EING/DT/CLT/CW/BIELD/CGURE/GS/CLLED/CN"
  336.   WordList$(26)="AL/FLY/DD/DE/CRE/DM/DST/CSCAL/CVE/BLOOR/BOLLOWED/GING/COD/DT"
  337.   WordList$(27)="/CR/DCE/FS/DEIGN/DM/EER/ES/DWARD/CUND/DR/BREE/EDOM/DNCH/CIEN"
  338.   WordList$(28)="D/GS/COM/DNT/BULL/CNCTION/CRTHER/CTURE/AG/BAME/CVE/BENERAL/H"
  339.   WordList$(29)="LY/CORGE/CT/DTING/BIRL/ES/CVE/EN/ES/BLASS/BO/CD/CING/CNE/COD"
  340.   WordList$(30)="/CT/CVERNMENT/BREAT/FER/DEN/COUND/EP/FS/DWING/ETH/BUN/AH/BAD"
  341.   WordList$(31)="/CIR/CLF/DL/CND/ES/CPPENED/CRD/CS/CVE/DING/BE/CAD/DR/ED/ET/D"
  342.   WordList$(32)="VY/CLD/DL/DP/CR/DE/DSELF/C[S/BIGH/EER/CM/DSELF/CS/DTORY/CT/B"
  343.   WordList$(33)="OLD/CME/CPE/CRSE/CSPITAL/CT/DEL/CUR/ES/DSE/CW/DEVER/BUMAN/CN"
  344.   WordList$(34)="DRED/CSBAND/AI/BDEA/ES/BF/B[LL/CM/BMAGE/CMEDIATELY/CPORTANT/"
  345.   WordList$(35)="BN/CCLUDE/GING/DOME/DREASE/ID/CDEED/DIVIDUAL/DUSTRIAL/HY/CFL"
  346.   WordList$(36)="UENCE/DORMATION/CSIDE/DTEAD/CTEREST/FNATIONAL/DO/CVOLVED/BS/"
  347.   WordList$(37)="CLAND/CSUE/BT/CS/C[S/CSELF/B[VE/AJ/BOB/CHN/BUST/EICE/AKEEP/C"
  348.   WordList$(38)="NNEDY/CPT/BIND/BNEW/COW/ELEDGE/EN/AL/BABOR/CCK/CND/DGUAGE/CR"
  349.   WordList$(39)="GE/FR/CST/CTE/ER/DTER/CW/CY/BEAD/EERS/DRNED/DST/DVE/CD/CFT/C"
  350.   WordList$(40)="NGTH/CSS/CT/DTER/GS/CVEL/BIFE/CGHT/CKE/CNE/ES/CST/CTERATURE/"
  351.   WordList$(41)="DTLE/CVE/ED/DING/BOCAL/CNG/EER/COK/EED/EING/CST/CT/CVE/CW/DE"
  352.   WordList$(42)="R/AM/BADE/CIN/CJOR/CKE/ES/DING/CN/DNER/DS/DY/CRCH/DKET/DRIED"
  353.   WordList$(43)="/CSS/CTERIAL/DTER/CY/DBE/BE/CAN/EING/ES/CDICAL/CET/EING/CMBE"
  354.   WordList$(44)="R/GS/CN/CRELY/CT/DHOD/GS/BIDDLE/CGHT/CLES/DITARY/DLION/CND/D"
  355.   WordList$(45)="UTES/CSS/BODERN/CMENT/CNEY/DTH/FS/CRAL/DE/DNING/CST/CTHER/CV"
  356.   WordList$(46)="E/ED/EMENT/DING/BR/CS/BUCH/CSIC/DT/BY/CSELF/AN/BAME/CTION/GA"
  357.   WordList$(47)="L/GS/DURAL/FE/BEAR/ELY/CCESSARY/CED/EED/ES/CGRO/CITHER/CVER/"
  358.   WordList$(48)="CW/CXT/BIGHT/BO/CN/CR/DMAL/DTH/CT/DE/DHING/CW/BUCLEAR/CMBER/"
  359.   WordList$(49)="GS/AOBTAINED/CVIOUSLY/BF/CF/DICE/CTEN/BH/BLD/BN/CCE/CE/DS/D["
  360.   WordList$(50)="S/CLY/BPEN/EED/DRATION/CPORTUNITY/BR/CDER/CGANIZATION/BTHER/"
  361.   WordList$(51)="FS/BUR/CT/DSIDE/BVER/BWN/AP/BAID/CPER/CRT/EICULAR/KLY/ES/EY/"
  362.   WordList$(52)="CSSED/DT/CTTERN/CY/BEACE/COPLE/CR/DFORMANCE/DHAPS/DIOD/DSON/"
  363.   WordList$(53)="GAL/GS/BHYSICAL/BICTURE/CECE/BLACE/DN/EE/ENING/ES/ET/DY/BOIN"
  364.   WordList$(54)="T/FS/CLICE/FY/ETICAL/COL/DR/CPULATION/CSITION/DSIBLE/DT/CWER"
  365.   WordList$(55)="/BRESENT/EIDENT/ES/FURE/CICE/DNCIPLE/DVATE/COBABLY/ELEM/HS/D"
  366.   WordList$(56)="CESS/DDUCTION/HS/DGRAM/HS/FESS/DPERTY/DVIDE/HD/BUBLIC/CRPOSE"
  367.   WordList$(57)="/CT/AQUALITY/CESTION/IS/CITE/AR/BACE/CDIO/CN/DGE/CTE/DHER/BE"
  368.   WordList$(58)="ACHED/ETION/DD/EING/EY/DL/ELY/DSON/CCEIVED/ENT/GLY/DORD/CD/C"
  369.   WordList$(59)="LIGION/HUS/CMEMBER/CPORT/GED/CQUIRED/CSEARCH/DPECT/EONSIBILI"
  370.   WordList$(60)="TY/DT/DULT/GS/CTURN/GED/BIGHT/CVER/BOAD/COM/BUN/DNING/AS/BAI"
  371.   WordList$(61)="D/CLES/CME/CT/CW/CY/DING/DS/BCHOOL/GS/CIENCE/BEASON/CCOND/DR"
  372.   WordList$(62)="ETARY/DTION/CE/DM/EED/ES/DN/CLF/CNSE/DT/CRIES/EOUS/DVED/EICE"
  373.   WordList$(63)="/HS/CT/CVEN/ERAL/BHALL/CE/CORT/DT/DULD/DW/EED/EN/BIDE/CMILAR"
  374.   WordList$(64)="/DPLE/FY/CNCE/DGLE/CTUATION/CX/CZE/BLOWLY/BMALL/BO/CCIAL/EET"
  375.   WordList$(65)="Y/CME/ETHING/FIMES/EWHAT/CN/CON/CRT/CUND/DTH/FERN/CVIET/BPAC"
  376.   WordList$(66)="E/CEAK/DCIAL/FFIC/CIRIT/CRING/BQUARE/BT/CAFF/DGE/DND/FARD/DR"
  377.   WordList$(67)="T/FED/DTE/FMENTS/FS/DY/CEP/ES/CILL/COCK/DOD/DP/EPED/DRY/CRAI"
  378.   WordList$(68)="GHT/DEET/ENGTH/DONG/CUDENT/HS/EY/BUBJECT/CCH/CDDENLY/CMMER/C"
  379.   WordList$(69)="N/CPPORT/CRE/DFACE/BYSTEM/AT/BABLE/CKE/EN/DING/CLK/CX/BECHNI"
  380.   WordList$(70)="CAL/CLL/CMPERATURE/CN/CRM/ES/CST/BH/CAN/DT/ES/CE/DIR/DM/ESEL"
  381.   WordList$(71)="VES/DN/DORY/DRE/FFORE/F[S/DSE/DY/CING/FS/EK/FING/DRD/ETY/DS/"
  382.   WordList$(72)="COSE/DUGHT/CREE/DOUGH/HOUT/CUS/BIME/ES/BO/CDAY/CGETHER/CLD/C"
  383.   WordList$(73)="O/DK/CP/CTAL/CWARD/DN/BRADE/DINING/CIAL/DED/COUBLE/CUE/DTH/C"
  384.   WordList$(74)="Y/DING/BURN/EED/BWENTY/CO/BYPE/ES/AU/BNLIKELY/CDER/FSTAND/CI"
  385.   WordList$(75)="ON/DTED/DVERSITY/CTIL/BP/CON/BS/CE/DD/CING/CUALLY/AVALUE/FS/"
  386.   WordList$(76)="CRIOUS/BERY/BIEW/BOICE/CLUME/AWAITING/CLKED/DL/CNT/EED/CR/CS"
  387.   WordList$(77)="/DHINGTON/DN[T/CTER/CY/DS/BE/CEK/ES/CLL/CNT/CRE/CST/EERN/BHA"
  388.   WordList$(78)="T/EEVER/CEN/DRE/DTHER/CICH/DLE/DTE/CO/DLE/DM/DSE/CY/BIDE/CFE"
  389.   WordList$(79)="/CLL/EIAM/CNDOW/CSH/CTH/EIN/EOUT/BOMAN/DEN/CRD/ES/DK/EED/EIN"
  390.   WordList$(80)="G/ES/DLD/CULD/FN[T/BRITTEN/CONG/DTE/AYEAR/ES/CS/CT/BORK/CU/D"
  391.   WordList$(81)="NG/DR/D[RE/!"
  392.   LineNum&=1
  393.   CharNum%=1
  394.   PreviousWord$=""
  395.   Pattern&=Malloc&:(256)
  396.   IF Pattern& = 0
  397.     FatalError%=True%
  398.     PRINT "Fatal error:  out of memory."
  399.   ELSE
  400.     DO
  401.       GetWordListWord:(PreviousWord$)
  402.       IF (NOT FatalError%) AND (Word$ <> "")
  403.         PreviousWord$=Word$
  404.         GetPatternForPlaintextWord:(Pattern&)
  405.         IF (Alphabetic%)
  406.           AddPlaintext:(PatternHead&,Pattern&,Word$)
  407.         ENDIF
  408.       ENDIF
  409.     UNTIL FatalError% OR (Word$ = "")
  410.     FREEALLOC Pattern&
  411.   ENDIF
  412.   RETURN
  413. ENDP
  414.  
  415. PROC GetMaxDistinctLettersPerWord:(EncipheredHead&)
  416.   EXTERNAL EncipheredPtrForMax&
  417.   EXTERNAL MaxDistinctLettersPerWord
  418.   EXTERNAL NumDistinctWords&
  419.   LOCAL EncipheredPtr1&
  420.   LOCAL NumDistinctLettersPerWord
  421.   LOCAL PatternPtr&
  422.   LOCAL PlaintextCount&
  423.  
  424.   MaxDistinctLettersPerWord=0.0
  425.   EncipheredPtr1&=EncipheredHead&
  426.   WHILE EncipheredPtr1& <> 0
  427.     PatternPtr&=PEEKL(EncipheredPtr1&+4)
  428.     PlaintextCount&=PEEKL(PatternPtr&+8)
  429.     IF PlaintextCount& <> 0
  430.       NumDistinctLettersPerWord=FLT(PEEKL(PatternPtr&))/FLT(PlaintextCount&)
  431.       IF NumDistinctLettersPerWord > MaxDistinctLettersPerWord
  432.         MaxDistinctLettersPerWord=NumDistinctLettersPerWord
  433.         EncipheredPtrForMax&=EncipheredPtr1&
  434.       ENDIF
  435.     ENDIF
  436.     EncipheredPtr1&=PEEKL(EncipheredPtr1&+12)
  437.   ENDWH
  438.   RETURN
  439. ENDP
  440.  
  441. PROC Sort:
  442.   EXTERNAL CiphertextCharPtr&
  443.   EXTERNAL EncipheredHead&
  444.   EXTERNAL EncipheredPtrForMax&
  445.   EXTERNAL FatalError%
  446.   EXTERNAL NumDistinctWords&
  447.   EXTERNAL SortedHead&
  448.   LOCAL CipherTextChar%
  449.   LOCAL DuplicateWord%
  450.   LOCAL EncipheredPtr1&
  451.   LOCAL EncipheredPtr2&
  452.   LOCAL LetterNum%
  453.   LOCAL LetterUsed%(27)
  454.   LOCAL MaxMatchingLetters%
  455.   LOCAL NumMatchingLetters%
  456.   LOCAL PatternPtr&
  457.   LOCAL SortedPtr&
  458.   LOCAL SortedTail&
  459.  
  460.   POKEL EncipheredPtrForMax&+8,SortedHead&
  461.   POKEL SortedHead&,PEEKL(EncipheredPtrForMax&)
  462.   PatternPtr&=PEEKL(EncipheredPtrForMax&+4)
  463.   POKEL SortedHead&+4,PatternPtr&
  464.   POKEL SortedHead&+8,PEEKL(PatternPtr&+12)
  465.   POKEL SortedHead&+12,0
  466.   POKEL SortedHead&+16,0
  467.   SortedTail&=SortedHead&
  468.   LetterNum%=1
  469.   WHILE LetterNum% <= AlphabetSize%
  470.     LetterUsed%(LetterNum%)=False%
  471.     LetterNum%=LetterNum%+1
  472.   ENDWH
  473.   CiphertextCharPtr&=PEEKL(EncipheredPtrForMax&)
  474.   CiphertextChar%=PEEKB(CiphertextCharPtr&)
  475.   WHILE CiphertextChar% <> 0
  476.     IF CiphertextChar% <> Apostrophe%
  477.       LetterUsed%((ToLower%:(CiphertextChar%)-LowercaseA%)+1)=True%
  478.     ENDIF
  479.     CiphertextCharPtr&=CiphertextCharPtr&+1
  480.     CiphertextChar%=PEEKB(CiphertextCharPtr&)
  481.   ENDWH
  482.   EncipheredPtr1&=PEEKL(EncipheredHead&+12)
  483.   WHILE (NOT FatalError%) AND (EncipheredPtr1& <> 0)
  484.     MaxMatchingLetters%=0
  485.     EncipheredPtrForMax&=0
  486.     EncipheredPtr2&=EncipheredHead&
  487.     WHILE EncipheredPtr2& <> 0
  488.       IF PEEKL(EncipheredPtr2&+8) = 0
  489.         NumMatchingLetters%=0
  490.         CiphertextCharPtr&=PEEKL(EncipheredPtr2&)
  491.         WHILE PEEKB(CiphertextCharPtr&) <> 0
  492.           IF PEEKB(CiphertextCharPtr&) <> Apostrophe%
  493.             IF LetterUsed%((ToLower%:(PEEKB(CiphertextCharPtr&))-LowercaseA%)+1)
  494.               NumMatchingLetters%=NumMatchingLetters%+1
  495.             ENDIF
  496.           ENDIF
  497.           CiphertextCharPtr&=CiphertextCharPtr&+1
  498.         ENDWH
  499.         IF NumMatchingLetters% >= MaxMatchingLetters%
  500.           MaxMatchingLetters%=NumMatchingLetters%
  501.           EncipheredPtrForMax&=EncipheredPtr2&
  502.         ENDIF
  503.       ENDIF
  504.       EncipheredPtr2&=PEEKL(EncipheredPtr2&+12)
  505.     ENDWH
  506.     DuplicateWord%=False%
  507.     EncipheredPtr2&=EncipheredHead&
  508.     WHILE (NOT DuplicateWord%) AND (EncipheredPtr2& <> 0)
  509.       IF PEEKL(EncipheredPtr2&+8)
  510.         IF StrICmp%:(PEEKL(EncipheredPtr2&),PEEKL(EncipheredPtrForMax&)) <> 0
  511.           EncipheredPtr2&=PEEKL(EncipheredPtr2&+12)
  512.         ELSE
  513.           DuplicateWord%=True%
  514.         ENDIF
  515.       ELSE
  516.         EncipheredPtr2&=PEEKL(EncipheredPtr2&+12)
  517.       ENDIF
  518.     ENDWH
  519.     IF DuplicateWord%
  520.       POKEL EncipheredPtrForMax&+8,PEEKL(EncipheredPtr2&+8)
  521.     ELSE
  522.       SortedPtr&=Malloc&:(20)
  523.       IF SortedPtr& = 0
  524.         FatalError%=True%
  525.         PRINT "Fatal error:  out of memory."
  526.       ELSE
  527.         NumDistinctWords&=NumDistinctWords&+1
  528.         POKEL EncipheredPtrForMax&+8,SortedPtr&
  529.         POKEL SortedPtr&,PEEKL(EncipheredPtrForMax&)
  530.         PatternPtr&=PEEKL(EncipheredPtrForMax&+4)
  531.         POKEL SortedPtr&+4,PatternPtr&
  532.         POKEL SortedPtr&+8,PEEKL(PatternPtr&+12)
  533.         POKEL SortedTail&+16,SortedPtr&
  534.         POKEL SortedPtr&+12,SortedTail&
  535.         POKEL SortedPtr&+16,0
  536.         SortedTail&=SortedPtr&
  537.         CiphertextCharPtr&=PEEKL(EncipheredPtrForMax&)
  538.         CiphertextChar%=PEEKB(CiphertextCharPtr&)
  539.         WHILE CiphertextChar% <> 0
  540.           IF CiphertextChar% <> Apostrophe%
  541.             LetterUsed%((ToLower%:(CiphertextChar%)-LowercaseA%)+1)=True%
  542.           ENDIF
  543.           CiphertextCharPtr&=CiphertextCharPtr&+1
  544.           CiphertextChar%=PEEKB(CiphertextCharPtr&)
  545.         ENDWH
  546.       ENDIF
  547.     ENDIF
  548.     EncipheredPtr1&=PEEKL(EncipheredPtr1&+12)
  549.   ENDWH
  550.   RETURN
  551. ENDP
  552.  
  553. PROC GetEncipheredChar%:
  554.   EXTERNAL CiphertextCharPtr&
  555.   EXTERNAL CiphertextPtr&
  556.   LOCAL EncipheredChar%
  557.  
  558.   IF CiphertextPtr& = 0
  559.     EncipheredChar%=EOF%
  560.   ELSE
  561.     EncipheredChar%=PEEKB(CiphertextCharPtr&)
  562.     CiphertextCharPtr&=CiphertextCharPtr&+1
  563.     IF PEEKB(CiphertextCharPtr&) = 0
  564.       CiphertextPtr&=PEEKL(CiphertextPtr&+4)
  565.       IF CiphertextPtr& <> 0
  566.         CiphertextCharPtr&=PEEKL(CiphertextPtr&)
  567.       ENDIF
  568.     ENDIF
  569.   ENDIF
  570.   RETURN EncipheredChar%
  571. ENDP
  572.     
  573. PROC StrICmp%:(Str1&,Str2&)
  574.   LOCAL CharPtr1&
  575.   LOCAL CharPtr2&
  576.   LOCAL Char1%
  577.   LOCAL Char2%
  578.   LOCAL Result%
  579.  
  580.   Result%=0
  581.   CharPtr1&=Str1&
  582.   CharPtr2&=Str2&
  583.   Char1%=PEEKB(CharPtr1&)
  584.   Char2%=PEEKB(CharPtr2&)
  585.   WHILE (Result% = 0) AND (Char1% <> 0)
  586.     Result%=Char1%-Char2%
  587.     IF Result% = 0
  588.       CharPtr1&=CharPtr1&+1
  589.       Char1%=PEEKB(CharPtr1&)
  590.       CharPtr2&=CharPtr2&+1
  591.       Char2%=PEEKB(CharPtr2&)
  592.     ENDIF
  593.   ENDWH
  594.   RETURN Result%
  595. ENDP
  596.  
  597. PROC Solve:(NumDistinctWords&,EncipheredHead&,SortedHead&,KeepOnlyTheBest%,CiphertextHead&)
  598.   EXTERNAL CiphertextCharPtr&
  599.   EXTERNAL CiphertextPtr&
  600.   EXTERNAL FatalError%
  601.   GLOBAL Contradiction%
  602.   GLOBAL Decipherment$(27,1)
  603.   GLOBAL DeciphermentCount&(27)
  604.   GLOBAL Encipherment$(27,1)
  605.   GLOBAL EnciphermentCount&(27)
  606.   GLOBAL KeyPressed%
  607.   GLOBAL MaxScore&
  608.   GLOBAL NumPossibleSolutions&
  609.   GLOBAL Score&
  610.   GLOBAL SortedPtr&     
  611.   GLOBAL WordNum&
  612.   LOCAL Borrow%
  613.   LOCAL CharPtr1&
  614.   LOCAL CharPtr2&
  615.   LOCAL CurrentChar%
  616.   LOCAL DecipheredChar$(1)
  617.   LOCAL DecipheredIndex%
  618.   LOCAL EncipheredChar%
  619.   LOCAL EncipheredIndex%
  620.  
  621.   NumPossibleSolutions&=0
  622.   CurrentChar%=1
  623.   WHILE CurrentChar% <= AlphabetSize%
  624.     Decipherment$(CurrentChar%)=""
  625.     DeciphermentCount&(CurrentChar%)=0
  626.     Encipherment$(CurrentChar%)=""
  627.     EnciphermentCount&(CurrentChar%)=0
  628.     CurrentChar%=CurrentChar%+1
  629.   ENDWH
  630.   Score&=0
  631.   MaxScore&=0
  632.   SortedPtr&=SortedHead&
  633.   WordNum&=0
  634.   KeyPressed%=False%
  635.   WHILE (SortedPtr& <> 0) AND (NOT KeyPressed%)
  636.     CharPtr1&=PEEKL(PEEKL(SortedPtr&+8))
  637.     IF PEEKB(CharPtr1&) <> 0
  638.       Score&=Score&+1
  639.     ENDIF
  640.     WordNum&=WordNum&+1
  641.     Contradiction%=False%
  642.     IF PEEKB(CharPtr1&) <> 0
  643.       REM Word in dictionary
  644.       CharPtr2&=PEEKL(SortedPtr&)
  645.       WHILE (NOT Contradiction%) AND (PEEKB(CharPtr2&) <> 0)
  646.         IF PEEKB(CharPtr1&) <> Apostrophe%
  647.           DecipheredChar$=CHR$(ToLower%:(PEEKB(CharPtr1&)))
  648.           EncipheredChar%=ToLower%:(PEEKB(CharPtr2&))
  649.           EncipheredIndex%=(EncipheredChar%-LowercaseA%)+1
  650.           IF DeciphermentCount&(EncipheredIndex%) <> 0
  651.             IF Decipherment$(EncipheredIndex%) = DecipheredChar$
  652.               DeciphermentCount&(EncipheredIndex%)=DeciphermentCount&(EncipheredIndex%)+1
  653.             ELSE
  654.               Contradiction%=True%
  655.             ENDIF
  656.           ELSE
  657.             Decipherment$(EncipheredIndex%)=DecipheredChar$
  658.             DeciphermentCount&(EncipheredIndex%)=1
  659.           ENDIF
  660.           DecipheredIndex%=(ASC(DecipheredChar$)-LowercaseA%)+1
  661.           IF EnciphermentCount&(DecipheredIndex%) <> 0
  662.             IF ASC(Encipherment$(DecipheredIndex%)) = EncipheredChar%
  663.               EnciphermentCount&(DecipheredIndex%)=EnciphermentCount&(DecipheredIndex%)+1
  664.             ELSE
  665.               Contradiction%=True%
  666.             ENDIF
  667.           ELSE
  668.             Encipherment$(DecipheredIndex%)=CHR$(EncipheredChar%)
  669.             EnciphermentCount&(DecipheredIndex%)=1
  670.           ENDIF
  671.         ENDIF
  672.         CharPtr1&=CharPtr1&+1
  673.         CharPtr2&=CharPtr2&+1
  674.       ENDWH
  675.     ELSE
  676.       REM Word not in dictionary
  677.       IF Score&+NumDistinctWords&-WordNum& < MaxScore&
  678.         Contradiction%=True%
  679.       ENDIF
  680.     ENDIF
  681.     IF Contradiction%
  682.       GoBackward:
  683.     ELSE
  684.       GoForward:(KeepOnlyTheBest%,EncipheredHead&,CiphertextHead&)
  685.     ENDIF
  686.     IF NOT KeyPressed%
  687.       IF KEY
  688.         KeyPressed%=True%
  689.       ENDIF
  690.     ENDIF
  691.   ENDWH
  692.   IF NOT FatalError%
  693.     IF NumPossibleSolutions& = 0
  694.       PRINT "No solutions were found."
  695.     ENDIF
  696.   ENDIF
  697.   RETURN
  698. ENDP
  699.  
  700. PROC GoForward:(KeepOnlyTheBest%,EncipheredHead&,CiphertextHead&)
  701.   EXTERNAL CiphertextCharPtr&
  702.   EXTERNAL CiphertextPtr&
  703.   EXTERNAL Contradiction%
  704.   EXTERNAL Decipherment$()
  705.   EXTERNAL DeciphermentCount&()
  706.   EXTERNAL Encipherment$()
  707.   EXTERNAL EnciphermentCount&()
  708.   EXTERNAL KeyPressed%
  709.   EXTERNAL MaxScore&
  710.   EXTERNAL NumPossibleSolutions&
  711.   EXTERNAL Score&
  712.   EXTERNAL SortedPtr&
  713.   EXTERNAL WordNum&
  714.   LOCAL Borrow%
  715.   LOCAL CharPtr1&
  716.   LOCAL CharPtr2&
  717.   LOCAL Count&
  718.   LOCAL DecipheredChar$(1)
  719.   LOCAL DecipheredIndex%
  720.   LOCAL EncipheredChar%
  721.   LOCAL EncipheredIndex%
  722.  
  723.   IF PEEKL(SortedPtr&+16) <> 0
  724.     SortedPtr&=PEEKL(SortedPtr&+16)
  725.   ELSE
  726.     IF Score& > MaxScore&
  727.       MaxScore&=Score&
  728.       IF KeepOnlyTheBest%
  729.         REM Delete previous solutions from display.
  730.         NumPossibleSolutions&=0
  731.       ENDIF
  732.     ENDIF
  733.     OutputSolution:(EncipheredHead&,CiphertextHead&)
  734.     IF PEEKB(PEEKL(PEEKL(SortedPtr&+8))) <> 0
  735.       Score&=Score&-1
  736.     ENDIF
  737.     WordNum&=WordNum&-1
  738.     Borrow%=True%
  739.     WHILE Borrow% AND (SortedPtr& <> 0) AND (NOT KeyPressed%)
  740.       CharPtr1&=PEEKL(PEEKL(SortedPtr&+8))
  741.       IF PEEKB(CharPtr1&) <> 0
  742.         Contradiction%=False%
  743.         CharPtr2&=PEEKL(SortedPtr&)
  744.         WHILE (NOT Contradiction%) AND (PEEKB(CharPtr2&) <> 0)
  745.           IF PEEKB(CharPtr1&) <> Apostrophe%
  746.             DecipheredChar$=CHR$(ToLower%:(PEEKB(CharPtr1&)))
  747.             EncipheredChar%=ToLower%:(PEEKB(CharPtr2&))
  748.             EncipheredIndex%=(EncipheredChar%-LowercaseA%)+1
  749.             IF Decipherment$(EncipheredIndex%) = DecipheredChar$
  750.               Count&=DeciphermentCount&(EncipheredIndex%)-1
  751.               DeciphermentCount&(EncipheredIndex%)=Count&
  752.               IF Count& = 0
  753.                 Decipherment$(EncipheredIndex%)=""
  754.               ENDIF
  755.             ELSE
  756.              Contradiction%=True%
  757.             ENDIF
  758.             DecipheredIndex%=(ASC(DecipheredChar$)-LowercaseA%)+1
  759.             IF ASC(Encipherment$(DecipheredIndex%)) = EncipheredChar%
  760.               Count&=EnciphermentCount&(DecipheredIndex%)-1
  761.               EnciphermentCount&(DecipheredIndex%)=Count&
  762.               IF Count& = 0
  763.                 Encipherment$(DecipheredIndex%)=""
  764.               ENDIF
  765.             ELSE
  766.               Contradiction%=True%
  767.             ENDIF
  768.           ENDIF
  769.           CharPtr1&=CharPtr1&+1
  770.           CharPtr2&=CharPtr2&+1
  771.         ENDWH
  772.       ENDIF
  773.       POKEL SortedPtr&+8,PEEKL(PEEKL(SortedPtr&+8)+4)
  774.       IF PEEKL(SortedPtr&+8) <> 0
  775.         Borrow%=False%
  776.       ELSE
  777.         POKEL SortedPtr&+8,PEEKL(PEEKL(SortedPtr&+4)+12)
  778.         SortedPtr&=PEEKL(SortedPtr&+12)
  779.         IF SortedPtr& <> 0
  780.           IF PEEKB(PEEKL(PEEKL(SortedPtr&+8))) <> 0
  781.             Score&=Score&-1
  782.           ENDIF
  783.         ENDIF
  784.         WordNum&=WordNum&-1
  785.       ENDIF
  786.       IF KEY
  787.         KeyPressed%=True%
  788.       ENDIF
  789.     ENDWH
  790.   ENDIF
  791.   RETURN
  792. ENDP
  793.  
  794. PROC GoBackward:
  795.   EXTERNAL Contradiction%
  796.   EXTERNAL Decipherment$()
  797.   EXTERNAL DeciphermentCount&()
  798.   EXTERNAL Encipherment$()
  799.   EXTERNAL EnciphermentCount&()
  800.   EXTERNAL KeyPressed%
  801.   EXTERNAL Score&
  802.   EXTERNAL SortedPtr&     
  803.   EXTERNAL WordNum&
  804.   LOCAL Borrow%
  805.   LOCAL CharPtr1&
  806.   LOCAL CharPtr2&
  807.   LOCAL Count&
  808.   LOCAL DecipheredChar$(1)
  809.   LOCAL DecipheredIndex%
  810.   LOCAL EncipheredChar%
  811.   LOCAL EncipheredIndex%
  812.  
  813.   IF PEEKB(PEEKL(PEEKL(SortedPtr&+8))) <> 0
  814.     Score&=Score&-1
  815.   ENDIF
  816.   WordNum&=WordNum&-1
  817.   Borrow%=True%
  818.   WHILE Borrow% AND (SortedPtr& <> 0) AND (NOT KeyPressed%)
  819.     CharPtr1&=PEEKL(PEEKL(SortedPtr&+8))
  820.     IF PEEKB(CharPtr1&) <> 0
  821.       Contradiction%=False%
  822.       CharPtr2&=PEEKL(SortedPtr&)
  823.       WHILE (NOT Contradiction%) AND (PEEKB(CharPtr2&) <> 0)
  824.         IF PEEKB(CharPtr1&) <> Apostrophe%
  825.           DecipheredChar$=CHR$(Tolower%:(PEEKB(CharPtr1&)))
  826.           EncipheredChar%=ToLower%:(PEEKB(CharPtr2&))
  827.           EncipheredIndex%=(EncipheredChar%-LowercaseA%)+1
  828.           IF Decipherment$(EncipheredIndex%) = DecipheredChar$
  829.             Count&=DeciphermentCount&(EncipheredIndex%)-1
  830.             DeciphermentCount&(EncipheredIndex%)=Count&
  831.             IF Count& = 0
  832.               Decipherment$(EncipheredIndex%)=""
  833.             ENDIF
  834.           ELSE
  835.            Contradiction%=True%
  836.           ENDIF
  837.           DecipheredIndex%=(ASC(DecipheredChar$)-LowercaseA%)+1
  838.           IF ASC(Encipherment$(DecipheredIndex%)) = EncipheredChar%
  839.             Count&=EnciphermentCount&(DecipheredIndex%)-1
  840.             EnciphermentCount&(DecipheredIndex%)=Count&
  841.             IF Count& = 0
  842.               Encipherment$(DecipheredIndex%)=""
  843.             ENDIF
  844.           ELSE
  845.             Contradiction%=True%
  846.           ENDIF
  847.         ENDIF
  848.         CharPtr1&=CharPtr1&+1
  849.         CharPtr2&=CharPtr2&+1
  850.       ENDWH
  851.     ENDIF
  852.     POKEL SortedPtr&+8,PEEKL(PEEKL(SortedPtr&+8)+4)
  853.     IF PEEKL(SortedPtr&+8) <> 0
  854.       Borrow%=False%
  855.     ELSE
  856.       POKEL SortedPtr&+8,PEEKL(PEEKL(SortedPtr&+4)+12)
  857.       SortedPtr&=PEEKL(SortedPtr&+12)
  858.       IF SortedPtr& <> 0
  859.         IF PEEKB(PEEKL(PEEKL(SortedPtr&+8))) <> 0
  860.           Score&=Score&-1
  861.         ENDIF
  862.       ENDIF
  863.       WordNum&=WordNum&-1
  864.     ENDIF
  865.     IF KEY
  866.       KeyPressed%=True%
  867.     ENDIF
  868.   ENDWH
  869.   RETURN
  870. ENDP
  871.  
  872. PROC OutputSolution:(EncipheredHead&,CiphertextHead&)
  873.   EXTERNAL CiphertextCharPtr&
  874.   EXTERNAL CiphertextPtr&
  875.   EXTERNAL Decipherment$()
  876.   EXTERNAL DeciphermentCount&()
  877.   EXTERNAL NumPossibleSolutions&
  878.   LOCAL CurrentChar%
  879.   LOCAL EncipheredIndex%
  880.   LOCAL EncipheredPtr&
  881.   LOCAL EndOfFile%
  882.   LOCAL Letter%
  883.   LOCAL PlaintextChar%
  884.   LOCAL PlaintextCharPtr& 
  885.  
  886.   CiphertextPtr&=CiphertextHead&
  887.   CiphertextCharPtr&=PEEKL(CiphertextHead&)
  888.   NumPossibleSolutions&=NumPossibleSolutions&+1
  889.   EncipheredPtr&=EncipheredHead&
  890.   PRINT
  891.   DO
  892.     EndOfFile%=False%
  893.     Letter%=False%
  894.     WHILE (NOT EndOfFile%) AND (NOT Letter%)
  895.       CurrentChar%=GetEncipheredChar%:
  896.       IF CurrentChar% = EOF%
  897.         EndOfFile%=True%
  898.       ELSE
  899.         IF CurrentChar% = Apostrophe%
  900.           Letter%=True%
  901.         ELSE
  902.           IF IsLower%:(CurrentChar%)
  903.             Letter%=True%
  904.           ELSE
  905.             IF IsUpper%:(CurrentChar%)
  906.               Letter%=True%
  907.             ELSE
  908.               IF CurrentChar% = 10
  909.                 PRINT
  910.               ELSE
  911.                 PRINT CHR$(CurrentChar%);
  912.               ENDIF
  913.             ENDIF
  914.           ENDIF
  915.         ENDIF
  916.       ENDIF
  917.     ENDWH
  918.     IF CurrentChar% <> EOF%
  919.       PlaintextCharPtr&=PEEKL(PEEKL(PEEKL(EncipheredPtr&+8)+8))
  920.       PlaintextChar%=PEEKB(PlaintextCharPtr&)
  921.       IF PlaintextChar% <> 0
  922.         DO
  923.           IF CurrentChar% = Apostrophe%
  924.             PRINT "'";
  925.           ELSE
  926.             IF IsLower%:(CurrentChar%)
  927.               CurrentChar%=ToLower%:(PlaintextChar%)
  928.             ELSE
  929.               CurrentChar%=ToUpper%:(PlaintextChar%)
  930.             ENDIF
  931.             PRINT CHR$(CurrentChar%);
  932.           ENDIF
  933.           PlaintextCharPtr&=PlaintextCharPtr&+1
  934.           PlaintextChar%=PEEKB(PlaintextCharPtr&)
  935.           CurrentChar%=GetEncipheredChar%:
  936.         UNTIL (CurrentChar% = EOF%) OR ((CurrentChar% <> Apostrophe%) AND (NOT IsLower%:(ToLower%:(CurrentChar%))))
  937.       ELSE
  938.         DO
  939.           IF CurrentChar% = Apostrophe%
  940.             PRINT CHR$(CurrentChar%);
  941.           ELSE
  942.             IF IsLower%:(CurrentChar%)
  943.               EncipheredIndex%=(CurrentChar%-LowercaseA%)+1
  944.               IF DeciphermentCount&(EncipheredIndex%) <> 0
  945.                 CurrentChar%=ToLower%:(ASC(Decipherment$(EncipheredIndex%)))
  946.               ELSE
  947.                 CurrentChar%=Asterisk%
  948.               ENDIF
  949.               PRINT CHR$(CurrentChar%);
  950.             ELSE
  951.               IF IsUpper%:(CurrentChar%)
  952.                 EncipheredIndex%=(CurrentChar%-UppercaseA%)+1
  953.                 IF DeciphermentCount&(EncipheredIndex%) <> 0
  954.                   CurrentChar%=ToUpper%:(ASC(Decipherment$(EncipheredIndex%)))
  955.                 ELSE
  956.                   CurrentChar%=Asterisk%
  957.                 ENDIF
  958.                 PRINT CHR$(CurrentChar%);
  959.               ELSE
  960.                 CurrentChar%=ToUpper%:(PEEKB(PlaintextCharPtr&))
  961.                 PRINT CHR$(CurrentChar%);
  962.               ENDIF
  963.             ENDIF
  964.           ENDIF
  965.           CurrentChar%=GetEncipheredChar%:
  966.         UNTIL (CurrentChar% = EOF%) OR ((CurrentChar% <> Apostrophe%) AND (NOT IsLower%:(ToLower%:(CurrentChar%))))
  967.       ENDIF
  968.       IF CurrentChar% <> EOF%
  969.         IF CurrentChar% = 10
  970.           PRINT
  971.         ELSE
  972.           PRINT CHR$(CurrentChar%);
  973.         ENDIF
  974.       ENDIF
  975.       EncipheredPtr&=PEEKL(EncipheredPtr&+12)
  976.     ENDIF
  977.   UNTIL CurrentChar% = EOF%
  978.   RETURN
  979. ENDP
  980.  
  981. PROC AddWordNotInWordList:(PatternPtr&)
  982.   EXTERNAL FatalError%
  983.   LOCAL Plaintext&
  984.   LOCAL PlaintextPtr&
  985.   PlaintextPtr&=Malloc&:(8)
  986.   IF PlaintextPtr& = 0
  987.     FatalError%=True%
  988.     PRINT "Fatal error:  out of memory."
  989.   ELSE
  990.     Plaintext&=Malloc&:(1)
  991.     IF Plaintext& = 0
  992.       FatalError%=True%
  993.       PRINT "Fatal error:  out of memory."
  994.     ELSE
  995.       POKEB Plaintext&,0
  996.       POKEL PlaintextPtr&,Plaintext&
  997.       POKEL PlaintextPtr&+4,0
  998.       POKEL PatternPtr&+12,PlaintextPtr&
  999.     ENDIF
  1000.   ENDIF
  1001.   RETURN
  1002. ENDP
  1003.  
  1004. PROC AddPlaintext:(PatternHead&,Pattern&,Plaintext$)
  1005.   EXTERNAL FatalError%
  1006.   LOCAL BytePtr&
  1007.   LOCAL Finished%
  1008.   LOCAL GreaterPtr&
  1009.   LOCAL InternalPtr&
  1010.   LOCAL LesserPtr&
  1011.   LOCAL NumPlaintextChars%
  1012.   LOCAL Plaintext2&
  1013.   LOCAL PlaintextCharNum%
  1014.   LOCAL PlaintextPtr&
  1015.   LOCAL Relation%
  1016.  
  1017.   InternalPtr&=PatternHead&
  1018.   Finished%=False%
  1019.   WHILE NOT Finished%
  1020.     Relation%=StrCmp%:(Pattern&,PEEKL(InternalPtr&+4))
  1021.     IF Relation% < 0
  1022.       LesserPtr&=PEEKL(InternalPtr&+16)
  1023.       IF LesserPtr& <> 0
  1024.         InternalPtr&=LesserPtr&
  1025.       ELSE
  1026.         Finished%=True%
  1027.       ENDIF
  1028.     ELSE
  1029.       IF Relation% > 0
  1030.         GreaterPtr&=PEEKL(InternalPtr&+20)
  1031.         IF GreaterPtr& <> 0
  1032.           InternalPtr&=GreaterPtr&
  1033.         ELSE
  1034.           Finished%=True%
  1035.         ENDIF
  1036.       ELSE
  1037.         PlaintextPtr&=Malloc&:(8)
  1038.         IF PlaintextPtr& = 0
  1039.           FatalError%=True%
  1040.           PRINT "Fatal error:  out of memory."
  1041.         ELSE
  1042.           NumPlaintextChars%=LEN(Plaintext$)
  1043.           Plaintext2&=Malloc&:(1+NumPlaintextChars%)
  1044.           IF Plaintext2& = 0
  1045.             FatalError%=True%
  1046.             PRINT "Fatal error:  out of memory."
  1047.             FREEALLOC PlaintextPtr&
  1048.           ELSE
  1049.             BytePtr&=Plaintext2&
  1050.             PlaintextCharNum%=1
  1051.             WHILE PlaintextCharNum% <= NumPlaintextChars%
  1052.               POKEB BytePtr&,ASC(MID$(Plaintext$,PlaintextCharNum%,1))
  1053.               BytePtr&=BytePtr&+1
  1054.               PlaintextCharNum%=PlaintextCharNum%+1
  1055.             ENDWH
  1056.             POKEB BytePtr&,0
  1057.             POKEL PlaintextPtr&,Plaintext2&
  1058.             POKEL InternalPtr&+8,PEEKL(InternalPtr&+8)+1
  1059.             POKEL PlaintextPtr&+4,PEEKL(InternalPtr&+12)
  1060.             POKEL InternalPtr&+12,PlaintextPtr&
  1061.           ENDIF
  1062.         ENDIF
  1063.         Finished%=True%
  1064.       ENDIF
  1065.     ENDIF
  1066.   ENDWH
  1067.   RETURN
  1068. ENDP
  1069.  
  1070. PROC GetPatternForPlaintextWord:(PatternPtr&)
  1071.   EXTERNAL Word$
  1072.   EXTERNAL Alphabetic%
  1073.   LOCAL CharNum1%
  1074.   LOCAL CharPtr2&
  1075.   LOCAL CharNum3%
  1076.   LOCAL CharPtr4&
  1077.   LOCAL CharValue%
  1078.   LOCAL CurrentChar$(1)
  1079.   LOCAL LowercaseWord$(255)
  1080.   LOCAL NumChars%
  1081.   LOCAL NumDistinctChars%
  1082.  
  1083.   Alphabetic%=True%
  1084.   CharNum1%=1
  1085.   NumChars%=LEN(Word$)
  1086.   CharPtr2&=PatternPtr&
  1087.   LowercaseWord$=""
  1088.   WHILE Alphabetic% AND (CharNum1% <= NumChars%)
  1089.     CurrentChar$=MID$(Word$,CharNum1%,1)
  1090.     IF CurrentChar$ = "'"
  1091.       LowercaseWord$=LowercaseWord$+"'"
  1092.     ELSE
  1093.       CharValue%=ToLower%:(ASC(CurrentChar$))
  1094.       LowercaseWord$=LowercaseWord$+CHR$(CharValue%)
  1095.       Alphabetic%=IsLower%:(CharValue%)
  1096.     ENDIF
  1097.     POKEB CharPtr2&,0
  1098.     CharPtr2&=CharPtr2&+1
  1099.     CharNum1%=CharNum1%+1
  1100.   ENDWH
  1101.   IF Alphabetic%
  1102.     POKEB CharPtr2&,0
  1103.     NumDistinctChars%=0
  1104.     CharNum1%=1
  1105.     CharPtr2&=PatternPtr&
  1106.     WHILE CharNum1% <= NumChars%
  1107.       IF PEEKB(CharPtr2&) = 0
  1108.         CurrentChar$=MID$(Word$,CharNum1%,1)
  1109.         IF CurrentChar$ = "'"
  1110.           POKEB CharPtr2&,AlphabetSize%
  1111.         ELSE
  1112.           NumDistinctChars%=NumDistinctChars%+1
  1113.           POKEB CharPtr2&,NumDistinctChars%
  1114.           CharNum3%=CharNum1%+1
  1115.           CharPtr4&=CharPtr2&+1
  1116.           WHILE CharNum3% <= NumChars%
  1117.             IF MID$(Word$,CharNum3%,1) = CurrentChar$
  1118.               POKEB CharPtr4&,NumDistinctChars%
  1119.             ENDIF
  1120.             CharPtr4&=CharPtr4&+1
  1121.             CharNum3%=CharNum3%+1
  1122.           ENDWH
  1123.         ENDIF
  1124.       ENDIF
  1125.       CharPtr2&=CharPtr2&+1
  1126.       CharNum1%=CharNum1%+1
  1127.     ENDWH
  1128.   ENDIF
  1129.   RETURN
  1130. ENDP
  1131.  
  1132. PROC FreePattern:(PatternPtr&)
  1133.   LOCAL PlaintextHead&
  1134.   LOCAL PlaintextPtr&
  1135.  
  1136.   IF PatternPtr& <> 0
  1137.     FreePattern:(PEEKL(PatternPtr&+16))
  1138.     FreePattern:(PEEKL(PatternPtr&+20))
  1139.     FREEALLOC PEEKL(PatternPtr&+4)
  1140.     PlaintextHead&=PEEKL(PatternPtr&+12)
  1141.     WHILE PlaintextHead& <> 0
  1142.       PlaintextPtr&=PEEKL(PlaintextHead&+4)
  1143.       FREEALLOC PEEKL(PlaintextHead&)
  1144.       FREEALLOC PlaintextHead&
  1145.       PlaintextHead&=PlaintextPtr&
  1146.     ENDWH
  1147.     FREEALLOC PatternPtr&
  1148.   ENDIF
  1149.   RETURN
  1150. ENDP
  1151.  
  1152. PROC PatternForWord&:(Word&,WordLen%)
  1153.   EXTERNAL FatalError%
  1154.   EXTERNAL NumDistinctLetters&
  1155.   LOCAL CharPtr1&
  1156.   LOCAL CharPtr2&
  1157.   LOCAL CharPtr3&
  1158.   LOCAL CharPtr4&
  1159.   LOCAL Char1%
  1160.   LOCAL Char3%
  1161.   LOCAL NumDistinctChars&
  1162.   LOCAL Pattern&
  1163.  
  1164.   Pattern&=Malloc&:(1+WordLen%)
  1165.   IF Pattern& = 0
  1166.     FatalError%=True%
  1167.     PRINT "Fatal error:  out of memory."
  1168.     NumDistinctLetters&=0
  1169.   ELSE
  1170.     CharPtr1&=Word&
  1171.     CharPtr2&=Pattern&
  1172.     WHILE PEEKB(CharPtr1&) <> 0
  1173.       POKEB CharPtr2&,0
  1174.       CharPtr2&=CharPtr2&+1
  1175.       CharPtr1&=CharPtr1&+1
  1176.     ENDWH
  1177.     POKEB CharPtr2&,0
  1178.     NumDistinctChars&=0
  1179.     CharPtr1&=Word&
  1180.     CharPtr2&=Pattern&
  1181.     Char1%=PEEKB(CharPtr1&)
  1182.     WHILE Char1% <> 0
  1183.       IF PEEKB(CharPtr2&) = 0
  1184.         IF Char1% = Apostrophe%
  1185.           POKEB CharPtr2&,AlphabetSize%
  1186.         ELSE
  1187.           NumDistinctChars&=NumDistinctChars&+1
  1188.           POKEB CharPtr2&,NumDistinctChars&
  1189.           CharPtr3&=CharPtr1&+1
  1190.           Char3%=PEEKB(CharPtr3&)
  1191.           CharPtr4&=CharPtr2&+1
  1192.           WHILE Char3% <> 0
  1193.             IF Char3% = Char1%
  1194.               POKEB CharPtr4&,NumDistinctChars&
  1195.             ENDIF
  1196.             CharPtr4&=CharPtr4&+1
  1197.             CharPtr3&=CharPtr3&+1
  1198.             Char3%=PEEKB(CharPtr3&)
  1199.           ENDWH
  1200.         ENDIF
  1201.       ENDIF
  1202.       CharPtr2&=CharPtr2&+1
  1203.       CharPtr1&=CharPtr1&+1
  1204.       Char1%=PEEKB(CharPtr1&)
  1205.     ENDWH
  1206.     NumDistinctLetters&=NumDistinctChars&
  1207.   ENDIF
  1208.   RETURN Pattern&
  1209. ENDP
  1210.  
  1211. PROC StrCmp%:(Str1&,Str2&)
  1212.   LOCAL CharPtr1&
  1213.   LOCAL CharPtr2&
  1214.   LOCAL Char1%
  1215.   LOCAL Char2%
  1216.   LOCAL Result%
  1217.  
  1218.   Result%=0
  1219.   CharPtr1&=Str1&
  1220.   CharPtr2&=Str2&
  1221.   Char1%=PEEKB(CharPtr1&)
  1222.   Char2%=PEEKB(CharPtr2&)
  1223.   WHILE (Result% = 0) AND (Char1% <> 0) AND (Char2% <> 0)
  1224.     Result%=Char1%-Char2%
  1225.     CharPtr1&=CharPtr1&+1
  1226.     Char1%=PEEKB(CharPtr1&)
  1227.     CharPtr2&=CharPtr2&+1
  1228.     Char2%=PEEKB(CharPtr2&)
  1229.   ENDWH
  1230.   IF Result% = 0
  1231.     Result%=Char1%-Char2%
  1232.   ENDIF
  1233.   RETURN Result%
  1234. ENDP
  1235.  
  1236. PROC PatternForEncipheredWord&:(EncipheredWord&,EncipheredWordLen%)
  1237.   EXTERNAL FatalError%
  1238.   EXTERNAL PatternHead&
  1239.   GLOBAL NumDistinctLetters&
  1240.   LOCAL ExternalPtr&
  1241.   LOCAL Finished%
  1242.   LOCAL GreaterPtr&
  1243.   LOCAL InternalPtr&
  1244.   LOCAL LesserPtr&
  1245.   LOCAL Relation%
  1246.   LOCAL Pattern&
  1247.  
  1248.   InternalPtr&=0
  1249.   Pattern&=PatternForWord&:(EncipheredWord&,EncipheredWordLen%)
  1250.   IF (NOT FatalError%)
  1251.     IF (PatternHead&)
  1252.       InternalPtr&=PatternHead&
  1253.       Finished%=False%
  1254.       DO
  1255.         Relation%=StrCmp%:(Pattern&,PEEKL(InternalPtr&+4))
  1256.         IF Relation% < 0
  1257.           LesserPtr&=PEEKL(InternalPtr&+16)
  1258.           IF LesserPtr& <> 0
  1259.             InternalPtr&=LesserPtr&
  1260.           ELSE
  1261.             ExternalPtr&=Malloc&:(24)
  1262.             IF ExternalPtr& = 0
  1263.               FatalError%=True%
  1264.               PRINT "Fatal error:  out of memory."
  1265.             ELSE
  1266.               POKEL ExternalPtr&+4,Pattern&
  1267.               POKEL ExternalPtr&,NumDistinctLetters&
  1268.               POKEL ExternalPtr&+8,0
  1269.               POKEL ExternalPtr&+12,0
  1270.               POKEL ExternalPtr&+16,0
  1271.               POKEL ExternalPtr&+20,0
  1272.               POKEL InternalPtr&+16,ExternalPtr&
  1273.             ENDIF
  1274.             InternalPtr&=ExternalPtr&
  1275.             Finished%=True%
  1276.           ENDIF
  1277.         ELSE
  1278.           IF Relation% > 0
  1279.             GreaterPtr&=PEEKL(InternalPtr&+20)
  1280.             IF GreaterPtr& <> 0
  1281.               InternalPtr&=GreaterPtr&
  1282.             ELSE
  1283.               ExternalPtr&=Malloc&:(24)
  1284.               IF ExternalPtr& = 0
  1285.                 FatalError%=True%
  1286.                 PRINT "Fatal error:  out of memory."
  1287.               ELSE
  1288.                 POKEL ExternalPtr&+4,Pattern&
  1289.                 POKEL ExternalPtr&,NumDistinctLetters&
  1290.                 POKEL ExternalPtr&+8,0
  1291.                 POKEL ExternalPtr&+12,0
  1292.                 POKEL ExternalPtr&+16,0
  1293.                 POKEL ExternalPtr&+20,0
  1294.                 POKEL InternalPtr&+20,ExternalPtr&
  1295.               ENDIF
  1296.               InternalPtr&=ExternalPtr&
  1297.               Finished%=True%
  1298.             ENDIF
  1299.           ELSE
  1300.             FREEALLOC Pattern&
  1301.             Finished%=True%
  1302.           ENDIF
  1303.         ENDIF
  1304.       UNTIL Finished%
  1305.     ELSE
  1306.       InternalPtr&=Malloc&:(24)
  1307.       IF InternalPtr& = 0
  1308.         FatalError%=True%
  1309.         PRINT "Fatal error:  out of memory."
  1310.       ELSE
  1311.         POKEL InternalPtr&+4,Pattern&
  1312.         POKEL InternalPtr&,NumDistinctLetters&
  1313.         POKEL InternalPtr&+8,0
  1314.         POKEL InternalPtr&+12,0
  1315.         POKEL InternalPtr&+16,0
  1316.         POKEL InternalPtr&+20,0
  1317.         PatternHead&=InternalPtr&
  1318.       ENDIF
  1319.     ENDIF
  1320.   ENDIF
  1321.   RETURN InternalPtr&
  1322. ENDP
  1323.  
  1324. PROC AddEncipheredWord&:(EncipheredWord$)
  1325.   EXTERNAL EncipheredHead&
  1326.   EXTERNAL EncipheredTail&
  1327.   EXTERNAL FatalError%
  1328.   EXTERNAL PatternHead&
  1329.   LOCAL Ciphertext&
  1330.   LOCAL BytePtr&
  1331.   LOCAL EncipheredWordIndex%
  1332.   LOCAL EncipheredWordLen%
  1333.   LOCAL ExternalPtr&
  1334.   LOCAL PatternPtr&
  1335.  
  1336.   PatternPtr&=0
  1337.   ExternalPtr&=Malloc&:(16)
  1338.   IF ExternalPtr& = 0
  1339.     FatalError%=True%
  1340.     PRINT "Fatal error:  out of memory."
  1341.   ELSE
  1342.     Ciphertext&=Malloc&:(1+LEN(EncipheredWord$))
  1343.     IF Ciphertext& = 0
  1344.       FatalError%=True%
  1345.       PRINT "Fatal error:  out of memory."
  1346.     ELSE
  1347.       BytePtr&=Ciphertext&
  1348.       EncipheredWordLen%=LEN(EncipheredWord$)
  1349.       EncipheredWordIndex%=1
  1350.       WHILE EncipheredWordIndex% <= EncipheredWordLen%
  1351.         POKEB BytePtr&,ASC(MID$(EncipheredWord$,EncipheredWordIndex%,1))
  1352.         BytePtr&=BytePtr&+1
  1353.         EncipheredWordIndex%=EncipheredWordIndex%+1
  1354.       ENDWH
  1355.       POKEB BytePtr&,0
  1356.       POKEL ExternalPtr&,Ciphertext&
  1357.       POKEL ExternalPtr&+8,0
  1358.       PatternPtr&=PatternForEncipheredWord&:(Ciphertext&,EncipheredWordLen%)
  1359.       POKEL ExternalPtr&+4,PatternPtr&
  1360.       POKEL ExternalPtr&+12,0
  1361.       IF EncipheredTail& <> 0
  1362.         POKEL EncipheredTail&+12,ExternalPtr&
  1363.       ELSE
  1364.         EncipheredHead&=ExternalPtr&
  1365.       ENDIF
  1366.       EncipheredTail&=ExternalPtr&
  1367.     ENDIF
  1368.   ENDIF
  1369.   RETURN PatternPtr&
  1370. ENDP
  1371.  
  1372. PROC GetWordListWord:(PreviousWord$)
  1373.   EXTERNAL CharNum%
  1374.   EXTERNAL FatalError%
  1375.   EXTERNAL LineNum&
  1376.   EXTERNAL Word$
  1377.   EXTERNAL WordList$()
  1378.   LOCAL CurrentChar%
  1379.   LOCAL DupCount%
  1380.  
  1381.   Word$=""
  1382.   DupCount%=GetWordListChar%:
  1383.   IF DupCount% <> EOF%
  1384.     IF (DupCount% >= UppercaseA%) AND (DupCount% <= UppercaseZ%)
  1385.       DupCount%=DupCount%-UppercaseA%
  1386.       IF DupCount% > 0
  1387.         Word$=LEFT$(PreviousWord$,DupCount%)
  1388.       ENDIF
  1389.       DO
  1390.         CurrentChar%=GetWordListChar%:
  1391.         IF CurrentChar% = EOF%
  1392.           FatalError%=True%
  1393.           PRINT "Fatal error:  premature end of word list."
  1394.         ELSE
  1395.           IF (CurrentChar% >= UppercaseA%) AND (CurrentChar% <= UppercaseZ%)
  1396.             Word$=Word$+CHR$(ToLower%:(CurrentChar%))
  1397.           ELSE
  1398.             IF CurrentChar% = UppercaseZ%+1
  1399.               Word$=Word$+"'"
  1400.             ELSE
  1401.               IF CurrentChar% <> Slash%
  1402.                 FatalError%=True%
  1403.                 PRINT "Fatal error:  unexpected character in word list."
  1404.               ENDIF
  1405.             ENDIF
  1406.           ENDIF
  1407.         ENDIF
  1408.       UNTIL FatalError% OR (CurrentChar% = Slash%)
  1409.     ELSE
  1410.       FatalError%=True%
  1411.       PRINT "Fatal error:  invalid dup count in word list."
  1412.     ENDIF
  1413.   ENDIF
  1414.   RETURN
  1415. ENDP
  1416.  
  1417. PROC GetWordListChar%:
  1418.   EXTERNAL CharNum%
  1419.   EXTERNAL LineNum&
  1420.   EXTERNAL WordList$()
  1421.   LOCAL CurrentChar$(1)
  1422.   LOCAL Result%
  1423.  
  1424.   CurrentChar$=MID$(WordList$(LineNum&),CharNum%,1)
  1425.   IF CurrentChar$ = "!"
  1426.     Result%=EOF%
  1427.   ELSE
  1428.     Result%=ASC(CurrentChar$)
  1429.     CharNum%=CharNum%+1
  1430.     IF CharNum% > LEN(WordList$(LineNum&))
  1431.       LineNum&=LineNum&+1
  1432.       CharNum%=1
  1433.     ENDIF
  1434.   ENDIF
  1435.   RETURN Result%
  1436. ENDP
  1437.  
  1438. PROC Malloc&:(NumBytes%)
  1439.   LOCAL Result&
  1440.  
  1441.   ONERR AllocFailed
  1442.   Result&=ALLOC(NumBytes%)
  1443.   ONERR OFF
  1444.   RETURN Result&
  1445. AllocFailed::
  1446.   RETURN 0
  1447. ENDP
  1448.  
  1449. PROC ToLower%:(CurrentChar%)
  1450.   LOCAL Result%
  1451.  
  1452.   IF CurrentChar% < UppercaseA%
  1453.     Result%=CurrentChar%
  1454.   ELSE
  1455.     IF CurrentChar% > UppercaseZ%
  1456.       Result%=CurrentChar%
  1457.     ELSE
  1458.       Result%=(CurrentChar%-UppercaseA%)+LowercaseA%
  1459.     ENDIF
  1460.   ENDIF
  1461.   RETURN Result%
  1462. ENDP
  1463.  
  1464. PROC ToUpper%:(CurrentChar%)
  1465.   LOCAL Result%
  1466.  
  1467.   IF CurrentChar% < LowercaseA%
  1468.     Result%=CurrentChar%
  1469.   ELSE
  1470.     IF CurrentChar% > LowercaseZ%
  1471.       Result%=CurrentChar%
  1472.     ELSE
  1473.       Result%=(CurrentChar%-LowercaseA%)+UppercaseA%
  1474.     ENDIF
  1475.   ENDIF
  1476.   RETURN Result%
  1477. ENDP
  1478.  
  1479. PROC IsLower%:(CurrentChar%)
  1480.   LOCAL Result%
  1481.  
  1482.   IF CurrentChar% < LowercaseA%
  1483.     Result%=False%
  1484.   ELSE
  1485.     IF CurrentChar% > LowercaseZ%
  1486.       Result%=False%
  1487.     ELSE
  1488.       Result%=True%
  1489.     ENDIF
  1490.   ENDIF
  1491.   RETURN Result%
  1492. ENDP
  1493.  
  1494. PROC IsUpper%:(CurrentChar%)
  1495.   LOCAL Result%
  1496.  
  1497.   IF CurrentChar% < UppercaseA%
  1498.     Result%=False%
  1499.   ELSE
  1500.     IF CurrentChar% > UppercaseZ%
  1501.       Result%=False%
  1502.     ELSE
  1503.       Result%=True%
  1504.     ENDIF
  1505.   ENDIF
  1506.   RETURN Result%
  1507. ENDP
  1508.  
  1509.  
  1510.  
  1511.