Task

Implement functions to encrypt and decrypt a message using the straddling checkerboard method. The checkerboard should take a 28 character alphabet (A-Z plus a full stop and an escape character) and two different numbers representing the blanks in the first row. The output will be a series of decimal digits.

Numbers should be encrypted by inserting the escape character before each digit, then including the digit unencrypted. This should be reversed for decryption.




Procedure.s encrypt_SC(originalText.s, alphabet.s, blank_1, blank_2)
  Static notEscape.s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ."
  Protected preDigit_1.s = Str(blank_1), preDigit_2.s = Str(blank_2)
  Protected i, index, curChar.s, escapeChar.s, outputText.s
  Protected NewMap cipher.s()
 
  ;build cipher reference
  alphabet = UCase(alphabet)
  For i = 1 To 28
    curChar = Mid(alphabet, i, 1)
    If Not FindString(notEscape, curChar)
      escapeChar = curChar
    EndIf 
 
    Select i
      Case 1 To 8
        If index = blank_1 Or index = blank_2: index + 1: EndIf ;adjust index for blank
 
        cipher(curChar) = Str(index)
        index + 1
      Case 9 To 18
        cipher(curChar) = preDigit_1 + Str(i - 9)
      Case 19 To 28
        cipher(curChar) = preDigit_2 + Str(i - 19)
    EndSelect
  Next
 
  For i = 0 To 9: cipher(Str(i)) = cipher(escapeChar) + Str(i): Next 
 
  ;encrypt each character
  originalText = UCase(originalText)
  Protected length = Len(originalText)
  For i = 1 To length
    outputText + cipher(Mid(originalText, i, 1))
  Next 
 
  ProcedureReturn outputText
EndProcedure
 
Procedure.s decrypt_SC(cipherText.s, alphabet.s, blank_1, blank_2)
  Static notEscape.s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ."
  Protected preDigit_1.s = Str(blank_1), preDigit_2.s = Str(blank_2)
  Protected i, index, curChar.s, escapeCipher.s, outputText.s
  Protected NewMap cipher.s()
 
  ;build decipher reference
  alphabet = UCase(alphabet)
  For i = 1 To 28
    curChar = Mid(alphabet, i, 1)
 
    Select i
      Case 1 To 8
        If index = blank_1 Or index = blank_2: index + 1: EndIf ;adjust index for blank
 
        cipher(Str(index)) = curChar
        index + 1
      Case 9 To 18
        cipher(preDigit_1 + Str(i - 9)) = curChar
      Case 19 To 28
        cipher(preDigit_2 + Str(i - 19)) = curChar
    EndSelect
    If Not FindString(notEscape, curChar)
      escapeCipher = MapKey(cipher())
    EndIf
  Next
 
  For i = 0 To 9: cipher(escapeCipher + Str(i)) = Str(i): Next 
 
  ;decrypt each character
  Protected length = Len(cipherText)
  index = 1
  While index <=length
    curChar = Mid(cipherText, index, 1)
    If curChar = preDigit_1 Or curChar = preDigit_2
      curChar = Mid(cipherText, index, 2)
      If curChar = escapeCipher: curChar = Mid(cipherText, index, 3): EndIf
    EndIf 
    outputText + cipher(curChar)
    index + Len(curChar)
  Wend
 
  ProcedureReturn outputText
EndProcedure
 
If OpenConsole()
  Define message.s = "One night-it was on the twentieth of March, 1888-I was returning"
  Define cipher.s = "HOLMESRTABCDFGIJKNPQUVWXYZ./", encoded.s
 
  PrintN("Original: " + message)
  encoded = encrypt_SC(message, cipher, 3, 7)
  PrintN("encoded: " + encoded)
  PrintN("decoded: " + decrypt_SC(encoded, cipher, 3, 7))
 
  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
  CloseConsole()
EndIf