# HG changeset patch # User Brian Neal # Date 1370199465 18000 # Node ID 328790e5bc5d90fe215f07cc291153b736b52d68 # Parent 0a2a066fb18c9851a1bf0c5d8b9b2928d6deca1b Introduce shortcut notation for drum lugs. diff -r 0a2a066fb18c -r 328790e5bc5d m209/converter.py --- a/m209/converter.py Wed May 29 22:04:12 2013 -0500 +++ b/m209/converter.py Sun Jun 02 13:57:45 2013 -0500 @@ -62,7 +62,7 @@ If lug_list is passed as a string, it is assumed to be in key list format. That is, it must consist of at most 27 whitespace separated pairs of integers separated by dashes. For example: - '1-0 2-0 2-0 0-3 0-5 0-5 0-6 2-4 3-6' + '1-0 2-0 2-0 0-3 0-5 0-5 0-5 0-6 2-4 3-6' Each integer pair must be in the form 'm-n' where m & n are integers between 0 and 6, inclusive. Each integer represents a lug position where @@ -74,6 +74,15 @@ Order in a list or string doesn't matter. + An alternate shortcut notation is also supported: + '1-0 2-0*2 0-3 0-5*3 0-6 2-4 3-6' + + Any pair that is suffixed by '*k', where k is a positive integer, means + there are k copies of the preceeding lug pair combination. In other + words, these two strings describe identical drum configurations: + '2-4 2-4 2-4 0-1 0-1' + '2-4*3 0-1*2' + """ if isinstance(lug_list, str): drum = Drum.from_key_list(lug_list) @@ -96,7 +105,7 @@ for kw in self.key_wheels: kw.rotate() - self.letter_count += 1 + self.letter_counter += 1 if group: s = ' '.join(''.join(ciphertext[i:i+5]) for i in range(0, @@ -110,7 +119,7 @@ if __name__ == '__main__': m209 = M209() - m209.set_drum_lugs('1-0 2-0 2-0 2-0 2-0 0-3 0-4 0-4 0-4 0-5 0-5 0-5 0-6 0-6 0-6 0-6 0-6 0-6 0-6 0-6 0-6 0-6 0-6 2-5 2-6 3-4 4-5') + m209.set_drum_lugs('1-0 2-0*4 0-3 0-4*3 0-5*3 0-6*11 2-5 2-6 3-4 4-5') m209.set_pins(0, 'BFJKLOSTUWXZ') m209.set_pins(1, 'ABDJKLMORTUV') m209.set_pins(2, 'EHJKNPQRSX') diff -r 0a2a066fb18c -r 328790e5bc5d m209/drum.py --- a/m209/drum.py Wed May 29 22:04:12 2013 -0500 +++ b/m209/drum.py Sun Jun 02 13:57:45 2013 -0500 @@ -18,7 +18,7 @@ lugs can be slid into positions numbered 1-6 and/or 2 neutral positions numbered 0. As the drum rotates all 27 bars have a chance for their lugs to interact with 6 guide arms (one for each key wheel), which may or may not be - in position. The guide arms' positioning are controlled by the effective + in position. The positioning of the guide arms are controlled by the effective pins on the six key wheels. As each bar rotates past the 6 guide arms for each key wheel, if one or both lugs come into contact with a guide arm, the bar will quickly shift left. This causes the indicator disk to rotate once, @@ -62,33 +62,37 @@ @classmethod def from_key_list(cls, lug_list): """Creates a Drum instance from a string that might be found on a key - list. The must consist of at most 27 whitespace separated pairs of - integers separated by dashes. For example: - '1-0 2-0 2-0 0-3 0-5 0-5 0-6 2-4 3-6' - - Each integer pair must be in the form 'm-n' where m & n are integers - between 0 and 6, inclusive. Each integer represents a lug position where - 0 is a neutral position, and 1-6 correspond to key wheel positions. If - m & n are both non-zero, they cannot be equal. - - If a string has less than 27 pairs of integers, it is assumed all - remaining bars have both lugs in the neutral (0) positions. + list. See the description of the M209.set_drum_lugs() method for the + format of the lug_list string argument. """ bars = [] lug_list = lug_list.split() for lug_pair in lug_list: + + repeat = 1 + pair = lug_pair try: - m, n = [int(x) for x in lug_pair.split('-')] + if '*' in lug_pair: + pair, repeat = lug_pair.split('*') + repeat = int(repeat) + if repeat < 0: + raise ValueError + + m, n = [int(x) for x in pair.split('-')] except ValueError: raise DrumError("Invalid lug pair {}".format(lug_pair)) + t = None if m and n: - bars.append((m - 1, n - 1)) + t = (m - 1, n - 1) elif m and not n: - bars.append((m - 1, )) + t = (m - 1, ) elif not m and n: - bars.append((n - 1, )) + t = (n - 1, ) + + for i in range(repeat): + bars.append(t) return cls(lug_list=bars) diff -r 0a2a066fb18c -r 328790e5bc5d m209/tests/test_drum.py --- a/m209/tests/test_drum.py Wed May 29 22:04:12 2013 -0500 +++ b/m209/tests/test_drum.py Sun Jun 02 13:57:45 2013 -0500 @@ -81,6 +81,18 @@ key_list = "2-0" * (Drum.NUM_BARS + 1) self.assertRaises(DrumError, Drum.from_key_list, key_list) + key_list = "2-0* 1-0 1-0 4-4 2-3" + self.assertRaises(DrumError, Drum.from_key_list, key_list) + + key_list = "2-0 1-0*-3 1-0 4-4 2-3" + self.assertRaises(DrumError, Drum.from_key_list, key_list) + + key_list = "2-0 1-0*-3 1-0 4-4 2*3" + self.assertRaises(DrumError, Drum.from_key_list, key_list) + + key_list = "2-0*10 1-0*2 4-4*10 1-6*6" + self.assertRaises(DrumError, Drum.from_key_list, key_list) + def test_valid_key_list(self): key_list = "0-6 1-4 2-5" drum = Drum.from_key_list(key_list) @@ -88,10 +100,13 @@ key_list = "2-4 " + ("0-6 1-4 " * 13).rstrip() drum = Drum.from_key_list(key_list) - bars = [(1, 3)] + [(5, ), (0, 3)] * 13 self.assertEqual(bars, drum.bars) + key_list = "2-4 0-6*13 1-4*13" + drum = Drum.from_key_list(key_list) + self.assertEqual(sorted(bars), sorted(drum.bars)) + def test_rotate(self): # These are just simple tests to flush out syntax errors, etc. Higher # level tests will verify the correct operation of the entire machine.