#!/usr/bin/python3
# ===================================================================
# test the rotors, reflector and plugboard with and without
# rotor advance
# ===================================================================
# the user must advance to rotors with the "advance" command.
# they do not automatically advance.
# -------------------------------------------------------------------
# Note: because this is software and not hardware, we do some special
# "stuff" with characters not in the enigma machine's alphabet [A-Z].
# see the code/comments.
# ===================================================================
from EnigmaMachine import EnigmaMachine
import user_interface as ui
import re
import os
import sys
# -------------------------------------------------------------------
# ---- main
# -------------------------------------------------------------------
if __name__ == '__main__':
# ---- start enigma machine simulation
configfile = 'enigma_config.csv'
if len(sys.argv) > 1:
configfile = sys.argv[1]
if not os.path.exists(configfile):
print()
print(f'Can not find enigma configuration file ({configfile})')
print()
sys.exit()
em = EnigmaMachine(configfile)
# ---- user commands
while True:
print()
print('Cmd: text, advance, reset, set, display, stats')
print(' autoon, autooff, subdebugon, subdebugoff')
print()
s = ui.get_user_input('Enter text: ')
if not s:
break
# ---- display command
if re.match('^display$',s):
em.display_internal_state()
continue
# ---- display rotor stats command
if re.match('^stats$',s):
em.display_rotor_stats()
continue
# ---- advance the rotors
if re.match('^advance$',s):
em.advance_rotors()
continue
# ---- auto advance
if re.match('^auto$',s):
print()
print(f'auto advance ({em.auto_advance_rotors})')
continue
if re.match('^auton$',s) or re.match('^autoon$',s):
em.auto_advance_rotors = True
continue
if re.match('^autoff$',s) or re.match('^autooff$',s):
em.auto_advance_rotors = False
continue
# ---- substitution debug
if re.match('^subdebug$',s):
print()
print(f'substitution debug ({em.substitution_debug})')
continue
if re.match('^subdebugon$',s) or re.match('^subon$',s):
em.substitution_debug = True
continue
if re.match('^subdebugoff$',s) or re.match('^suboff$',s):
em.substitution_debug = False
continue
# ---- reset the rotors to the initial configuration
if re.match('^reset$',s):
em.reset()
continue
# ---- set rotor configuration support function
def _get_set_rotor_configuration(r):
while True:
print()
prompt = f'Enter {r} rotor\'s new config (name,start): '
s = ui.get_user_input(prompt)
if not s:
return None
nn = s.split(',')
if len(nn) != 2:
print()
print('bad input - try again')
continue
nam = nn[0].strip().upper()
num = nn[1].strip()
if nam not in em.rotorkeys:
print()
print('bad input - try again')
continue
tf,nnum = ui.is_int(num)
if not tf or nnum < 0 or nnum > em.abclen-1:
print()
print('bad input - try again')
continue
break
return (nam,nnum)
# ---- set the rotors to a specified configuration
if re.match('^set$',s):
names = []
starts = []
x0 = _get_set_rotor_configuration('left')
if x0 == None:
print()
print('No changees made')
continue
x1 = _get_set_rotor_configuration('middle')
if x1 == None:
print()
print('No changees made')
continue
x2 = _get_set_rotor_configuration('right')
if x2 == None:
print()
print('No changees made')
continue
names.append(x0[0])
names.append(x1[0])
names.append(x2[0])
starts.append(x0[1])
starts.append(x1[1])
starts.append(x2[1])
em.set(names,starts)
continue
# ---- convert the input text
ss = s.upper() # convert input text to uppercase
sss = []
for c in ss:
if c not in em.abc:
print(f'char {c} not in alphabet ' +
f'- substituting {em.abcunk}')
c = em.abcunk
n = em.char_to_idx(c) # convert a character to an index
##if n < 0:
## continue
newidx = em.substitution(n) # substitution cypher
sss.append(em.abc[newidx]) # collect new characters into a list
ssss = ''.join(sss) # convert the list to a string
print()
print(f'{s} --> {ssss}')