#!/usr/bin/python3
# ===================================================================
# Enigma Machine Simulation - create configuration file
# ===================================================================
from EnigmaUtils import *
import copy
import re
import sys
import random
import user_interface as ui
from datetime import date
rotors = {'I':[], 'II':[], 'III':[], 'IV':[],
'V':[], 'VI':[], 'VII':[], 'VIII':[] }
# ---------------------------------------------------------------
# ---- select alphabet
# ----
# ---- NOTES:
# ---- 1. AN ALPHABET MUST CONTAIN AN EVEN NUMBER OF CHARACTERS
# ---- 2. IT MUST NOT CONTAIN A COMMA
# ---------------------------------------------------------------
def select_alphabet():
# ---- big alphabet (44 characters)
alphabet0 = [ 'A','B','C','D','E','F','G','H','I','J','K','L',
'M','N','O','P','Q','R','S','T','U','V','W','X',
'Y','Z','1','2','3','4','5','6','7','8','9','0',
'.','=','+','-','/','*','(',')' ]
# ---- enigma alphabet
alphabet1 = [ 'A','B','C','D','E','F','G','H','I','J','K','L',
'M','N','O','P','Q','R','S','T','U','V','W','X',
'Y','Z' ]
# ---- test alphabet
alphabet2 = [ 'A','B','C','D','E','F' ]
# ---- big alphabet (48 characters)
alphabet3 = [ 'A','B','C','D','E','F','G','H','I','J','K','L',
'M','N','O','P','Q','R','S','T','U','V','W','X',
'Y','Z','1','2','3','4','5','6','7','8','9','0',
'.','=','+','-','/','*','(',')',' ','\\','"','\'' ]
# ---- alphabet menu
print('''select an alphabet for enigma configuration file
option description
------ ------------------------------------------------
0 big alphabet [ A-Z,0-9, ... ] (44 characters)
1 enigma alphabet [ A-Z ]
2 test alphabet [ A-F ]
3 bigger alphabet [ A-Z,0-9, ... ] (48 characters)
9 exit program''')
# ---- make sure the alphabets have an even number of characters
if len(alphabet0)%2 != 0 or \
len(alphabet1)%2 != 0 or \
len(alphabet2)%2 != 0 or \
len(alphabet3)%2 != 0:
print()
print('Internal error: An alphabet contains an odd ')
print('number of characters - end program')
sys.exit()
while True:
print()
s =ui.get_user_input('Select alphabet: ')
if not s:
sys.exit()
tf,i = ui.is_int(s)
if not tf:
continue
if i == 0:
return alphabet0
if i == 1:
return alphabet1
if i == 2:
return alphabet2
if i == 3:
return alphabet3
if i == 9:
print()
sys.exit()
print()
print(f'Unlnown alphabet selection (i)')
continue
# ---------------------------------------------------------------
# ---- create plugboard connections (two unique characters)
# ---------------------------------------------------------------
def add_plugboard_connections(abc):
plubs = []
char_in_use = []
# ---- display the current alphabet
for i in range(len(abc)):
if i % 12 == 0:
print()
print('Alphabet:',end='')
print(f' {abc[i]}',end='')
print()
# ---- process user input
while True:
print()
s = ui.get_user_input('Enter plugboard connection (ab): ')
if not s:
break
# ---- error check the user's input
s = s.upper()
if len(s) != 2 or s[0] == s[1]:
print()
print(f'Bad connection entered ({s})')
continue
c0 = s[0]
c1 = s[1]
if c0 not in abc:
print()
print(f'Character {c0} not in the alphabet')
continue
if c1 not in abc:
print()
print(f'Character {c1} not in the alphabet')
continue
if c0 in char_in_use:
print()
print(f'Character {c0} already in use')
continue
if c1 in char_in_use:
print()
print(f'Character {c1} already in use')
continue
# ---- save the user's input
char_in_use.append(c0)
char_in_use.append(c1)
plugs.append(s)
return plugs
# -------------------------------------------------------------------
# ---- main
# -------------------------------------------------------------------
# ---- select an alphabet
abc = select_alphabet() # alphabet
abclen = len(abc) # abc list length
abcidx = list(range(abclen)) # abc ordered list of indexes
configfile = 'enigma_config.csv' # configuration file
plugs = [] # plugboard pairs list
reflst = [] # reflector list
today = date.today() # today's date
# ---- write enigma config file
line_count = 0 # count, lines written
plug_count = 0 # count, plugs written
refl_count = 0 # count, reflector lists written
roto_count = 0 # count, rotor lists written
with open(configfile,"w") as f:
# ---- add header lines to output file
f.write(f'# Enigma Machine Simulation Configuration\n')
line_count += 1
f.write(f'date,{today}\n')
line_count += 1
# ---- add an unknown character substitution to the output file
# ---- if an input character is not in the alphabet substitute
# ---- a known character
if len(abc) < 25:
f.write(f'unk,{abc[-1]}\n')
else:
f.write('unk,X\n')
line_count += 1
# ---- output alphabet length
f.write(f'len,{abclen}\n')
line_count += 1
# ---- add alphabet to output file
f.write(f'# alphabet,list-idx,char\n')
line_count += 1
for i in range(abclen):
f.write(f'abc,{i},{abc[i]}\n')
line_count += 1
# ---- create rotor lists and add them to the output file
for r in rotors:
ranlst = create_randomized_rotor_list(abcidx)
rotors[r] = ranlst # save it for later counting
f.write(f'# rotor-name,in-list-idx,out-list-idx,in-char,out-char\n')
line_count += 1
for i in range(len(ranlst)):
j = ranlst[i]
f.write(f'{r},{i},{j},{abc[i]},{abc[j]}\n')
line_count += 1
roto_count += 1
# ---- create reflector list and add it to the output file
reflst = create_randomized_reflector_list(abcidx)
f.write(f'# reflector,in-list-idx,out-list-idx,in-char,out-char\n')
line_count += 1
for i in range(abclen):
j = reflst[i]
f.write(f'ref,{i},{j},{abc[i]},{abc[j]}\n')
line_count += 1
# ---- verify reflector pairs
for i in range(abclen):
j = reflst[i]
if reflst[j] != i:
print(f'Error in reflector list i={i} j={j}')
print(f'reflst[{i}] = {reflst[i]}')
print(f'reflst[{j}] = {reflst[j]}')
sys.exit()
refl_count += 1
# ---- add plugboard connections to the output file
plubs = add_plugboard_connections(abc)
l = len(plugs)
print()
if l == 0:
print('No plugboard connections')
else:
print(f'{l} plugboard connections')
f.write(f'# plugboard,char-pair\n')
line_count += 1
for i in range(l):
f.write(f'plug,{plugs[i]}\n')
line_count += 1
# ---- display stats
print()
print(f'date : {today}')
print(f'file name: {configfile}')
print(f'abc len: {abclen}')
print(f'alphabet len: {len(abc)}')
print(f'rotor count: {len(rotors)}')
for r in rotors.keys():
print(f' {r:5} len: {len(rotors[r])}')
print(f'reflector len: {len(reflst)}')
print(f'plugs : {len(plugs)}')
print(f'lines written: {line_count}')
print()