' Substitution Cipher — simple monoalphabetic substitution cipher
#COMPILE EXE
#DIM ALL

FUNCTION PBMAIN() AS LONG
    LOCAL alphabet AS STRING
    LOCAL shuffled AS STRING
    LOCAL plaintext AS STRING
    LOCAL ciphertext AS STRING
    LOCAL decrypted AS STRING
    LOCAL i AS LONG
    LOCAL j AS LONG
    LOCAL pIdx AS LONG
    LOCAL pos AS LONG
    LOCAL ch AS STRING
    LOCAL tempChar AS STRING
    LOCAL testCount AS LONG
    LOCAL passCount AS LONG
    LOCAL failCount AS LONG
    LOCAL lineStr AS STRING
    LOCAL keyMap(256) AS LONG
    LOCAL revMap(256) AS LONG
    LOCAL mappingCount AS LONG
    LOCAL charCode AS LONG
    LOCAL used(256) AS LONG
    LOCAL isLowerCase AS LONG
    testCount = 0
    passCount = 0
    failCount = 0
    PRINT "============================================"
    PRINT "      SUBSTITUTION CIPHER"
    PRINT "============================================"
    PRINT ""
    PRINT "Monoalphabetic substitution with random key"
    PRINT ""
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    shuffled = alphabet
    FOR i = 1 TO 26
        j = (i * 7 + 3) MOD 26 + 1
        tempChar = MID$(shuffled, i, 1)
        MID$(shuffled, i, 1) = MID$(shuffled, j, 1)
        MID$(shuffled, j, 1) = tempChar
    NEXT i
    PRINT "Alphabet:  " + alphabet
    PRINT "Substitut: " + shuffled
    PRINT ""
    mappingCount = 26
    FOR i = 1 TO mappingCount
        ch = MID$(alphabet, i, 1)
        charCode = ASC(ch)
        keyMap(charCode) = ASC(MID$(shuffled, i, 1))
    NEXT i
    FOR i = 1 TO mappingCount
        ch = MID$(shuffled, i, 1)
        charCode = ASC(ch)
        revMap(charCode) = ASC(MID$(alphabet, i, 1))
    NEXT i
    plaintext = "HELLOWORLDTHISISATEST"
    PRINT "Plaintext:  " + plaintext
    PRINT ""
    ciphertext = ""
    FOR i = 1 TO LEN(plaintext)
        ch = MID$(plaintext, i, 1)
        charCode = ASC(ch)
        IF charCode >= 65 AND charCode <= 90 THEN
            ciphertext = ciphertext + CHR$(keyMap(charCode))
        ELSE
            ciphertext = ciphertext + ch
        END IF
    NEXT i
    PRINT "Ciphertext: " + ciphertext
    PRINT ""
    decrypted = ""
    FOR i = 1 TO LEN(ciphertext)
        ch = MID$(ciphertext, i, 1)
        charCode = ASC(ch)
        IF charCode >= 65 AND charCode <= 90 THEN
            decrypted = decrypted + CHR$(revMap(charCode))
        ELSE
            decrypted = decrypted + ch
        END IF
    NEXT i
    PRINT "Decrypted:  " + decrypted
    testCount = testCount + 1
    IF decrypted = plaintext THEN
        passCount = passCount + 1
        PRINT "PASS"
    ELSE
        failCount = failCount + 1
        PRINT "FAIL"
    END IF
    PRINT ""
    PRINT "============================================"
    PRINT "     SHIFT CIPHER (Caesar variant)"
    PRINT "============================================"
    PRINT ""
    LOCAL shift AS LONG
    shift = 3
    PRINT "Caesar shift = " + STR$(shift)
    PRINT ""
    plaintext = "THEQUICKBROWNFOXJUMPSOVERLAZYDOG"
    ciphertext = ""
    FOR i = 1 TO LEN(plaintext)
        ch = MID$(plaintext, i, 1)
        charCode = ASC(ch)
        IF charCode >= 65 AND charCode <= 90 THEN
            charCode = charCode + shift
            IF charCode > 90 THEN
                charCode = charCode - 26
            END IF
        END IF
        ciphertext = ciphertext + CHR$(charCode)
    NEXT i
    decrypted = ""
    FOR i = 1 TO LEN(ciphertext)
        ch = MID$(ciphertext, i, 1)
        charCode = ASC(ch)
        IF charCode >= 65 AND charCode <= 90 THEN
            charCode = charCode - shift
            IF charCode < 65 THEN
                charCode = charCode + 26
            END IF
        END IF
        decrypted = decrypted + CHR$(charCode)
    NEXT i
    PRINT "Plain:  " + plaintext
    PRINT "Cipher: " + ciphertext
    PRINT "Decode: " + decrypted
    testCount = testCount + 1
    IF decrypted = plaintext THEN
        passCount = passCount + 1
    ELSE
        failCount = failCount + 1
    END IF
    PRINT ""
    PRINT "============================================"
    PRINT "     AFFINE CIPHER (ax + b mod 26)"
    PRINT "============================================"
    PRINT ""
    LOCAL affineA AS LONG
    LOCAL affineB AS LONG
    LOCAL invA AS LONG
    affineA = 5
    affineB = 8
    invA = 21
    PRINT "Affine: a=" + STR$(affineA) + ", b=" + STR$(affineB) + ", inv(a)=" + STR$(invA)
    PRINT ""
    plaintext = "AFFINECIPHERTEST"
    ciphertext = ""
    FOR i = 1 TO LEN(plaintext)
        ch = MID$(plaintext, i, 1)
        p = ASC(ch) - 65
        c = (affineA * p + affineB) MOD 26
        ciphertext = ciphertext + CHR$(c + 65)
    NEXT i
    decrypted = ""
    FOR i = 1 TO LEN(ciphertext)
        ch = MID$(ciphertext, i, 1)
        c = ASC(ch) - 65
        p = (invA * (c - affineB + 26)) MOD 26
        decrypted = decrypted + CHR$(p + 65)
    NEXT i
    PRINT "Plain:  " + plaintext
    PRINT "Cipher: " + ciphertext
    PRINT "Decode: " + decrypted
    testCount = testCount + 1
    IF decrypted = plaintext THEN
        passCount = passCount + 1
    ELSE
        failCount = failCount + 1
    END IF
    PRINT ""
    PRINT "============================================"
    PRINT "     ATBASH CIPHER (reverse alphabet)"
    PRINT "============================================"
    PRINT ""
    plaintext = "ATBASHTEST"
    ciphertext = ""
    FOR i = 1 TO LEN(plaintext)
        ch = MID$(plaintext, i, 1)
        p = ASC(ch) - 65
        c = 25 - p
        ciphertext = ciphertext + CHR$(c + 65)
    NEXT i
    decrypted = ""
    FOR i = 1 TO LEN(ciphertext)
        ch = MID$(ciphertext, i, 1)
        c = ASC(ch) - 65
        p = 25 - c
        decrypted = decrypted + CHR$(p + 65)
    NEXT i
    PRINT "Plain:  " + plaintext
    PRINT "Cipher: " + ciphertext
    PRINT "Decode: " + decrypted
    testCount = testCount + 1
    IF decrypted = plaintext THEN
        passCount = passCount + 1
    ELSE
        failCount = failCount + 1
    END IF
    PRINT ""
    PRINT "============================================"
    PRINT "     ROT13 CIPHER"
    PRINT "============================================"
    PRINT ""
    plaintext = "THEQUICKBROWNFOX"
    ciphertext = ""
    FOR i = 1 TO LEN(plaintext)
        ch = MID$(plaintext, i, 1)
        p = ASC(ch) - 65
        c = (p + 13) MOD 26
        ciphertext = ciphertext + CHR$(c + 65)
    NEXT i
    decrypted = ""
    FOR i = 1 TO LEN(ciphertext)
        ch = MID$(ciphertext, i, 1)
        c = ASC(ch) - 65
        p = (c + 13) MOD 26
        decrypted = decrypted + CHR$(p + 65)
    NEXT i
    PRINT "ROT13: " + ciphertext
    PRINT "BACK:  " + decrypted
    testCount = testCount + 1
    IF decrypted = plaintext THEN
        passCount = passCount + 1
    ELSE
        failCount = failCount + 1
    END IF
    PRINT ""
    PRINT "Results: " + STR$(passCount) + " passed, " + STR$(failCount) + " failed"
    FUNCTION = 0
END FUNCTION
