bgneal@64: Key lists bgneal@64: --------- bgneal@64: bgneal@64: Key lists are represented as a named tuple called ``KeyList``. bgneal@64: bgneal@64: .. class:: m209.keylist.KeyList(indicator, lugs, pin_list, letter_check) bgneal@64: bgneal@64: As a named tuple, ``KeyList`` has the following attributes: bgneal@64: bgneal@64: * ``indicator`` - the string name for the ``KeyList``; must be 2 letters in bgneal@64: the range ``AA`` - ``ZZ`` bgneal@64: * ``lugs`` - a string representing the drum lug settings; see below bgneal@64: * ``pin_list`` - a list of six strings which represent key wheel pin bgneal@64: settings; see below bgneal@64: * ``letter_check`` - a string representing the letter check used to verify bgneal@64: operator settings; if unknown this can be ``None`` or an empty string bgneal@64: bgneal@64: Lug settings format bgneal@64: ~~~~~~~~~~~~~~~~~~~ bgneal@64: bgneal@64: Drum lug settings are often conveniently represented as strings consisting of bgneal@64: at most 27 whitespace-separated pairs of integers separated by dashes. For bgneal@64: example:: bgneal@64: bgneal@64: lugs = '1-0 2-0 2-0 0-3 0-5 0-5 0-5 0-6 2-4 3-6' bgneal@64: bgneal@64: Each integer pair must be in the form ``m-n`` where m & n are integers bgneal@64: between 0 and 6, inclusive. Each integer represents a lug position where bgneal@64: 0 is a neutral position, and 1-6 correspond to key wheel positions. If bgneal@64: m & n are both non-zero, they cannot be equal. bgneal@64: bgneal@64: If a string has less than 27 pairs, it is assumed all remaining bars have both bgneal@64: lugs in the neutral (0) positions. bgneal@64: bgneal@64: Order of the pairs within the string does not matter. bgneal@64: bgneal@64: To reduce typing and to aid in readability, an alternate shortcut notation is bgneal@64: supported:: bgneal@64: bgneal@64: lugs = '1-0 2-0*2 0-3 0-5*3 0-6 2-4 3-6' bgneal@64: bgneal@64: Any pair that is suffixed by ``*k``, where k is a positive integer, means there bgneal@64: are ``k`` copies of the preceeding lug pair combination. For example, these two bgneal@64: strings describe identical drum configurations:: bgneal@64: bgneal@64: lugs1 = '2-4 2-4 2-4 0-1 0-1' bgneal@64: lugs2 = '2-4*3 0-1*2' bgneal@64: bgneal@64: Key wheel pin settings bgneal@64: ~~~~~~~~~~~~~~~~~~~~~~ bgneal@64: bgneal@64: Key wheel pin settings are represented as iterables of letters whose pins are bgneal@64: slid to the "effective" position (to the right). Letters not appearing in this bgneal@64: sequence are considered to be in the "ineffective" position (to the left). If bgneal@64: None or empty, all pins are set to be ineffective. bgneal@64: bgneal@64: Examples:: bgneal@64: bgneal@64: all_ineffective = '' bgneal@64: wheel1 = 'ABDEFHIJMQSUXZ' bgneal@64: wheel2 = 'EINPQRTVXZ' bgneal@64: wheel3 = 'DEFGIKNOSUX' bgneal@64: wheel4 = 'BFGJKRS' bgneal@64: wheel5 = 'ABCDFGHIJMPS' bgneal@64: wheel6 = 'ADEFHIJKN' bgneal@64: bgneal@64: Key list example bgneal@64: ~~~~~~~~~~~~~~~~ bgneal@64: bgneal@64: An example of using the :class:`~m209.keylist.KeyList` is: bgneal@64: bgneal@64: .. code-block:: python bgneal@64: bgneal@64: from m209.keylist import KeyList bgneal@64: bgneal@64: key_list1 = KeyList( bgneal@64: indicator='AA', bgneal@64: lugs='0-4 0-5*4 0-6*6 1-0*5 1-2 1-5*4 3-0*3 3-4 3-6 5-6', bgneal@64: pin_list=[ bgneal@64: 'FGIKOPRSUVWYZ', bgneal@64: 'DFGKLMOTUY', bgneal@64: 'ADEFGIORTUVX', bgneal@64: 'ACFGHILMRSU', bgneal@64: 'BCDEFJKLPS', bgneal@64: 'EFGHIJLMNP' bgneal@64: ], bgneal@64: letter_check='QLRRN TPTFU TRPTN MWQTV JLIJE J') bgneal@64: bgneal@64: Key list file I/O bgneal@64: ~~~~~~~~~~~~~~~~~ bgneal@64: bgneal@64: Key lists can be stored in files in config file ("INI") style format using bgneal@64: functions found in the ``m209.keylist.config`` module. bgneal@64: bgneal@64: .. function:: m209.keylist.config.read_key_list(fname[, indicator=None]) bgneal@64: bgneal@64: Reads key list information from the file given by ``fname``. bgneal@64: bgneal@64: Searches the config file for the key list with the given indicator. If bgneal@64: found, returns a :class:`~m209.keylist.KeyList` object. Returns ``None`` if bgneal@64: not found. bgneal@64: bgneal@64: If ``indicator`` is ``None``, a key list is chosen from the file at random. bgneal@64: bgneal@64: .. function:: m209.keylist.config.write(fname, key_lists) bgneal@64: bgneal@64: Writes the key lists to the file named ``fname`` in config file format. bgneal@64: bgneal@64: ``key_lists`` must be an iterable of :class:`~m209.keylist.KeyList` objects. bgneal@64: bgneal@64: Key list file format bgneal@64: ++++++++++++++++++++ bgneal@64: bgneal@64: An example key list file in config file format is presented below. The label bgneal@64: for each section of the file is the key list indicator. bgneal@64: bgneal@64: :: bgneal@64: bgneal@64: [CA] bgneal@64: lugs = 0-5*5 0-6*2 1-0*7 1-2 1-3*3 1-6 2-0 3-0*3 3-5*2 3-6 4-5 bgneal@64: wheel1 = ABCDFGHJLOPRVWYZ bgneal@64: wheel2 = BCDEIJKPQSUVX bgneal@64: wheel3 = ACDGLNQRSTUV bgneal@64: wheel4 = FGHIJNQRSU bgneal@64: wheel5 = DEIJOQS bgneal@64: wheel6 = BCDEILMNOP bgneal@64: check = RGPRO RTYOO TWYSN GXTPF PNWIH P bgneal@64: bgneal@64: [CD] bgneal@64: lugs = 0-4*4 0-5 1-0*7 1-2*2 1-4*3 2-0*2 2-4*2 2-6*2 3-0*4 bgneal@64: wheel1 = AEFHIKMPQRSUVZ bgneal@64: wheel2 = ABFGHINORSUVZ bgneal@64: wheel3 = BDEHJKLMNOQRSU bgneal@64: wheel4 = CDEFGHJKMRU bgneal@64: wheel5 = FGHIJOQS bgneal@64: wheel6 = EGIJKLP bgneal@64: check = ZRLWL YRMIZ RZOPN UWMVZ DVGPM H bgneal@64: bgneal@64: Generating key lists bgneal@64: ~~~~~~~~~~~~~~~~~~~~ bgneal@64: bgneal@64: The ``m209`` library contains a function to pseudo-randomly generate a key list bgneal@64: that is based on the procedure described in the 1944 M-209 manual. bgneal@64: bgneal@64: .. function:: m209.keylist.generate.generate_key_list(indicator[, lug_selection=None, max_lug_attempts=MAX_LUG_ATTEMPTS, max_pin_attempts=MAX_PIN_ATTEMPTS]) bgneal@64: bgneal@64: The only required parameter is ``indicator``, the two-letter indicator for bgneal@64: the key list. bgneal@64: bgneal@64: If successful, a :class:`~m209.keylist.KeyList` object is returned. bgneal@64: bgneal@64: If a :class:`~m209.keylist.KeyList` could not be generated bgneal@64: a ``KeyListGenError`` exception is raised. bgneal@64: bgneal@64: The algorithm is heuristic-based and makes random decisions based upon the bgneal@64: 1944 procedure. The actual procedure is loosely specified in the manual, and bgneal@64: much is left up to the human operator. It is possible that the algorithm bgneal@64: cannot find a solution to meet the key list requirements specified in the bgneal@64: manual, in which case it simply tries again up to some set of limits. These bgneal@64: limits can be tweaked using the optional parameters to the algorithm. If no bgneal@64: solution is found after exhausting the limits, a ``KeyListGenError`` is bgneal@64: raised. bgneal@64: bgneal@64: The optional parameters are: bgneal@64: bgneal@64: * ``lug_selection`` - a list of 6 integers used to drive the lug settings bgneal@64: portion of the algorithm. If not supplied, a list of 6 integers is chosen bgneal@64: from data tables that appear in the 1944 manual. For more information on bgneal@64: the requirements for these integers, see the manual. bgneal@64: bgneal@64: * ``max_lug_attempts`` - the maximum number of times to attempt to create bgneal@64: lug settings before giving up bgneal@64: bgneal@64: * ``max_pin_attempts`` - the maximum number of times to attempt to generate bgneal@64: key wheel pin settings before giving up bgneal@64: