Extended Straddling Checkerboard
An extended Straddling Checkerboard, is like the regular Straddling checkerboard, but allows word dictionaries and arbitrary functional codes like (FIGURE, where you can specify a number literally).
Related tasks:
References:
- Cipher Machines web page on Checkerboards: Checkerboards
Python
<syntaxhighlight lang="python">""" rosettacode.org/wiki/Extended_Straddling_Checkerboard """
from functools import reduce
WDICT = {
'CODE': 'κ', 'ACK': 'α', 'REQ': 'ρ', 'MSG': 'μ', 'RV': 'ν', 'GRID': 'γ', 'SEND': 'σ', 'SUPP': 'π',
} SDICT = {v: k for (k, v) in WDICT.items()} # reversed WDICT for reverse lookup on decode
- web site CT37w, but '/' is 98 not 99 to help differentiate from code for 9 of '999'
CT37w = [[, 'A', 'E', 'I', 'N', 'O', 'T', 'κ', , , ,],
['7', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M',], ['8', 'P', 'Q', 'R', 'S', 'U', 'V', 'W', 'X', 'Y', 'Z',], ['9', ' ', '.', 'α', 'ρ', 'μ', 'ν', 'γ', 'σ', '/', 'π',],]
def xcb_encode(message, nchangemode='98', code='κ', table=CT37w, wdict=WDICT):
""" Encode with extended straddling checkerboard. Default checkerboard is CT37w at https://www.ciphermachinesandcryptology.com/en/table.htm The numeric mode has the numbers as repeated in triplicate The CODE mode expects a 3-digit numeric code """ encoded = [] numericmode, codemode = False, False codemodecount = 0 # replace terms found in dictionary with a single char symbol that is in the table s = reduce(lambda x, p: x.replace( p[0], p[1]), wdict.items(), message.upper()) for c in s: if c.isnumeric(): if codemode: # codemode symbols are preceded by the CODE digit '6' then as-is encoded.append(c) codemodecount += 1 if codemodecount >= 3: codemode = False
else: # numeric numbers are triplicate encoded so '3' -> '333' if not numericmode: numericmode = True encoded.append(nchangemode)
encoded.append(c*3)
else: codemode = False if numericmode: encoded.append(nchangemode) # end numericmode with the numeric code for '/' (98) numericmode = False
if c == code: codemode = True codemodecount = 0
for row in table: if c in row: k = row.index(c) encoded.append(str(row[0]) + str(k-1)) break
return .join(encoded)
def xcb_decode(s, nchangemode='98', code='κ', table=CT37w, sdict=SDICT):
""" Decode extended straddling checkerboard """ numbers = {c*3: c for c in list('0123456789')} prefixes = sorted([row[0] for row in table], reverse=True) pos = 0 numericmode = False codemode = False decoded = [] while pos < len(s): if numericmode: if s[pos:pos+3] in numbers: decoded.append(numbers[s[pos:pos+3]]) pos += 2 elif s[pos:pos+2] == nchangemode: numericmode = False pos += 1
elif codemode: if (s[pos:pos+3]).isnumeric(): decoded.append(s[pos:pos+3]) pos += 2
codemode = False
elif s[pos:pos+2] == nchangemode: numericmode = not numericmode pos += 1 else: for p in prefixes: if s[pos:].startswith(p): n = len(p) row = next(i for i, r in enumerate(table) if p == r[0]) c = table[row][int(s[pos+n])+1] decoded.append(c) if c == code: codemode = True pos += n break
pos += 1
return reduce(lambda x, p: x.replace(p[0], p[1]), sdict.items(), .join(decoded))
if __name__ == '__main__':
MESSAGE = 'Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March' print(MESSAGE) print('Encoded: ', xcb_encode(MESSAGE)) print('Decoded: ', xcb_decode(xcb_encode(MESSAGE)))
</syntaxhighlihjt>
- Output:
Admin ACK your MSG. CODE291 SEND further 2000 SUPP to HQ by 1 March Encoded: 072792390929088484829094919062919097907384825751829098222000000000989099905490758190708890981119890790827175 Decoded: ADMIN ACK YOUR MSG. CODE291 SEND FURTHER 2000 SUPP TO HQ BY 1 MARCH