# =================================================================== # Enigma Machine Simulation - read/process configuration file # =================================================================== from datetime import date import user_interface as ui import copy import re import sys # -------------------------------------------------------------------- # ---- namespace for enigma simulation runtime configuration # -------------------------------------------------------------------- class EnigmaConfig(): def __init__(self,filename): # ---- rotor dictionary and keys self.rotors = { 'I':[], 'II':[], 'III':[], 'IV':[], 'V':[], 'VI':[], 'VII':[], 'VIII':[] } self.rotorkeys = list(self.rotors.keys()) self.abc = [] # alphabet list self.abclen = 0 # abc list length self.abcidx = [] # list of alphabet # indexes self.configfile = filename # configuration # file self.line_count = 0 # line count read # from config file self.plugs = [] # plugboard pairs self.pglst = [] # plugboard list self.reflst = [] # reflector list self.date = date.today() # config file date # ---- default enigma machine rotor configuration # ---- [left,middle,right] self.default_rotor_names = ['III','II','I'] self.default_rotor_starts= [2,1,0] # ---- create an empty configuration if not filename: return # ---- read/process configuration file fh = open(filename,'r') for line in fh: self.line_count += 1 line = line.strip() if not line: # empty string (line) continue if re.match('^#',line): # comment continue x = line.split(',') # --- date file created if x[0] =='date': # date self.date = x[1] continue # --- alphabet length? if x[0] == 'len': # alphabet length tf,i = ui.is_int(x[1]) if tf: if i >= 0: self.abclen = i continue if x[0] == 'unk': # substitute for unknown # character self.abcunk = x[1] continue # --- alphabet? if x[0] == 'abc': # alphabet self.abc.append(x[2]) continue # --- plug? if x[0] == 'plug': # plugboard self.plugs.append(x[1]) continue # ---- reflector? if x[0] == 'ref': # reflector self.reflst.append(int(x[2])) continue # ---- rotor? if x[0] in self.rotors.keys(): # rotor tf,i = ui.is_int(x[2]) if tf: if i >= 0: self.rotors[x[0]].append(int(x[2])) continue # ---- what? print() print('unknown line in config file ' + f'line={line_count})\n({line})') sys.exit() fh.close() # ---- verify config file data for r in self.rotors: if len(self.rotors[r]) != self.abclen: print() print(f'bad rotor list length (r)') sys.exit() if len(self.abc) != self.abclen: print() print('bad abc list length\n(alphabet)') sys.exit() if len(self.reflst) != self.abclen: print() print('bad reflector list length\n(reflector)') sys.exit() for i in range(self.abclen): j = self.reflst[i] if self.reflst[j] != i: print(f'error in reflector pair i={i} j={j}') sys.exit() # ---- now set abcidx self.abcidx = list(range(self.abclen)) # ---- now create plugboard self.create_plugboard() # --------------------------------------------------------------- # ---- helper function: convert character to index # --------------------------------------------------------------- def _char_to_index(self,c): for i in range(len(self.abc)): if c == self.abc[i]: return i print() print(f'character c not found in alphabet') sys.exit() # --------------------------------------------------------------- # ---- create plugboard (list) # --------------------------------------------------------------- def create_plugboard(self): used_chars = [] self.pglst = list(range(self.abclen)) for cc in self.plugs: # --- error check if len(cc) != 2 or cc[0] == cc[1] or \ cc[0] in used_chars or \ cc[1] in used_chars or \ cc[0] not in self.abc or \ cc[1] not in self.abc: print() print(f' error in plugboard pair ({cc})') sys.exit() used_chars.append(cc[0]) used_chars.append(cc[1]) idx0 = self._char_to_index(cc[0]) idx1 = self._char_to_index(cc[1]) self.pglst[idx0] = idx1 self.pglst[idx1] = idx0 # --------------------------------------------------------------- # ---- display EnigmaConfig internals # --------------------------------------------------------------- def display_config(self): self.display_stats() def display_stats(self): print() print(f'config file: {self.configfile}') print(f'date : {self.date}') print(f'lines read : {self.line_count}') print(f'alphabet len: {len(self.abc)}') print(f' abclen : {self.abclen}') print(f' abcunk : {self.abcunk}') print(f'rotor count: {len(self.rotors)}') for r in self.rotors.keys(): print(f' {r:5} len: {len(self.rotors[r])}') print(f'reflector len: {len(self.reflst)}') print(f'plugs : {len(self.plugs)}') for p in self.plugs: print(f' ({p})') ##for idx in range(len(self.pglst)): ## print(f' {idx:>2} --> {self.pglst[idx]:<2} i' + ## f'({self.abc[idx]})') print()