5 <meta name=
"viewport" content=
"width=device-width, initial-scale=1, minimum-scale=1" />
6 <meta name=
"generator" content=
"pdoc 0.9.2" />
7 <title>szyfrow.bombe API documentation
</title>
8 <meta name=
"description" content=
"A simulator for Bombe machines …" />
9 <link rel=
"preload stylesheet" as=
"style" href=
"https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity=
"sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin
>
10 <link rel=
"preload stylesheet" as=
"style" href=
"https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity=
"sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin
>
11 <link rel=
"stylesheet preload" as=
"style" href=
"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin
>
12 <style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:
1.5em}#content{padding:
20px}#sidebar{padding:
30px;overflow:hidden}#sidebar
> *:last-child{margin-bottom:
2cm}.http-server-breadcrumbs{font-size:
130%;margin:
0 0 15px
0}#footer{font-size:
.75em;padding:
5px
30px;border-top:
1px solid #ddd;text-align:right}#footer p{margin:
0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:
30px}h1,h2,h3,h4,h5{font-weight:
300}h1{font-size:
2.5em;line-height:
1.1em}h2{font-size:
1.75em;margin:
1em
0 .50em
0}h3{font-size:
1.4em;margin:
25px
0 10px
0}h4{margin:
0;font-size:
105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:
.2em
0}a{color:#
058;text-decoration:none;transition:color
.3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^=
"header-"]{margin-top:
2em}.ident{color:#
900}pre code{background:#f8f8f8;font-size:
.8em;line-height:
1.4em}code{background:#f2f2f1;padding:
1px
4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:
0;border-top:
1px solid #ccc;border-bottom:
1px solid #ccc;margin:
1em
0;padding:
1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:
10%}#http-server-module-list p{margin-top:
0}.toc ul,#index{list-style-type:none;margin:
0;padding:
0}#index code{background:transparent}#index h3{border-bottom:
1px solid #ddd}#index ul{padding:
0}#index h4{margin-top:
.6em;font-weight:bold}@media (min-width:
200ex){#index .two-column{column-count:
2}}@media (min-width:
300ex){#index .two-column{column-count:
3}}dl{margin-bottom:
2em}dl dl:last-child{margin-bottom:
4em}dd{margin:
0 0 1em
3em}#header-classes + dl
> dd{margin-bottom:
3em}dd dd{margin-left:
2em}dd p{margin:
10px
0}.name{background:#eee;font-weight:bold;font-size:
.85em;padding:
5px
10px;display:inline-block;min-width:
40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name
> span:first-child{white-space:nowrap}.name.class
> span:nth-child(
2){margin-left:
.4em}.inherited{color:#
999;border-left:
5px solid #eee;padding-left:
1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:
400;font-size:
1.25em}.desc h3{font-size:
1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#
666;text-align:right;font-weight:
400;font-size:
.8em;text-transform:uppercase}.source summary
> *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:
1em}.source pre{max-height:
500px;overflow:auto;margin:
0}.source pre code{font-size:
12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\
2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:
1em}img{max-width:
100%}td{padding:
0 .5em}.admonition{padding:
.1em
.5em;margin-bottom:
1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}
</style>
13 <style media=
"screen and (min-width: 700px)">@media screen and (min-width:
700px){#sidebar{width:
30%;height:
100vh;overflow:auto;position:sticky;top:
0}#content{width:
70%;max-width:
100ch;padding:
3em
4em;border-left:
1px solid #ddd}pre code{font-size:
1em}.item .name{font-size:
1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:
1.5em}.toc
> ul
> li{margin-top:
.5em}}
</style>
14 <style media=
"print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#
000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:
" (" attr(href)
")";font-size:
90%}a[href][title]:after{content:none}abbr[title]:after{content:
" (" attr(title)
")"}.ir a:after,a[href^=
"javascript:"]:after,a[href^=
"#"]:after{content:
""}pre,blockquote{border:
1px solid #
999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:
100% !important}@page{margin:
0.5cm}p,h2,h3{orphans:
3;widows:
3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}
</style>
15 <script defer
src=
"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity=
"sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin
></script>
16 <script>window.addEventListener('DOMContentLoaded', () =
> hljs.initHighlighting())
</script>
20 <article id=
"content">
22 <h1 class=
"title">Module
<code>szyfrow.bombe
</code></h1>
24 <section id=
"section-intro">
25 <p>A simulator for Bombe machines.
</p>
26 <p>See
<code><a title=
"szyfrow.enigma.Enigma" href=
"enigma.html#szyfrow.enigma.Enigma">Enigma
</a></code> for an implementation of the Enigma to create
28 <p>There is a good explanation of
<a href=
"http://www.ellsbury.com/enigmabombe.htm">how the bombe worked
</a>
29 by Graham Ellsbury.
</p>
30 <p>In this implementation, there are
<em>banks
</em> of wires (what Ellsbury refers to
31 as
"cables"), one bank for each position that appears in the menu. A bank
32 comprises
26 wires, represented as a
<code>dict
</code> of
<code>bool
</code>s, depending on whether
33 that wire is live (
"energised") or not.
</p>
34 <p>The menu, derived from the crib, determines how the scramblers connect the
35 banks. A
<code><a title=
"szyfrow.bombe.Connection" href=
"#szyfrow.bombe.Connection">Connection
</a></code> represents this.
</p>
36 <details class=
"source">
38 <span>Expand source code
</span>
40 <pre><code class=
"python">"""A simulator for Bombe machines.
42 See `szyfrow.enigma.Enigma` for an implementation of the Enigma to create
45 There is a good explanation of [how the bombe worked](http://www.ellsbury.com/enigmabombe.htm)
48 In this implementation, there are *banks* of wires (what Ellsbury refers to
49 as
"cables
"), one bank for each position that appears in the menu. A bank
50 comprises
26 wires, represented as a `dict` of `bool`s, depending on whether
51 that wire is live (
"energised
") or not.
53 The menu, derived from the crib, determines how the scramblers connect the
54 banks. A `Connection` represents this.
59 import multiprocessing
63 from szyfrow.enigma import *
67 Signal = collections.namedtuple(
'Signal
', [
'bank
',
'wire
'])
68 __pdoc__[
'Signal
'] =
"""Current propogation through the Bombe indicates that
69 this wire in this bank is live, and the effects need to be proogated further
72 __pdoc__[
'Signal.bank
'] =
"""The bank of a signal.
"""
73 __pdoc__[
'Signal.wire
'] =
"""The wire of a signal.
"""
75 Connection = collections.namedtuple(
'Connection
', [
'banks
',
'scrambler
'])
76 __pdoc__[
'Connection
'] =
"""A connection between banks made by a particular
77 scrambler (the scrambler state given by its position in the crib).
79 __pdoc__[
'Connection.banks
'] =
"""A list of two items, holding the bnaks of
80 a connection.
"""
81 __pdoc__[
'Connection.scrambler
'] =
"""The bnaks of a connection.
"""
84 MenuItem = collections.namedtuple(
'MenuIem
', [
'before
',
'after
',
'number
'])
85 __pdoc__[
'MenuItem
'] =
"""One item in the menu, derived from the crib.
87 __pdoc__[
'MenuItem.before
'] =
"The letter before the transform (plaintext).
"
88 __pdoc__[
'MenuItem.after
'] =
"The letter after the transform (ciphertext).
"
89 __pdoc__[
'MenuItem.number
'] =
"The position of this item in the menu.
"
92 def make_menu(plaintext, ciphertext):
93 """Create a menu from a crib: a given plaintext and ciphertext.
95 No validation is done to ensure that this is a viable crib (e.g. no
96 checking for length, no checking that a letter is enciphered to itself).
98 return [MenuItem(p, c, i+
1)
99 for i, (p, c) in enumerate(zip(plaintext, ciphertext))]
102 class Scrambler(object):
103 """A scrambler is a collection of three `szyfrow.enigma.SimpleWheel`s.
105 def __init__(self, wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec,
106 wheel1_pos=
'a
', wheel2_pos=
'a
', wheel3_pos=
'a
'):
107 self.wheel1 = SimpleWheel(wheel1_spec, position=wheel1_pos)
108 self.wheel2 = SimpleWheel(wheel2_spec, position=wheel2_pos)
109 self.wheel3 = SimpleWheel(wheel3_spec, position=wheel3_pos)
110 self.reflector = Reflector(reflector_spec)
112 __pdoc__[
'Scrambler.wheel_positions
'] =
"""Return a
3-tuple of the wheel
113 positions (as numbers)
"""
114 __pdoc__[
'Scrambler.wheel_positions_l
'] =
"""Return a
3-tuple of the wheel
115 positions (as letters)
"""
116 def __getattribute__(self, name):
117 if name==
'wheel_positions
':
118 return self.wheel1.position, self.wheel2.position, self.wheel3.position
119 elif name==
'wheel_positions_l
':
120 return self.wheel1.position_l, self.wheel2.position_l, self.wheel3.position_l
122 return object.__getattribute__(self, name)
124 def advance(self, wheel1=False, wheel2=False, wheel3=True):
125 """Advance some wheels of a scrambler.
127 if wheel1: self.wheel1.advance()
128 if wheel2: self.wheel2.advance()
129 if wheel3: self.wheel3.advance()
131 def lookup(self, letter):
132 """Lookup the decipherment of a letter, given a particular scrambler
135 a = self.wheel3.forward(letter)
136 b = self.wheel2.forward(a)
137 c = self.wheel1.forward(b)
138 d = self.reflector.forward(c)
139 e = self.wheel1.backward(d)
140 f = self.wheel2.backward(e)
141 g = self.wheel3.backward(f)
144 def set_positions(self, wheel1_pos, wheel2_pos, wheel3_pos):
145 """Set the positions of a scrambler
's wheels.
147 self.wheel1.set_position(wheel1_pos)
148 self.wheel2.set_position(wheel2_pos)
149 self.wheel3.set_position(wheel3_pos)
153 """An entire Bombe machine.
155 This specifies the pattern of the wheels and reflectors used. The
156 scramblers are connected and wired up according the to the specification
159 Bombe objects are callable. Calling a Bombe (with the starting scrambler
160 positions) calls the `test` method and returns the pair of
161 `start_positions` and the result of `test`.
163 Bombe objects have attributes `wheel_positions` and `wheel_positions_l`,
164 which return the results of the scramblers
' `Scrambler.wheel_positions`
165 and `Scrambler.wheel_positions_l`.
168 def __init__(self, wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec,
169 menu=None, start_signal=None, use_diagonal_board=True,
170 verify_plugboard=True):
171 self.connections = []
172 self.wheel1_spec = wheel1_spec
173 self.wheel2_spec = wheel2_spec
174 self.wheel3_spec = wheel3_spec
175 self.reflector_spec = reflector_spec
179 self.test_start = start_signal
180 self.use_diagonal_board = use_diagonal_board
181 self.verify_plugboard = verify_plugboard
183 __pdoc__[
'Bombe.wheel_positions
'] =
"""Return a
3-tuple of the wheel
184 positions (as numbers)
"""
185 __pdoc__[
'Bomb3.wheel_positions_l
'] =
"""Return a
3-tuple of the wheel
186 positions (as letters)
"""
187 def __getattribute__(self, name):
188 if name==
'wheel_positions
':
189 return self.connections[
0].scrambler.wheel_positions
190 elif name==
'wheel_positions_l
':
191 return self.connections[
0].scrambler.wheel_positions_l
193 return object.__getattribute__(self, name)
195 def __call__(self, start_positions):
196 return start_positions, self.test(initial_signal=self.test_start,
197 start_positions=start_positions,
198 use_diagonal_board=self.use_diagonal_board,
199 verify_plugboard=self.verify_plugboard)
201 def add_connection(self, bank_before, bank_after, scrambler):
202 """Create a new connection between banks.
204 self.connections += [Connection([bank_before, bank_after], scrambler)]
206 def read_menu(self, menu):
207 """Read a menu, creating one scrambler for each element of the menu
208 and setting up the connections it implies. Also defines the most
209 common letter in the menu
's plaintext as the default letter to start
210 testing with.
"""
211 self.connections = []
213 scrambler = Scrambler(self.wheel1_spec, self.wheel2_spec, self.wheel3_spec,
215 wheel3_pos=unpos(item.number -
1))
216 self.add_connection(item.before, item.after, scrambler)
217 most_common_letter = (collections.Counter(m.before for m in menu) +\
218 collections.Counter(m.after for m in menu)).most_common(
1)[
0][
0]
219 self.test_start = Signal(most_common_letter, most_common_letter)
221 def set_positions(self, wheel1_pos, wheel2_pos, wheel3_pos):
222 """Set positions of all scramblers. The first scrambler will be set
223 to the specified positions. The second scrambler will have its
224 third wheel advanced one position; the third scramber will have its
225 third wheel advanced two positios; and so on. Not that the first and
226 second wheels of the scramblers are never advanced in setup.
"""
227 for i, c in enumerate(self.connections):
228 c.scrambler.set_positions(wheel1_pos, wheel2_pos, unpos(pos(wheel3_pos) + i))
230 def test(self, initial_signal=None, start_positions=None, use_diagonal_board=True,
231 verify_plugboard=True):
232 """Test a scrambler setting. It creates a signal (held in
233 `self.pending`) on the `initial_signal` wire then uses
234 `Bombe.propagate` to propagate the signal across the Bombe.
236 Returns a Boolean recording if this scrambler setting with
237 this signal is a
"stop
" (potential valid scrambler setting).
239 * If `initial_signal` is `None`, use the default starting signal set in
241 * If `start_positions` is `None`, use the existing scramber positions.
"""
243 dict(zip(string.ascii_lowercase,
244 [False]*len(string.ascii_lowercase)))
245 for label in string.ascii_lowercase}
247 self.set_positions(*start_positions)
248 if not initial_signal:
249 initial_signal = self.test_start
250 self.pending = [initial_signal]
251 self.propagate(use_diagonal_board)
252 live_wire_count = len([self.banks[self.test_start.bank][w]
253 for w in self.banks[self.test_start.bank]
254 if self.banks[self.test_start.bank][w]])
255 if live_wire_count
< 26:
257 possibles = self.possible_plugboards()
258 return all(s0.isdisjoint(s1)
267 def propagate(self, use_diagonal_board):
268 """Propagate a signal through the Bombe. Uses `self.pending` as an
269 agenda for a breadth-first search. Each element on the agenda represents
270 a particular wire in a bank that is being
"energised
" (set to `True`).
271 The first element in the agenda is removed, the wire/bank is set,
272 then all connected wire/banks are added to the `self.pending`
276 current = self.pending[
0]
277 # print(
"processing
", current)
278 self.pending = self.pending[
1:]
279 if not self.banks[current.bank][current.wire]:
280 self.banks[current.bank][current.wire] = True
281 if use_diagonal_board:
282 self.pending += [Signal(current.wire, current.bank)]
283 for c in self.connections:
284 if current.bank in c.banks:
285 other_bank = [b for b in c.banks if b != current.bank][
0]
286 other_wire = c.scrambler.lookup(current.wire)
287 # print(
" adding
", other_bank, other_wire,
"because
", c.banks)
288 self.pending += [Signal(other_bank, other_wire)]
290 def run(self, run_start=None, wheel1_pos=
'a
', wheel2_pos=
'a
', wheel3_pos=
'a
',
291 use_diagonal_board=True):
292 """Run a Bombe after setup with a menu, by trying all scramber
293 positions. For each scrambler position, `Bombe.test` is run. If the
294 test is successful, the scrambler positiions are added to `self.solutions`.
295 `self.Solutions` is returned.
298 run_start = self.test_start
300 self.set_positions(wheel1_pos, wheel2_pos, wheel3_pos)
301 for run_index in range(
26*
26*
26):
302 if self.test(initial_signal=run_start, use_diagonal_board=use_diagonal_board):
303 self.solutions += [self.connections[
0].scrambler.wheel_positions_l]
307 if (run_index +
1) %
26 ==
0: advance2 = True
308 if (run_index +
1) % (
26*
26) ==
0: advance1 = True
309 for c in self.connections:
310 c.scrambler.advance(advance1, advance2, advance3)
311 return self.solutions
313 def possible_plugboards(self):
314 """Given a Bombe after a `Bombe.test` has been performed, determine
315 what plugboard settings can be derived from the solution.
319 active = [w for w in self.banks[b] if self.banks[b][w]]
320 inactive = [w for w in self.banks[b] if not self.banks[b][w]]
322 possibles = possibles.union({frozenset((b, active[
0]))})
323 if len(inactive) ==
1:
324 possibles = possibles.union({frozenset((b, inactive[
0]))})
328 def run_multi_bombe(wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec, menu,
329 start_signal=None, use_diagonal_board=True,
330 verify_plugboard=True):
331 """Run a Bombe solution, spreading the load across multiple CPU cores.
332 Similar to `Bombe.run` in effects, but quicker on a multi-core machine.
334 allwheels = itertools.product(string.ascii_lowercase, repeat=
3)
336 with multiprocessing.Pool() as pool:
337 res = pool.map(Bombe(wheel1_spec, wheel2_spec, wheel3_spec,
338 reflector_spec, menu=menu, start_signal=start_signal,
339 use_diagonal_board=use_diagonal_board,
340 verify_plugboard=verify_plugboard),
342 return [r[
0] for r in res if r[
1]]
</code></pre>
350 <h2 class=
"section-title" id=
"header-functions">Functions
</h2>
352 <dt id=
"szyfrow.bombe.cat"><code class=
"name flex">
353 <span>def
<span class=
"ident">cat
</span></span>(
<span>iterable, /)
</span>
356 <div class=
"desc"><p>Concatenate any number of strings.
</p>
357 <p>The string whose method is called is inserted in between each given string.
358 The result is returned as a new string.
</p>
359 <p>Example: '.'.join(['ab', 'pq', 'rs']) -
> 'ab.pq.rs'
</p></div>
361 <dt id=
"szyfrow.bombe.lcat"><code class=
"name flex">
362 <span>def
<span class=
"ident">lcat
</span></span>(
<span>iterable, /)
</span>
365 <div class=
"desc"><p>Concatenate any number of strings.
</p>
366 <p>The string whose method is called is inserted in between each given string.
367 The result is returned as a new string.
</p>
368 <p>Example: '.'.join(['ab', 'pq', 'rs']) -
> 'ab.pq.rs'
</p></div>
370 <dt id=
"szyfrow.bombe.make_menu"><code class=
"name flex">
371 <span>def
<span class=
"ident">make_menu
</span></span>(
<span>plaintext, ciphertext)
</span>
374 <div class=
"desc"><p>Create a menu from a crib: a given plaintext and ciphertext.
</p>
375 <p>No validation is done to ensure that this is a viable crib (e.g. no
376 checking for length, no checking that a letter is enciphered to itself).
</p></div>
377 <details class=
"source">
379 <span>Expand source code
</span>
381 <pre><code class=
"python">def make_menu(plaintext, ciphertext):
382 """Create a menu from a crib: a given plaintext and ciphertext.
384 No validation is done to ensure that this is a viable crib (e.g. no
385 checking for length, no checking that a letter is enciphered to itself).
387 return [MenuItem(p, c, i+
1)
388 for i, (p, c) in enumerate(zip(plaintext, ciphertext))]
</code></pre>
391 <dt id=
"szyfrow.bombe.run_multi_bombe"><code class=
"name flex">
392 <span>def
<span class=
"ident">run_multi_bombe
</span></span>(
<span>wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec, menu, start_signal=None, use_diagonal_board=True, verify_plugboard=True)
</span>
395 <div class=
"desc"><p>Run a Bombe solution, spreading the load across multiple CPU cores.
396 Similar to
<code><a title=
"szyfrow.bombe.Bombe.run" href=
"#szyfrow.bombe.Bombe.run">Bombe.run()
</a></code> in effects, but quicker on a multi-core machine.
</p></div>
397 <details class=
"source">
399 <span>Expand source code
</span>
401 <pre><code class=
"python">def run_multi_bombe(wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec, menu,
402 start_signal=None, use_diagonal_board=True,
403 verify_plugboard=True):
404 """Run a Bombe solution, spreading the load across multiple CPU cores.
405 Similar to `Bombe.run` in effects, but quicker on a multi-core machine.
407 allwheels = itertools.product(string.ascii_lowercase, repeat=
3)
409 with multiprocessing.Pool() as pool:
410 res = pool.map(Bombe(wheel1_spec, wheel2_spec, wheel3_spec,
411 reflector_spec, menu=menu, start_signal=start_signal,
412 use_diagonal_board=use_diagonal_board,
413 verify_plugboard=verify_plugboard),
415 return [r[
0] for r in res if r[
1]]
</code></pre>
418 <dt id=
"szyfrow.bombe.wcat"><code class=
"name flex">
419 <span>def
<span class=
"ident">wcat
</span></span>(
<span>iterable, /)
</span>
422 <div class=
"desc"><p>Concatenate any number of strings.
</p>
423 <p>The string whose method is called is inserted in between each given string.
424 The result is returned as a new string.
</p>
425 <p>Example: '.'.join(['ab', 'pq', 'rs']) -
> 'ab.pq.rs'
</p></div>
430 <h2 class=
"section-title" id=
"header-classes">Classes
</h2>
432 <dt id=
"szyfrow.bombe.Bombe"><code class=
"flex name class">
433 <span>class
<span class=
"ident">Bombe
</span></span>
434 <span>(
</span><span>wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec, menu=None, start_signal=None, use_diagonal_board=True, verify_plugboard=True)
</span>
437 <div class=
"desc"><p>An entire Bombe machine.
</p>
438 <p>This specifies the pattern of the wheels and reflectors used. The
439 scramblers are connected and wired up according the to the specification
440 given by the menu.
</p>
441 <p>Bombe objects are callable. Calling a Bombe (with the starting scrambler
442 positions) calls the
<code>test
</code> method and
444 <code>start_positions
</code> and the result of
<code>test
</code>.
</p>
445 <p>Bombe objects have attributes
<code>wheel_positions
</code> and
<code>wheel_positions_l
</code>,
446 which return the results of the scramblers'
<code>Scrambler.wheel_positions
</code>
447 and
<code>Scrambler.wheel_positions_l
</code>.
</p></div>
448 <details class=
"source">
450 <span>Expand source code
</span>
452 <pre><code class=
"python">class Bombe(object):
453 """An entire Bombe machine.
455 This specifies the pattern of the wheels and reflectors used. The
456 scramblers are connected and wired up according the to the specification
459 Bombe objects are callable. Calling a Bombe (with the starting scrambler
460 positions) calls the `test` method and returns the pair of
461 `start_positions` and the result of `test`.
463 Bombe objects have attributes `wheel_positions` and `wheel_positions_l`,
464 which return the results of the scramblers
' `Scrambler.wheel_positions`
465 and `Scrambler.wheel_positions_l`.
468 def __init__(self, wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec,
469 menu=None, start_signal=None, use_diagonal_board=True,
470 verify_plugboard=True):
471 self.connections = []
472 self.wheel1_spec = wheel1_spec
473 self.wheel2_spec = wheel2_spec
474 self.wheel3_spec = wheel3_spec
475 self.reflector_spec = reflector_spec
479 self.test_start = start_signal
480 self.use_diagonal_board = use_diagonal_board
481 self.verify_plugboard = verify_plugboard
483 __pdoc__[
'Bombe.wheel_positions
'] =
"""Return a
3-tuple of the wheel
484 positions (as numbers)
"""
485 __pdoc__[
'Bomb3.wheel_positions_l
'] =
"""Return a
3-tuple of the wheel
486 positions (as letters)
"""
487 def __getattribute__(self, name):
488 if name==
'wheel_positions
':
489 return self.connections[
0].scrambler.wheel_positions
490 elif name==
'wheel_positions_l
':
491 return self.connections[
0].scrambler.wheel_positions_l
493 return object.__getattribute__(self, name)
495 def __call__(self, start_positions):
496 return start_positions, self.test(initial_signal=self.test_start,
497 start_positions=start_positions,
498 use_diagonal_board=self.use_diagonal_board,
499 verify_plugboard=self.verify_plugboard)
501 def add_connection(self, bank_before, bank_after, scrambler):
502 """Create a new connection between banks.
504 self.connections += [Connection([bank_before, bank_after], scrambler)]
506 def read_menu(self, menu):
507 """Read a menu, creating one scrambler for each element of the menu
508 and setting up the connections it implies. Also defines the most
509 common letter in the menu
's plaintext as the default letter to start
510 testing with.
"""
511 self.connections = []
513 scrambler = Scrambler(self.wheel1_spec, self.wheel2_spec, self.wheel3_spec,
515 wheel3_pos=unpos(item.number -
1))
516 self.add_connection(item.before, item.after, scrambler)
517 most_common_letter = (collections.Counter(m.before for m in menu) +\
518 collections.Counter(m.after for m in menu)).most_common(
1)[
0][
0]
519 self.test_start = Signal(most_common_letter, most_common_letter)
521 def set_positions(self, wheel1_pos, wheel2_pos, wheel3_pos):
522 """Set positions of all scramblers. The first scrambler will be set
523 to the specified positions. The second scrambler will have its
524 third wheel advanced one position; the third scramber will have its
525 third wheel advanced two positios; and so on. Not that the first and
526 second wheels of the scramblers are never advanced in setup.
"""
527 for i, c in enumerate(self.connections):
528 c.scrambler.set_positions(wheel1_pos, wheel2_pos, unpos(pos(wheel3_pos) + i))
530 def test(self, initial_signal=None, start_positions=None, use_diagonal_board=True,
531 verify_plugboard=True):
532 """Test a scrambler setting. It creates a signal (held in
533 `self.pending`) on the `initial_signal` wire then uses
534 `Bombe.propagate` to propagate the signal across the Bombe.
536 Returns a Boolean recording if this scrambler setting with
537 this signal is a
"stop
" (potential valid scrambler setting).
539 * If `initial_signal` is `None`, use the default starting signal set in
541 * If `start_positions` is `None`, use the existing scramber positions.
"""
543 dict(zip(string.ascii_lowercase,
544 [False]*len(string.ascii_lowercase)))
545 for label in string.ascii_lowercase}
547 self.set_positions(*start_positions)
548 if not initial_signal:
549 initial_signal = self.test_start
550 self.pending = [initial_signal]
551 self.propagate(use_diagonal_board)
552 live_wire_count = len([self.banks[self.test_start.bank][w]
553 for w in self.banks[self.test_start.bank]
554 if self.banks[self.test_start.bank][w]])
555 if live_wire_count
< 26:
557 possibles = self.possible_plugboards()
558 return all(s0.isdisjoint(s1)
567 def propagate(self, use_diagonal_board):
568 """Propagate a signal through the Bombe. Uses `self.pending` as an
569 agenda for a breadth-first search. Each element on the agenda represents
570 a particular wire in a bank that is being
"energised
" (set to `True`).
571 The first element in the agenda is removed, the wire/bank is set,
572 then all connected wire/banks are added to the `self.pending`
576 current = self.pending[
0]
577 # print(
"processing
", current)
578 self.pending = self.pending[
1:]
579 if not self.banks[current.bank][current.wire]:
580 self.banks[current.bank][current.wire] = True
581 if use_diagonal_board:
582 self.pending += [Signal(current.wire, current.bank)]
583 for c in self.connections:
584 if current.bank in c.banks:
585 other_bank = [b for b in c.banks if b != current.bank][
0]
586 other_wire = c.scrambler.lookup(current.wire)
587 # print(
" adding
", other_bank, other_wire,
"because
", c.banks)
588 self.pending += [Signal(other_bank, other_wire)]
590 def run(self, run_start=None, wheel1_pos=
'a
', wheel2_pos=
'a
', wheel3_pos=
'a
',
591 use_diagonal_board=True):
592 """Run a Bombe after setup with a menu, by trying all scramber
593 positions. For each scrambler position, `Bombe.test` is run. If the
594 test is successful, the scrambler positiions are added to `self.solutions`.
595 `self.Solutions` is returned.
598 run_start = self.test_start
600 self.set_positions(wheel1_pos, wheel2_pos, wheel3_pos)
601 for run_index in range(
26*
26*
26):
602 if self.test(initial_signal=run_start, use_diagonal_board=use_diagonal_board):
603 self.solutions += [self.connections[
0].scrambler.wheel_positions_l]
607 if (run_index +
1) %
26 ==
0: advance2 = True
608 if (run_index +
1) % (
26*
26) ==
0: advance1 = True
609 for c in self.connections:
610 c.scrambler.advance(advance1, advance2, advance3)
611 return self.solutions
613 def possible_plugboards(self):
614 """Given a Bombe after a `Bombe.test` has been performed, determine
615 what plugboard settings can be derived from the solution.
619 active = [w for w in self.banks[b] if self.banks[b][w]]
620 inactive = [w for w in self.banks[b] if not self.banks[b][w]]
622 possibles = possibles.union({frozenset((b, active[
0]))})
623 if len(inactive) ==
1:
624 possibles = possibles.union({frozenset((b, inactive[
0]))})
625 return possibles
</code></pre>
629 <dt id=
"szyfrow.bombe.Bombe.add_connection"><code class=
"name flex">
630 <span>def
<span class=
"ident">add_connection
</span></span>(
<span>self, bank_before, bank_after, scrambler)
</span>
633 <div class=
"desc"><p>Create a new connection between banks.
</p></div>
634 <details class=
"source">
636 <span>Expand source code
</span>
638 <pre><code class=
"python">def add_connection(self, bank_before, bank_after, scrambler):
639 """Create a new connection between banks.
641 self.connections += [Connection([bank_before, bank_after], scrambler)]
</code></pre>
644 <dt id=
"szyfrow.bombe.Bombe.possible_plugboards"><code class=
"name flex">
645 <span>def
<span class=
"ident">possible_plugboards
</span></span>(
<span>self)
</span>
648 <div class=
"desc"><p>Given a Bombe after a
<code><a title=
"szyfrow.bombe.Bombe.test" href=
"#szyfrow.bombe.Bombe.test">Bombe.test()
</a></code> has been performed, determine
649 what plugboard settings can be derived from the solution.
</p></div>
650 <details class=
"source">
652 <span>Expand source code
</span>
654 <pre><code class=
"python">def possible_plugboards(self):
655 """Given a Bombe after a `Bombe.test` has been performed, determine
656 what plugboard settings can be derived from the solution.
660 active = [w for w in self.banks[b] if self.banks[b][w]]
661 inactive = [w for w in self.banks[b] if not self.banks[b][w]]
663 possibles = possibles.union({frozenset((b, active[
0]))})
664 if len(inactive) ==
1:
665 possibles = possibles.union({frozenset((b, inactive[
0]))})
666 return possibles
</code></pre>
669 <dt id=
"szyfrow.bombe.Bombe.propagate"><code class=
"name flex">
670 <span>def
<span class=
"ident">propagate
</span></span>(
<span>self, use_diagonal_board)
</span>
673 <div class=
"desc"><p>Propagate a signal through the Bombe. Uses
<code>self.pending
</code> as an
674 agenda for a breadth-first search. Each element on the agenda represents
675 a particular wire in a bank that is being
"energised" (set to
<code>True
</code>).
676 The first element in the agenda is removed, the wire/bank is set,
677 then all connected wire/banks are added to the
<code>self.pending
</code>
679 <details class=
"source">
681 <span>Expand source code
</span>
683 <pre><code class=
"python">def propagate(self, use_diagonal_board):
684 """Propagate a signal through the Bombe. Uses `self.pending` as an
685 agenda for a breadth-first search. Each element on the agenda represents
686 a particular wire in a bank that is being
"energised
" (set to `True`).
687 The first element in the agenda is removed, the wire/bank is set,
688 then all connected wire/banks are added to the `self.pending`
692 current = self.pending[
0]
693 # print(
"processing
", current)
694 self.pending = self.pending[
1:]
695 if not self.banks[current.bank][current.wire]:
696 self.banks[current.bank][current.wire] = True
697 if use_diagonal_board:
698 self.pending += [Signal(current.wire, current.bank)]
699 for c in self.connections:
700 if current.bank in c.banks:
701 other_bank = [b for b in c.banks if b != current.bank][
0]
702 other_wire = c.scrambler.lookup(current.wire)
703 # print(
" adding
", other_bank, other_wire,
"because
", c.banks)
704 self.pending += [Signal(other_bank, other_wire)]
</code></pre>
707 <dt id=
"szyfrow.bombe.Bombe.read_menu"><code class=
"name flex">
708 <span>def
<span class=
"ident">read_menu
</span></span>(
<span>self, menu)
</span>
711 <div class=
"desc"><p>Read a menu, creating one scrambler for each element of the menu
712 and setting up the connections it implies. Also defines the most
713 common letter in the menu's plaintext as the default letter to start
714 testing with.
</p></div>
715 <details class=
"source">
717 <span>Expand source code
</span>
719 <pre><code class=
"python">def read_menu(self, menu):
720 """Read a menu, creating one scrambler for each element of the menu
721 and setting up the connections it implies. Also defines the most
722 common letter in the menu
's plaintext as the default letter to start
723 testing with.
"""
724 self.connections = []
726 scrambler = Scrambler(self.wheel1_spec, self.wheel2_spec, self.wheel3_spec,
728 wheel3_pos=unpos(item.number -
1))
729 self.add_connection(item.before, item.after, scrambler)
730 most_common_letter = (collections.Counter(m.before for m in menu) +\
731 collections.Counter(m.after for m in menu)).most_common(
1)[
0][
0]
732 self.test_start = Signal(most_common_letter, most_common_letter)
</code></pre>
735 <dt id=
"szyfrow.bombe.Bombe.run"><code class=
"name flex">
736 <span>def
<span class=
"ident">run
</span></span>(
<span>self, run_start=None, wheel1_pos='a', wheel2_pos='a', wheel3_pos='a', use_diagonal_board=True)
</span>
739 <div class=
"desc"><p>Run a Bombe after setup with a menu, by trying all scramber
740 positions. For each scrambler position,
<code><a title=
"szyfrow.bombe.Bombe.test" href=
"#szyfrow.bombe.Bombe.test">Bombe.test()
</a></code> is run. If the
741 test is successful, the scrambler positiions are added to
<code>self.solutions
</code>.
742 <code>self.Solutions
</code> is returned.
</p></div>
743 <details class=
"source">
745 <span>Expand source code
</span>
747 <pre><code class=
"python">def run(self, run_start=None, wheel1_pos=
'a
', wheel2_pos=
'a
', wheel3_pos=
'a
',
748 use_diagonal_board=True):
749 """Run a Bombe after setup with a menu, by trying all scramber
750 positions. For each scrambler position, `Bombe.test` is run. If the
751 test is successful, the scrambler positiions are added to `self.solutions`.
752 `self.Solutions` is returned.
755 run_start = self.test_start
757 self.set_positions(wheel1_pos, wheel2_pos, wheel3_pos)
758 for run_index in range(
26*
26*
26):
759 if self.test(initial_signal=run_start, use_diagonal_board=use_diagonal_board):
760 self.solutions += [self.connections[
0].scrambler.wheel_positions_l]
764 if (run_index +
1) %
26 ==
0: advance2 = True
765 if (run_index +
1) % (
26*
26) ==
0: advance1 = True
766 for c in self.connections:
767 c.scrambler.advance(advance1, advance2, advance3)
768 return self.solutions
</code></pre>
771 <dt id=
"szyfrow.bombe.Bombe.set_positions"><code class=
"name flex">
772 <span>def
<span class=
"ident">set_positions
</span></span>(
<span>self, wheel1_pos, wheel2_pos, wheel3_pos)
</span>
775 <div class=
"desc"><p>Set positions of all scramblers. The first scrambler will be set
776 to the specified positions. The second scrambler will have its
777 third wheel advanced one position; the third scramber will have its
778 third wheel advanced two positios; and so on. Not that the first and
779 second wheels of the scramblers are never advanced in setup.
</p></div>
780 <details class=
"source">
782 <span>Expand source code
</span>
784 <pre><code class=
"python">def set_positions(self, wheel1_pos, wheel2_pos, wheel3_pos):
785 """Set positions of all scramblers. The first scrambler will be set
786 to the specified positions. The second scrambler will have its
787 third wheel advanced one position; the third scramber will have its
788 third wheel advanced two positios; and so on. Not that the first and
789 second wheels of the scramblers are never advanced in setup.
"""
790 for i, c in enumerate(self.connections):
791 c.scrambler.set_positions(wheel1_pos, wheel2_pos, unpos(pos(wheel3_pos) + i))
</code></pre>
794 <dt id=
"szyfrow.bombe.Bombe.test"><code class=
"name flex">
795 <span>def
<span class=
"ident">test
</span></span>(
<span>self, initial_signal=None, start_positions=None, use_diagonal_board=True, verify_plugboard=True)
</span>
798 <div class=
"desc"><p>Test a scrambler setting. It creates a signal (held in
799 <code>self.pending
</code>) on the
<code>initial_signal
</code> wire then uses
800 <code><a title=
"szyfrow.bombe.Bombe.propagate" href=
"#szyfrow.bombe.Bombe.propagate">Bombe.propagate()
</a></code> to propagate the signal across the Bombe.
</p>
801 <p>Returns a Boolean recording if this scrambler setting with
802 this signal is a
"stop" (potential valid scrambler setting).
</p>
804 <li>If
<code>initial_signal
</code> is
<code>None
</code>, use the default starting signal set in
805 <code><a title=
"szyfrow.bombe.Bombe.read_menu" href=
"#szyfrow.bombe.Bombe.read_menu">Bombe.read_menu()
</a></code></li>
806 <li>If
<code>start_positions
</code> is
<code>None
</code>, use the existing scramber positions.
</li>
808 <details class=
"source">
810 <span>Expand source code
</span>
812 <pre><code class=
"python">def test(self, initial_signal=None, start_positions=None, use_diagonal_board=True,
813 verify_plugboard=True):
814 """Test a scrambler setting. It creates a signal (held in
815 `self.pending`) on the `initial_signal` wire then uses
816 `Bombe.propagate` to propagate the signal across the Bombe.
818 Returns a Boolean recording if this scrambler setting with
819 this signal is a
"stop
" (potential valid scrambler setting).
821 * If `initial_signal` is `None`, use the default starting signal set in
823 * If `start_positions` is `None`, use the existing scramber positions.
"""
825 dict(zip(string.ascii_lowercase,
826 [False]*len(string.ascii_lowercase)))
827 for label in string.ascii_lowercase}
829 self.set_positions(*start_positions)
830 if not initial_signal:
831 initial_signal = self.test_start
832 self.pending = [initial_signal]
833 self.propagate(use_diagonal_board)
834 live_wire_count = len([self.banks[self.test_start.bank][w]
835 for w in self.banks[self.test_start.bank]
836 if self.banks[self.test_start.bank][w]])
837 if live_wire_count
< 26:
839 possibles = self.possible_plugboards()
840 return all(s0.isdisjoint(s1)
847 return False
</code></pre>
852 <dt id=
"szyfrow.bombe.Connection"><code class=
"flex name class">
853 <span>class
<span class=
"ident">Connection
</span></span>
854 <span>(
</span><span>banks, scrambler)
</span>
857 <div class=
"desc"><p>A connection between banks made by a particular
858 scrambler (the scrambler state given by its position in the crib).
</p></div>
861 <li>builtins.tuple
</li>
863 <h3>Instance variables
</h3>
865 <dt id=
"szyfrow.bombe.Connection.banks"><code class=
"name">var
<span class=
"ident">banks
</span></code></dt>
867 <div class=
"desc"><p>A list of two items, holding the bnaks of
868 a connection.
</p></div>
870 <dt id=
"szyfrow.bombe.Connection.scrambler"><code class=
"name">var
<span class=
"ident">scrambler
</span></code></dt>
872 <div class=
"desc"><p>The bnaks of a connection.
</p></div>
876 <dt id=
"szyfrow.bombe.MenuIem"><code class=
"flex name class">
877 <span>class
<span class=
"ident">MenuItem
</span></span>
878 <span>(
</span><span>before, after, number)
</span>
881 <div class=
"desc"><p>MenuIem(before, after, number)
</p></div>
884 <li>builtins.tuple
</li>
886 <h3>Instance variables
</h3>
888 <dt id=
"szyfrow.bombe.MenuIem.after"><code class=
"name">var
<span class=
"ident">after
</span></code></dt>
890 <div class=
"desc"><p>Alias for field number
1</p></div>
892 <dt id=
"szyfrow.bombe.MenuIem.before"><code class=
"name">var
<span class=
"ident">before
</span></code></dt>
894 <div class=
"desc"><p>Alias for field number
0</p></div>
896 <dt id=
"szyfrow.bombe.MenuIem.number"><code class=
"name">var
<span class=
"ident">number
</span></code></dt>
898 <div class=
"desc"><p>Alias for field number
2</p></div>
902 <dt id=
"szyfrow.bombe.Scrambler"><code class=
"flex name class">
903 <span>class
<span class=
"ident">Scrambler
</span></span>
904 <span>(
</span><span>wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec, wheel1_pos='a', wheel2_pos='a', wheel3_pos='a')
</span>
907 <div class=
"desc"><p>A scrambler is a collection of three
<code><a title=
"szyfrow.enigma.SimpleWheel" href=
"enigma.html#szyfrow.enigma.SimpleWheel">SimpleWheel
</a></code>s.
</p></div>
908 <details class=
"source">
910 <span>Expand source code
</span>
912 <pre><code class=
"python">class Scrambler(object):
913 """A scrambler is a collection of three `szyfrow.enigma.SimpleWheel`s.
915 def __init__(self, wheel1_spec, wheel2_spec, wheel3_spec, reflector_spec,
916 wheel1_pos=
'a
', wheel2_pos=
'a
', wheel3_pos=
'a
'):
917 self.wheel1 = SimpleWheel(wheel1_spec, position=wheel1_pos)
918 self.wheel2 = SimpleWheel(wheel2_spec, position=wheel2_pos)
919 self.wheel3 = SimpleWheel(wheel3_spec, position=wheel3_pos)
920 self.reflector = Reflector(reflector_spec)
922 __pdoc__[
'Scrambler.wheel_positions
'] =
"""Return a
3-tuple of the wheel
923 positions (as numbers)
"""
924 __pdoc__[
'Scrambler.wheel_positions_l
'] =
"""Return a
3-tuple of the wheel
925 positions (as letters)
"""
926 def __getattribute__(self, name):
927 if name==
'wheel_positions
':
928 return self.wheel1.position, self.wheel2.position, self.wheel3.position
929 elif name==
'wheel_positions_l
':
930 return self.wheel1.position_l, self.wheel2.position_l, self.wheel3.position_l
932 return object.__getattribute__(self, name)
934 def advance(self, wheel1=False, wheel2=False, wheel3=True):
935 """Advance some wheels of a scrambler.
937 if wheel1: self.wheel1.advance()
938 if wheel2: self.wheel2.advance()
939 if wheel3: self.wheel3.advance()
941 def lookup(self, letter):
942 """Lookup the decipherment of a letter, given a particular scrambler
945 a = self.wheel3.forward(letter)
946 b = self.wheel2.forward(a)
947 c = self.wheel1.forward(b)
948 d = self.reflector.forward(c)
949 e = self.wheel1.backward(d)
950 f = self.wheel2.backward(e)
951 g = self.wheel3.backward(f)
954 def set_positions(self, wheel1_pos, wheel2_pos, wheel3_pos):
955 """Set the positions of a scrambler
's wheels.
957 self.wheel1.set_position(wheel1_pos)
958 self.wheel2.set_position(wheel2_pos)
959 self.wheel3.set_position(wheel3_pos)
</code></pre>
963 <dt id=
"szyfrow.bombe.Scrambler.advance"><code class=
"name flex">
964 <span>def
<span class=
"ident">advance
</span></span>(
<span>self, wheel1=False, wheel2=False, wheel3=True)
</span>
967 <div class=
"desc"><p>Advance some wheels of a scrambler.
</p></div>
968 <details class=
"source">
970 <span>Expand source code
</span>
972 <pre><code class=
"python">def advance(self, wheel1=False, wheel2=False, wheel3=True):
973 """Advance some wheels of a scrambler.
975 if wheel1: self.wheel1.advance()
976 if wheel2: self.wheel2.advance()
977 if wheel3: self.wheel3.advance()
</code></pre>
980 <dt id=
"szyfrow.bombe.Scrambler.lookup"><code class=
"name flex">
981 <span>def
<span class=
"ident">lookup
</span></span>(
<span>self, letter)
</span>
984 <div class=
"desc"><p>Lookup the decipherment of a letter, given a particular scrambler
985 orientation.
</p></div>
986 <details class=
"source">
988 <span>Expand source code
</span>
990 <pre><code class=
"python">def lookup(self, letter):
991 """Lookup the decipherment of a letter, given a particular scrambler
994 a = self.wheel3.forward(letter)
995 b = self.wheel2.forward(a)
996 c = self.wheel1.forward(b)
997 d = self.reflector.forward(c)
998 e = self.wheel1.backward(d)
999 f = self.wheel2.backward(e)
1000 g = self.wheel3.backward(f)
1001 return g
</code></pre>
1004 <dt id=
"szyfrow.bombe.Scrambler.set_positions"><code class=
"name flex">
1005 <span>def
<span class=
"ident">set_positions
</span></span>(
<span>self, wheel1_pos, wheel2_pos, wheel3_pos)
</span>
1008 <div class=
"desc"><p>Set the positions of a scrambler's wheels.
</p></div>
1009 <details class=
"source">
1011 <span>Expand source code
</span>
1013 <pre><code class=
"python">def set_positions(self, wheel1_pos, wheel2_pos, wheel3_pos):
1014 """Set the positions of a scrambler
's wheels.
1016 self.wheel1.set_position(wheel1_pos)
1017 self.wheel2.set_position(wheel2_pos)
1018 self.wheel3.set_position(wheel3_pos)
</code></pre>
1023 <dt id=
"szyfrow.bombe.Signal"><code class=
"flex name class">
1024 <span>class
<span class=
"ident">Signal
</span></span>
1025 <span>(
</span><span>bank, wire)
</span>
1028 <div class=
"desc"><p>Current propogation through the Bombe indicates that
1029 this wire in this bank is live, and the effects need to be proogated further
1030 through the machine.
</p></div>
1033 <li>builtins.tuple
</li>
1035 <h3>Instance variables
</h3>
1037 <dt id=
"szyfrow.bombe.Signal.bank"><code class=
"name">var
<span class=
"ident">bank
</span></code></dt>
1039 <div class=
"desc"><p>The bank of a signal.
</p></div>
1041 <dt id=
"szyfrow.bombe.Signal.wire"><code class=
"name">var
<span class=
"ident">wire
</span></code></dt>
1043 <div class=
"desc"><p>The wire of a signal.
</p></div>
1056 <li><h3>Super-module
</h3>
1058 <li><code><a title=
"szyfrow" href=
"index.html">szyfrow
</a></code></li>
1061 <li><h3><a href=
"#header-functions">Functions
</a></h3>
1063 <li><code><a title=
"szyfrow.bombe.cat" href=
"#szyfrow.bombe.cat">cat
</a></code></li>
1064 <li><code><a title=
"szyfrow.bombe.lcat" href=
"#szyfrow.bombe.lcat">lcat
</a></code></li>
1065 <li><code><a title=
"szyfrow.bombe.make_menu" href=
"#szyfrow.bombe.make_menu">make_menu
</a></code></li>
1066 <li><code><a title=
"szyfrow.bombe.run_multi_bombe" href=
"#szyfrow.bombe.run_multi_bombe">run_multi_bombe
</a></code></li>
1067 <li><code><a title=
"szyfrow.bombe.wcat" href=
"#szyfrow.bombe.wcat">wcat
</a></code></li>
1070 <li><h3><a href=
"#header-classes">Classes
</a></h3>
1073 <h4><code><a title=
"szyfrow.bombe.Bombe" href=
"#szyfrow.bombe.Bombe">Bombe
</a></code></h4>
1074 <ul class=
"two-column">
1075 <li><code><a title=
"szyfrow.bombe.Bombe.add_connection" href=
"#szyfrow.bombe.Bombe.add_connection">add_connection
</a></code></li>
1076 <li><code><a title=
"szyfrow.bombe.Bombe.possible_plugboards" href=
"#szyfrow.bombe.Bombe.possible_plugboards">possible_plugboards
</a></code></li>
1077 <li><code><a title=
"szyfrow.bombe.Bombe.propagate" href=
"#szyfrow.bombe.Bombe.propagate">propagate
</a></code></li>
1078 <li><code><a title=
"szyfrow.bombe.Bombe.read_menu" href=
"#szyfrow.bombe.Bombe.read_menu">read_menu
</a></code></li>
1079 <li><code><a title=
"szyfrow.bombe.Bombe.run" href=
"#szyfrow.bombe.Bombe.run">run
</a></code></li>
1080 <li><code><a title=
"szyfrow.bombe.Bombe.set_positions" href=
"#szyfrow.bombe.Bombe.set_positions">set_positions
</a></code></li>
1081 <li><code><a title=
"szyfrow.bombe.Bombe.test" href=
"#szyfrow.bombe.Bombe.test">test
</a></code></li>
1085 <h4><code><a title=
"szyfrow.bombe.Connection" href=
"#szyfrow.bombe.Connection">Connection
</a></code></h4>
1087 <li><code><a title=
"szyfrow.bombe.Connection.banks" href=
"#szyfrow.bombe.Connection.banks">banks
</a></code></li>
1088 <li><code><a title=
"szyfrow.bombe.Connection.scrambler" href=
"#szyfrow.bombe.Connection.scrambler">scrambler
</a></code></li>
1092 <h4><code><a title=
"szyfrow.bombe.MenuIem" href=
"#szyfrow.bombe.MenuIem">MenuIem
</a></code></h4>
1094 <li><code><a title=
"szyfrow.bombe.MenuIem.after" href=
"#szyfrow.bombe.MenuIem.after">after
</a></code></li>
1095 <li><code><a title=
"szyfrow.bombe.MenuIem.before" href=
"#szyfrow.bombe.MenuIem.before">before
</a></code></li>
1096 <li><code><a title=
"szyfrow.bombe.MenuIem.number" href=
"#szyfrow.bombe.MenuIem.number">number
</a></code></li>
1100 <h4><code><a title=
"szyfrow.bombe.Scrambler" href=
"#szyfrow.bombe.Scrambler">Scrambler
</a></code></h4>
1102 <li><code><a title=
"szyfrow.bombe.Scrambler.advance" href=
"#szyfrow.bombe.Scrambler.advance">advance
</a></code></li>
1103 <li><code><a title=
"szyfrow.bombe.Scrambler.lookup" href=
"#szyfrow.bombe.Scrambler.lookup">lookup
</a></code></li>
1104 <li><code><a title=
"szyfrow.bombe.Scrambler.set_positions" href=
"#szyfrow.bombe.Scrambler.set_positions">set_positions
</a></code></li>
1108 <h4><code><a title=
"szyfrow.bombe.Signal" href=
"#szyfrow.bombe.Signal">Signal
</a></code></h4>
1110 <li><code><a title=
"szyfrow.bombe.Signal.bank" href=
"#szyfrow.bombe.Signal.bank">bank
</a></code></li>
1111 <li><code><a title=
"szyfrow.bombe.Signal.wire" href=
"#szyfrow.bombe.Signal.wire">wire
</a></code></li>
1119 <footer id=
"footer">
1120 <p>Generated by
<a href=
"https://pdoc3.github.io/pdoc"><cite>pdoc
</cite> 0.9.2</a>.
</p>