Python Forum
Enigma Machine, I need help!
Thread Rating:
  • 3 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Enigma Machine, I need help!
#51
Quote:So thamk you a lot, and it isn't too urgent that it is done, it just sounded you were near to done
In programming, it's always almost done., let me just say there's more to do, and set a goal for next weekend.
Right Now, I'm working on the graphics for the plug board.
Here's what the first row of plugs looks like so far (click to enlarge):
   
when you click on a letter, and then another, the centers will change color, 13 different colors for all pairs.

I'm pretty satisfied with the operation of the  module Incrementor.py. You can download it,  and play with it, as
it has code to run standalone, or imported into full project.

It can do all of cipher, less the plug board.

Once the plugboard is done, I'll put it all together and you can add the gui.
The plugboard gui can be imported into the main gui as it uses a parent window to draw in.
all you will have to do to make it work, it to provide the parent location, and it will draw there.
[align=initial !important]
I also thought it would be fun to add a lamp gui, but that would probably take another few days.

I'll keep you updated
here's the full GUI, not connected yet, but I will put the code on Github in the next few minutes.
    [/align]
Reply
#52
Patchboard is partially working now, enough to play with it and get an idea of where I'm heading with it.
remaining issues:
  • Doesn't appear to be using all 13 colors, so I think my color chooses is broken.
  • Haven't attempted to add the selected pairs to the encryption algorithm yet.
  • Most likely other issues that won't show up until a full test is done.
the latest is on GitHub. Play with it and advise on other issues while I try to solve those above.
I am also going to take the time to synchronize with GitHub so code is always up to date (have to put the
hooks into PyCharm).
Reply
#53
Patchboard is done except for small change.
Needs a 'Done' button, and remove print statement which i left in for now because it shows expansion and
shrinking of patchboard as plugs are added and removed.

As always can be tested by running:
Python PatchBaord.py
and module is up to date in github (I can now do pushes directly from PyCharm)
Reply
#54
The images look very clean and professional. Did you use wxPython for the GUI?
If it ain't broke, I just haven't gotten to it yet.
OS: Windows 10, openSuse 42.3, freeBSD 11, Raspian "Stretch"
Python 3.6.5, IDE: PyCharm 2018 Community Edition
Reply
#55
I used tkinter. They are just overlays of the same image. I colored the centers with gimp.
I'm trying to finish up this weekend. I had restarted the encryption routine about four times, each time believing
that I really understood the operation. But not actually getting it right until two days ago. This time
I did it correctly, building my test case first, so I'm confident (yet again) that I have it right this time.
I'm also feeling guilty for commandeering the project.
Reply
#56
Hate to say I'm still working on this, but I am, at least I haven't given up, nor will I.

I found several more on line emulators - In order of favorite to least favorite

https://people.physik.hu-berlin.de/~pall...20_en.html
http://enigma.louisedade.co.uk/enigma.html
http://summersidemakerspace.ca/projects/enigma-machine/

Key sheet generators:
https://meinenigma.com/keychart.php
http://enigma.louisedade.co.uk/dailykeys.html
Reply
#57
(Dec-04-2017, 01:49 AM)Larz60+ Wrote: Hate to say I'm still working on this, but I am, at least I haven't given up, nor will I.

Hey again! I have to thank you a lot for sticking so much to this project!! It will serve me to be a great source of inspiration which I am looking very forward to!

You do not have to stress for the time, as long as the program gets done sometime, I'll be happy (which I am very laready)! :D Just tell me, just in case something else come through, when you will give up (which I don't think you would) and stop thi project.

And don't worry for commandeering around this proect, becasue what you have done so far, isn't even close to in reach for my skills at the moment. I can understand the code, and will only be able to copy the structure for the future!

Thank you a lot!!
Reply
#58
you will get the engine very soon. there is a gui for plugboard which you can incorporate into your own
gui, it is a class, and all  you have to do to use it is instantiate the class, passing it the parent window. When done
setting plugs, the pairs will be in an array which can be acessed by classname.plugboard_pairs

The PlugBoard.py class is up to date on GitHub. I don't plan on changing it anymore, so you can start to use it
if you wish.
Reply
#59
Here is a copy of Daniel Palloks browser enigma simulator that I converted to english
(download and double click to activate)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Enigma I / M3 - Simulator by dp</title>
<meta name="author" content="Daniel Palloks">
<meta name="version" content="v1.6 (30 Oct 2011)">
<meta name="generator" content="Notepad2">
<meta name="description" content="Enigma-Simulator in Javascript">
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

<script type="text/javascript">

// Enigmas I & M3: Roters I-VIII; Reversing Rollers A, B, C; ETW(I)

// === Variablendeklarationen ===
// --- Feste Werte ---
var abc       = 'abcdefghijklmnopqrstuvwxyz'; // geordnetes Alphabet

var walzeI    = 'ekmflgdqvzntowyhxuspaibrcj'; // Walze I (Rotor)
var walzeII   = 'ajdksiruxblhwtmcqgznpyfvoe'; // Walze II (Rotor)
var walzeIII  = 'bdfhjlcprtxvznyeiwgakmusqo'; // Walze III (Rotor)
var walzeIV   = 'esovpzjayquirhxlnftgkdcmwb'; // Walze IV (Rotor)
var walzeV    = 'vzbrgityupsdnhlxawmjqofeck'; // Walze V (Rotor)
var walzeVI   = 'jpgvoumfyqbenhzrdkasxlictw'; // Walze VI (Rotor) 
var walzeVII  = 'nzjhgrcxmyswboufaivlpekqdt'; // Walze VII (Rotor)
var walzeVIII = 'fkqhtlxocbjspdzramewniuygv'; // Walze VIII (Rotor)
var ukb       = 'yruhqsldpxngokmiebfzcwvjat'; // Umkehrwalze B (fest)
var ukc       = 'fvpjiaoyedrzxwgctkuqsbnmhl'; // Umkehrwalze C (fest)
var uka       = 'ejmzalyxvbwfcrquontspikhgd'; // Umkehrwalze A (fest)
var et0  = abc; // Eintrittswalze (fest, keine Permutation)

var notch = 'rfwkaaaa'; // Übertragskerben f. Weiterdrehung d. nächsten Walze
var winfo = new Array ('Übertrag: ',
  'Q|R','E|F','V|W','J|K','Z|A','Z|A, M|N','Z|A, M|N','Z|A, M|N');
var wname = new Array ('I','II','III','IV','V','VI','VII','VIII');
var oldqwertz = 'QWERTZUIOASDFGHJKPYXCVBNML'; // Enigma-Tastatur
// --- Ende feste Werte ---

// -- Auswahl + Defaults --
var ukw = ukb, etw = et0; // Auswahl UKW, ETW

var walz01 = walzeI, walz02 = walzeII, walz03 = walzeIII; // 3 ausgewählte Walzen von 8: walz01: rechte (schnelle), walz02: mittlere, walz03: linke (Grundstellung, f. Reset)
var walz1 = walz01, walz2 = walz02, walz3 = walz03; // innere Verdrahtung (f. Ringeinst.)
var wlz1 = walz1, wlz2 = walz2, wlz3 = walz3; // 3 Walzen zum Stellen (Startwerte)
 
var n1 = abc.indexOf(notch.charAt(0)), n2 = abc.indexOf(notch.charAt(1)); // Kerben der zwei rechten gewählten Rotoren
var n11 = n1, n21 = n2; // Zweite Kerbe (gleich erste K. gesetzt)

var w1set = 65, w2set = 65, w3set = 65; // Walzenstellung 'A' (real)
var w1out = 65, w2out = 65, w3out = 65; // Walzenstellung 'A' (angezeigt)
var r1set = 0, r2set = 0, r3set = 0; // Ringstellung '1'
var kcheck = ''; // Steckerpaare

var swp = abc, gesteckert = false; // Steckerkonfiguration
var ringst = false; // Modus 'Ringstellung' aus
var qwertzu = false; // QWERTZU-Tastatur aus
var monitor = false; 

// - Initialisierung dynamische Werte -
var w1 = wlz1, w2 = wlz2, w3 = wlz3; // Momentaufnahme der rotierten Walzen
var lastkey = -1; // f. QWERTZ-Anzeige
var coded = 0; // Anzahl kodierter Zeichen
var reset1 = true, reset2 = true, reset3 = true; // f. input box-Rolling lock, s. set()

// === Ende Variablendeklarationen ===


// ====== Funktionen ======

function info() {
  alert('\tEnigma I & M3 Emulator '+document.getElementsByName("version")[0].content+'\n\t(c) 2007-2011 Daniel Palloks\n\nInfos: http:\/\/people.physik.hu-berlin.de\/~palloks\/js\/enigma\/\n\nDas Programm ist Freeware und darf nach Belieben weitergegeben und verändert werden, solange (1) meine Urheberschaft anerkannt bleibt, (2) alle Änderungen entsprechend gekennzeichnet werden, (3) der Freeware-Status und die Bedingungen für Weitergabe/Änderungen gewahrt bleiben. Dies gilt auch für Teile des Quelltextes, sofern sie an anderer Stelle verwendet werden. Bei der Weitergabe der Software muß auch eine Kopie dieser Bestimmungen weitergegeben werden. -- Der Autor haftet nicht für Schäden, die mittelbar oder unmittelbar durch die Benutzung der Software entstehen.');
}

function neu() {
// Wenn Reload-Button d. Browsers betätigt...
  document.f.reset(); //leert Formular m. Walzeneinstellungen + Walzenauswahl
  wlzReset(); rngReset();
  unsteck(); //Stecker bleiben, müssen aber neu aktiviert werden
}


function wlzReset() {
  wlz1 = walz1; wlz2 = walz2; wlz3 = walz3; //könnte noch Ringstellg. haben!
  w1 = wlz1; w2 = wlz2; w3 = wlz3;
  w1set = w2set = w3set = 65; // wenn weg --> Reset auf letzte man. Walzenstellg.!
  w1out = w2out = w3out = 65; 
  reset1 = reset2 = reset3 = true;
  document.f.w1.value = String.fromCharCode(w1set);
  document.f.w2.value = String.fromCharCode(w2set);
  document.f.w3.value = String.fromCharCode(w3set);
  wlzAktuellShow(); viewKey();
}

function rngReset() {
  walz1 = rot(walz1,r1set); walz2 = rot(walz2,r2set); walz3 = rot(walz3,r3set); //innere Verdrathg. zurückdrehen
  wlz1 = rot(wlz1,r1set); wlz2 = rot(wlz2,r2set); wlz3 = rot(wlz3,r3set); //Var. synchronisieren
  r1set = r2set = r3set = 0;
  document.f.r1.value = String(r1set +1);
  document.f.r2.value = String(r2set +1);
  document.f.r3.value = String(r3set +1);
  wlzStellShow(); viewKey();
}

function steckReset () {
  stbMark() // nur Effekt
  swp = abc; kcheck= '';
  for (var i=0; i<13; i++) 
    document.getElementsByName('stf')[i].value= '';
  setTimeout('steck()',150);
}

function unsteck() {
  swp = abc; kcheck= ''; stecker = false; viewKey(); // Stecker deaktivieren (nicht löschen)
  document.getElementById("stb").value = ' Activate ';
  for (var i=0; i<13; i++) { //Stecker vorhanden? Eingabeknopf markieren
    if (document.s.stf[i].value != '') { stbMark(); break }
  }
}


function wlzAktuellShow () {
  document.getElementById('walzen').innerHTML= wlz3+' &nbsp; &nbsp; '+wlz2+' &nbsp; &nbsp; '+wlz1+'<br>'+w3+' &nbsp; &nbsp; '+w2+' &nbsp; &nbsp; '+w1;
}

function wlzStellShow () {
  document.getElementById('walzen').innerHTML= walz3+' &nbsp; &nbsp; '+walz2+' &nbsp; &nbsp; '+walz1+'<br>'+wlz3+' &nbsp; &nbsp; '+wlz2+' &nbsp; &nbsp; '+wlz1;
}


function w3sel (sel) { 
  w3set = w3out = 65; document.f.w3.value="A";
  r3set = 0; document.f.r3.value="1";
  wlz3 = walz3 = walz03 = wselect(sel); //w3 = wlz3;
  reset3 = true;
  document.getElementById('rng3').innerHTML= wname[sel-1];
  wlzStellShow (); viewKey();
}

function w2sel (sel) {
  w2set = w2out = 65; document.f.w2.value="A";
  r2set = 0; document.f.r2.value="1";
  wlz2 = walz2 = walz02 = wselect(sel); //w2 = wlz2;
  n2 = abc.indexOf(notch.charAt(parseInt(sel-1))); // passende Kerbe zuordnen!
  n21 = (sel > 5)? abc.indexOf('n') : n2; // VI-VIII haben Kerben bei M|N und Z|A!
  reset2 = true;
  document.getElementById('rng2').innerHTML= wname[sel-1];
  wlzStellShow (); viewKey();
}

function w1sel (sel) { 
  w1set = w1out = 65; document.f.w1.value="A";
  r1set = 0; document.f.r1.value="1";
  wlz1 = walz1 = walz01 = wselect(sel); //w1 = wlz1;
  n1 = abc.indexOf(notch.charAt(parseInt(sel-1)));
  n11 = (sel > 5)? abc.indexOf('n') : n1;
  reset1 = true;
  document.getElementById('rng1').innerHTML= wname[sel-1];
  wlzStellShow (); viewKey();
}


function wselect (sel) {
  var w;
  switch(sel) {
    case "1": w = walzeI; break;
    case "2": w = walzeII; break;
    case "3": w = walzeIII; break;
    case "4": w = walzeIV; break;
    case "5": w = walzeV; break;
    case "6": w = walzeVI; break;
    case "7": w = walzeVII; break;
    case "8": w = walzeVIII; break;
  }
  return w;
}


function ukwlz(sel) {
  switch(sel) {
    case "A": ukw = uka; 
      document.getElementById("ukw").style.color= "#000";
      document.getElementById("ukw").style.backgroundColor= "#c0c0c0";
      break;
    case "B": ukw = ukb;
      document.getElementById("ukw").style.color= "blue";
      document.getElementById("ukw").style.backgroundColor= "#c0c0c0";
      break;
    case "C": ukw = ukc;
      document.getElementById("ukw").style.color= "blue";
      document.getElementById("ukw").style.backgroundColor= "#fff";
      break;
  }
  viewKey();
}


function set(s) {
  if (document.f.inp.value != '' && !(reset1 && reset2 && reset3)) return 0; // gesperrt
  var n = s.charCodeAt(0);
  if (n==43) return 1;
  if (n==45) return -1;
  if (n < 65 || n > 90 || s=='') return 0;
  return n;
}

function setr(s) {
  var n=0;
  if (!(isNaN(s))) {
    n = parseInt(s) +1; // Abgrenzen v. '+'-Taste mit Wert 1 (später wieder rückrechnen!)
    if (n==1) n=2; // Eingabe Null gleich Eingabe Eins (wird also hier 2)
    else if (n < 1 || n > 27 || s=='') n= 0;
  }
  return n;
}


function set3(n) {
  if (n==0) {
    if (ringst) document.f.r3.value = r3set +1;
    else document.f.w3.value = String.fromCharCode(w3out);
    return;
  }
  if (ringst) { 
    if (n > 1 && n < 28) n -= r3set +2; // n aus rset() war ggü. r3set um 2 erhöht!
    r3set = (r3set + n) % 26; if (r3set < 0) r3set= 26 + n; 
    document.f.r3.value = String(r3set + 1);
    walz3 = rot(walz3,-n); wlz3 =rot(wlz3,-n);
  }
  else {
    if (n > 64 && n < 91) n -= w3out; // Abstand neuer-alter Wert
    w3set = 65 + (w3set - 65 + n) % 26; if (w3set< 65) w3set= 91 + n;
    w3out = 65 + (w3out - 65 + n) % 26; if (w3out< 65) w3out= 91 + n;
    document.f.w3.value = String.fromCharCode(w3out);
    wlz3 = rot(wlz3,n);
  }
  document.getElementById('walzen').innerHTML= '<b>'+walz3+'<\/b> &nbsp; &nbsp; '+walz2+' &nbsp; &nbsp; '+walz1+'<br><b>'+wlz3+'<\/b> &nbsp; &nbsp; '+wlz2+' &nbsp; &nbsp; '+wlz1;
  document.getElementById('status2').innerHTML= w3set-65 +'-' +r3set;
  viewKey();
}


function set2(n) {
  if (n==0) {
    if (ringst) document.f.r2.value = r2set +1;
    else document.f.w2.value = String.fromCharCode(w2out);
    return;
  }
  if (ringst) { 
    if (n > 1 && n < 28) n -= r2set +2;
    r2set = (r2set + n) % 26; if (r2set < 0) r2set= 26 + n; 
    document.f.r2.value = String(r2set + 1);
    walz2 = rot(walz2,-n); wlz2 =rot(wlz2,-n);
  }
  else {
    if (n > 64 && n < 91) n -= w2out;
    w2set = 65 + (w2set - 65 + n) % 26; if (w2set< 65) w2set= 91 + n;
    w2out = 65 + (w2out - 65 + n) % 26; if (w2out< 65) w2out= 91 + n;
    document.f.w2.value = String.fromCharCode(w2out);
    wlz2 = rot(wlz2,n);
  }
  document.getElementById('walzen').innerHTML= walz3+' &nbsp; &nbsp; <b>'+walz2+'<\/b> &nbsp; &nbsp; '+walz1+'<br>'+wlz3+' &nbsp; &nbsp; <b>'+wlz2+'<\/b> &nbsp; &nbsp; '+wlz1;
  document.getElementById('status2').innerHTML= w2set-65 +'-' +r2set;
  viewKey();
}


function set1(n) {
  if (n==0) {
    if (ringst) document.f.r1.value = r1set +1;
    else document.f.w1.value = String.fromCharCode(w1out);
    return;
  }
  if (ringst) { 
    if (n > 1 && n < 28) n -= r1set +2;
    r1set = (r1set + n) % 26; if (r1set < 0) r1set= 26 + n; 
    document.f.r1.value = String(r1set + 1);
    walz1 = rot(walz1,-n); wlz1 =rot(wlz1,-n);
  }
  else {
    if (n > 64 && n < 91) n -= w1out;
    w1set = 65 + (w1set -65 + n) % 26; if (w1set< 65) w1set= 91 + n;
    w1out = 65 + (w1out -65 + n) % 26; if (w1out< 65) w1out= 91 + n;
    document.f.w1.value = String.fromCharCode(w1out);
    wlz1 = rot(wlz1,n);
  }
  document.getElementById('walzen').innerHTML= walz3+' &nbsp; &nbsp; '+walz2+' &nbsp; &nbsp; <b>'+walz1+'<\/b><br>'+wlz3+' &nbsp; &nbsp; '+wlz2+' &nbsp; &nbsp; <b>'+wlz1+'<\/b>';
  document.getElementById('status2').innerHTML= w1set-65 +'-' +r1set;
  viewKey();
}


function switchWlzSettings (sw) {
  if (sw == false) {
    ringst = true; 
    document.getElementById("walz").style.display= "none";
    document.getElementById("rngst").style.display= "";
    wlzStellShow();
  }
  else {
    ringst = false;
    document.getElementById("rngst").style.display= "none";
    document.getElementById("walz").style.display= "";
    wlzAktuellShow();
  }
}


function walzenrot () {
  if (document.f.rotieren.checked == true)
    document.getElementById("walzenrot").innerHTML= 'Walzen rotieren';
  else
    document.getElementById("walzenrot").innerHTML= '<span style=background-color:#c33>&nbsp;Walzen fixiert!&nbsp;<\/span>';
}


function steck () {
  var stest0, stest1, k0, k1; 
  kcheck= ''; 
  swp = abc;
  for (var i=0; i<13; i++) {
    stest0 = document.getElementsByName('stf')[i].value.charAt(0).toLowerCase(); 
    stest1 = document.getElementsByName('stf')[i].value.charAt(1).toLowerCase();
    if (stest1 == stest0) { document.getElementsByName('stf')[i].value= ''; stest0 = stest1 = '' }
    // Validieren... 
    if (stest0 != '') {
      if ((stest0.charCodeAt(0) < 97 || stest0.charCodeAt(0) > 122) || (stest1.charCodeAt(0) < 97 || stest1.charCodeAt(0) > 122) || stest1 == '') { 
        alert('Fehler! (Feld '+String(i+1)+')'); kcheck=''; return(false); }
      // Validieren2: Doppelgänger suchen...
      if (kcheck.lastIndexOf(stest0) >= 0 || kcheck.lastIndexOf(stest1) >= 0 ) {
        alert('Fehler! Doppelter Wert (Feld '+String(i+1)+').'); kcheck=''; return(false); }
      else {
        kcheck = stest0 + stest1 + kcheck;
        // Swap-String bauen (m. Ersetzen-Fkt. srepl())...
        k0 = abc.indexOf(stest0), k1 = abc.indexOf(stest1);
        swp = srepl(swp,k0,stest1);
        swp = srepl(swp,k1,stest0);
      }//-if !=''
    } //-for
  }
  if (swp != abc) {
    gesteckert = true;
    document.getElementById("stb").value = ' Deactivate '; // Knopf umschalten
  }
  document.getElementById("stb").style.fontWeight = 'normal'; // Knopf zurücksetzen
  document.getElementById("stb").style.color = '#000';
  viewKey();
}


function srepl (s, nr, c) {
  if (nr==0) s = c + s.substring(1);
  else s = s.substring(0, nr) + c + s.substring(nr + 1);
  return(s);
}

function stbMark() {
  var s= document.getElementById("stb");
  s.value= ' Activate '; s.style.fontWeight= 'bold'; s.style.color= '#a52a2a';
}


function fadeSt () {
  if (document.k.stl.value=="Plug connector off") {
    document.getElementById('stecker').style.display= "none";
    document.k.stl.value= "Plug connector On";
  }
  else { 
  document.getElementById('stecker').style.display= "";
  document.k.stl.value= "Plug connector off";
  }
}


function fadeInp() { // --> TXT
  document.f.out.value= ''; document.f.inp.value= ''; coded = 0;
  if (qwertzu) { // --> TXT
    qwertzu = false;
    document.getElementById("qwertzu").style.display = "none";
    document.getElementById("txtfeld").style.display = "";
    document.k.qw.value= "QWERTZU-Tastatur";
    if (ringst) { ringst = false; var t = true } // folgende Zeile nur für Walzenpos.
    set1(w1set); set2(w2set); set3(w3set); // Zurück auf letzte man. Einstellung
    if (t) ringst = true; // Änderung aus vorletzter Zeile rückgängig machen
  }
  else { // --> QWERTZU
    qwertzu = true;
    document.getElementById("txtfeld").style.display= "none";
    document.getElementById("qwertzu").style.display= "";
    document.k.qw.value= "input box ";
    if (lastkey > -1) document.getElementsByName('kqw')[lastkey].style.color= 'gray';
    enigma(' '); // Zurück auf letzte man. Einstellung
  }
  w1set = w1out; w2set = w2out; w3set = w3out; 
  viewKey();
}


function fade () { 
  if (document.k.knopf.value==" Monitor aus ") {
    document.getElementById('monitor').style.display= "none";
    document.k.knopf.value= " Monitor ein ";
    monitor = false;
  }
  else {
  document.getElementById('monitor').style.display= "";
  document.k.knopf.value= " Monitor ";
  monitor = true;
  }
}


function ttw(s) {
  if (ringst) return ( '"' +abc.charAt(Number(s.toLowerCase()) -1).toUpperCase() +'"' );
  else return ( '"' +String(abc.indexOf(s.toLowerCase()) +1) +'"' );
}

function tts(s) {
  var s0= s.charAt(0), s1= s.charAt(1), n0= s0.charCodeAt(0), n1= s1.charCodeAt(0);
  if (s!='' && n0 > 64 && n0 < 91 && n1 > 64 && n1 < 91) return ( '"' +String(abc.indexOf(s0.toLowerCase()) +1) +'/' +String(abc.indexOf(s1.toLowerCase()) +1) +'"' );
  else return ('');
}


function viewKey() {
  var rg1=String(r1set +1), rg2=String(r2set +1), rg3=String(r3set +1);
  rg1= (rg1.length==2)? rg1 : '0'+rg1;
  rg2= (rg2.length==2)? rg2 : '0'+rg2;
  rg3= (rg3.length==2)? rg3 : '0'+rg3;
  if (qwertzu) { 
    w1set = w1out; w2set = w2out; w3set = w3out; // Im QWERTZU-Modus nach Walzenstellen: Startpos. auf aktuelle Werte
  }
  var wg = new Array ( String.fromCharCode(w3set), String.fromCharCode(w2set), String.fromCharCode(w1set) );
  if (kcheck=='') kcheck = ' - -';
  var k='Reflector: ';
  k += (ukw == ukb)? 'B. ' : (ukw == ukc)? 'C. ' : 'A. ';
  k+= document.getElementById("rng3").innerHTML +' '+ document.getElementById("rng2").innerHTML +' '+ document.getElementById("rng1").innerHTML +'&nbsp; (' +wg +') &nbsp; ';
  k+= 'ring position: '+rg3+' '+rg2+' '+rg1+' &nbsp; ';
  k+= 'Plugboard:';
  for (var i=kcheck.length -2; i > -1; i-=2) {
    if (kcheck.charAt(i) != kcheck.charAt(i+1)) k+= ' ' + kcheck.substr(i,2).toUpperCase();
  }
  document.getElementById('key1').innerHTML=k;
}



// ---- MAIN LOOP (input box) ----

function enigma(s) {
  // berechnet immer gesamten Text im Fenster!

  if (monitor) {
    document.getElementById('status0').innerHTML= '<font color=#cc3333>In Arbeit...<\/font>';
    if (s.length > 999) {
      var c= confirm('Achtung: Langer Eingabetext!\nDas Deaktivieren des Statusmonitors kann den Vorgang erheblich beschleunigen.\n\'OK\', um trotzdem fortzufahren (Fenster schließt u.U. nicht sofort).');
      if (c==false) { document.getElementById('status0').innerHTML= '<font color=#cc3333>Abbruch!<\/font>'; return ''; }
    }
  }

  var startzeit = new Date();

  document.getElementById('signal').innerHTML = ''; 
  w1out = w1set, w2out = w2set, w3out = w3set; // eingestellte Walzenpos. u. -anzeige
  w1 = wlz1; w2 = wlz2; w3 = wlz3;
  coded = 0;
  var out = '';
  // ... Walzen + Output zurücksetzen, da jedesmal String von Anfang an kodiert wird!

  for (var i=0; i < s.length; i++) {

    if (s.charCodeAt(i) > 96 && s.charCodeAt(i) < 123) {

      reset1 = false; reset2 = false; reset3 = false;

      if (document.f.rotieren.checked == true) gear(); //Walzenvortrieb
      out = out + kodieren(s.charAt(i));
      if ((coded+1) % 5 ==0) out += ' ';
      coded++;

    }

    if (monitor)
      document.getElementById('status1').innerHTML = s.charCodeAt(i);

  } //-for

  document.f.w3.value = String.fromCharCode(w3out);
  document.f.w2.value = String.fromCharCode(w2out);
  document.f.w1.value = String.fromCharCode(w1out);

  wlzAktuellShow();
  document.getElementById('status0').innerHTML = '( OK )';
  document.getElementById('status3').innerHTML = coded;

  var endzeit = new Date();
  var zeit = endzeit.getTime() - startzeit.getTime();
  document.getElementById('time').innerHTML = zeit/1000 + ' s';
  return(out);

}
// ---- End main loop ----


function en2(s) { // QWERTZU Main Loop (text input)...

  document.getElementById('status0').innerHTML= '<font color=#cc3333>In Arbeit...<\/font>';
  if (s.length > 1) var start = new Date();
  var l = document.f.out.value.length;

  for (var i=0; i < s.length; i++) {
    if (lastkey > -1) document.getElementsByName('kqw')[lastkey].style.color= 'gray';
    var e = en(s.charAt(i).toLowerCase()).toUpperCase(); 
    if (e != '') { 
      var taste = oldqwertz.indexOf(e);
      document.getElementsByName('kqw')[taste].style.color = '#cc0';
      lastkey = taste;
      l++;
      document.f.out.value += e;
      if ((l+1) % 6 == 0) { document.f.out.value += ' '; l++ }
    }
  }
  document.f.inpqw.value = '';
  document.getElementById('status0').innerHTML= '( OK )';

  if (s.length > 1) {
    var ende = new Date();
    var zeit = ende.getTime() - start.getTime();
    document.getElementById('time').innerHTML = zeit/1000 +' s';
  }

}


function en(s) { // QWERTZU Main Loop...

  document.getElementById('time').innerHTML= '';
  w1 = wlz1; w2 = wlz2; w3 = wlz3; 

  if (monitor) 
    document.getElementById('status1').innerHTML = s.charCodeAt(0); 

  if (s.charCodeAt(0) > 96 && s.charCodeAt(0) < 123) {

    if (document.f.rotieren.checked == true) gear(); // Walzenvortrieb
    var out = kodieren(s.charAt(0));
    
    wlz1 = w1; wlz2 = w2; wlz3 = w3; // ... soll ja immer weitergehen
    coded++;

    if (monitor) 
      document.getElementById('walzen').innerHTML= walz3+' &nbsp; &nbsp; '+walz2+' &nbsp; &nbsp; '+walz1+'<br>'+w3+' &nbsp; &nbsp; '+w2+' &nbsp; &nbsp; '+w1;

    document.f.w3.value = String.fromCharCode(w3out);
    document.f.w2.value = String.fromCharCode(w2out);
    document.f.w1.value = String.fromCharCode(w1out);

    document.getElementById('status1').innerHTML = s.charCodeAt(0);
    document.getElementById('status3').innerHTML = coded;

    return out;

  } //-validate charCode

  else return '';
}



// Walzenvortrieb
function gear() {

  w1 = rot(w1,1); 
  w1out++; if (w1out > 90) w1out= 65; // Anzeige Walze 1
  var w1c0 = w1.charAt(0);

  if ( w2.charAt(1) == walz2.charAt(n2) || w2.charAt(1) == walz2.charAt(n21) ) { //Übertrag 2-3 m. Doppelschritt od. bei Spezialfall (hat Priorität)
    w2 = rot(w2,1); 
    w3 = rot(w3,1);
    w2out++; if (w2out > 90) w2out= 65; 
    w3out++; if (w3out > 90) w3out= 65;
  }
  else if (w1c0 == walz1.charAt(n1) || w1c0 == walz1.charAt(n11)) { // Übertrag 1-2
    w2 = rot(w2,1); 
    w2out++; if (w2out > 90) w2out= 65; 
  }
}


// HIER passiert das Wesentliche!
function kodieren(s) { 

    // eff. Rotationsstellg.: Abstand Walzenpos. von Grundpos. der Verdrahtung 
    // d.h. <Abst. Walzenpos. v. Grundpos.> - <Abst. Verdrahtg. v. ihrer Grundpos.>
    var rw1 = w1out - 65 - r1set; if (rw1 < 0) rw1 += 26;
    var rw2 = w2out - 65 - r2set; if (rw2 < 0) rw2 += 26;
    var rw3 = w3out - 65 - r3set; if (rw3 < 0) rw3 += 26;
    if (monitor)
      document.getElementById('status2').innerHTML= rw3+'  '+rw2+'  '+rw1;

    var s0 = (gesteckert)? swp.charAt(abc.indexOf(s)) : s; // Stecker am Eingang?

    var se = etw.charAt(abc.indexOf(s0)); //=s0;
    var s1 = w1.charAt(abc.indexOf(se));  // (ETW ist fest)
    var s2 = w2.charAt( (abc.indexOf(s1) - rw1 + 26) % 26 );
    var s3 = w3.charAt( (abc.indexOf(s2) - rw2 + 26) % 26 );
    var su = ukw.charAt( (abc.indexOf(s3) - rw3 + 26) % 26 );
      var t = '<code>UKW &nbsp;W.3 &nbsp; W.2 &nbsp; W.1 &nbsp; ETW &nbsp; STK<br>';
      t+=' ┌- '+s3+' &lt;-- '+s2+' &lt;-- '+s1+' &lt;-- '+se+' &lt;-- '+s0+' &lt;-- '+s+' (REIN)<br> └&gt; '+su; 
    s3 = abc.charAt( w3.indexOf(abc.charAt((abc.indexOf(su) +rw3) % 26)) ); 
    s2 = abc.charAt( w2.indexOf(abc.charAt((abc.indexOf(s3) +rw2) % 26)) );
    s1 = abc.charAt( w1.indexOf(abc.charAt((abc.indexOf(s2) +rw1) % 26)) );
    se = abc.charAt( etw.indexOf(s1) ); // = s1; 

    s0 = (gesteckert)? swp.charAt(abc.indexOf(se)) : se; // Stecker am Ausgang?

      t= t+' --&gt; '+s3+' --&gt; '+s2+' --&gt; '+s1+' --&gt; '+se+' --&gt; '+s0+' (RAUS)<\/code>'
    if (monitor) document.getElementById('signal').innerHTML= t;
    return s0;
}


function rot (w,n) { 
  return (n>0)? w.substr(n)+ w.substr(0,n) : w.substr(w.length +n) + w.substring(0, w.length +n);
}

</script>



<style type="text/css">
h3, form { margin-bottom: 0 }
.rubrik { border:solid 1px #b9b8b6; background-color:#000; color:#fff; padding:5px; height:30px; text-align:center }
.wlzbk { width:180px; border:solid 1px #b9b8b6; background-color:#c93; padding:5px }
.wbk { background-color:#c0c0c0; text-align:center }
.k a, .k a:visited { color:gray; font-weight:bold; text-decoration:none }
.k a:hover { color:silver }
.k a:active { font-size:12px; letter-spacing:2px }
.i a, .i a:visited { color:yellow; text-decoration:none }
.i a:hover { background-color:#333 }
</style>
<!--[if IE]><style type="text/css">h3 { margin: .2em 0 .5em }</style><![endif]-->

</head>


<!-- ====================================== -->


<body onload="neu()">

<div align="center">
<noscript><h3 style="color:#a52a2a">Please activate Javascript!</h3></noscript>

<table style="width:830px; border:solid 1px #000; padding:10px; background-color:#c93; background-image:url(enigma_logo_90px.gif); background-repeat:no-repeat; background-position: top center">
<tr><td colspan="5" style="text-align:center"><h3>&nbsp; &nbsp; &nbsp; Simulation of &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Enigma <span style="background-color:#c0c0c0;border:1px solid #000">&nbsp;I&nbsp;</span><small> &amp;</small> <span style="border:1px solid #000; color:blue"><span style="background-color:#c0c0c0">&nbsp;M</span><span style="background-color:#fff">3&nbsp;</span></span></h3></td></tr>

<tr><td>
<form name="f" action="">

<table width="100%" border="0">
<tr><td id="key1" colspan="5" style="height:25px; background-color:#c33; font-family:monospace; font-size:12px; border:solid 1px #000; text-align:center">&nbsp;</td></tr>
<tr><td class="rubrik" style="width:300px">I n p u t</td>
<td  class="rubrik" style="width:180px">R o l l e r s</td>
<td  class="rubrik" style="width:300px">O u t p u t</td>
</tr>
<tr><td id="txtfeld">
<textarea name="inp" title="Zum Einfügen Strg+V benutzen" rows="10" cols="35" style="border:solid 1px #b9b8b6; padding:5px; width:300px; height:180px; " onKeyUp="this.form.out.value=enigma(this.value.toLowerCase())" onDblClick="this.select()"></textarea></td>
<td id="qwertzu" style="display:none">

<!--   QWERTZU-Feld   -->

<div class="k" style="width:300px; background-color:black; color:gray; font-family:Arial,sans-serif; font-size:16px"><div title="Virtuelle Tastatur" style="padding:20px; border:0px">
<a name="kqw" href="javascript:en2('Q')">&nbsp;Q&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('W')">&nbsp;W&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('E')">&nbsp;E&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('R')">&nbsp;R&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('T')">&nbsp;T&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('Z')">&nbsp;Z&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('U')">&nbsp;U&nbsp;</a>
<a name="kqw" href="javascript:en2('I')">&nbsp; I &nbsp;</a>
<a name="kqw" href="javascript:en2('O')">&nbsp;O&nbsp;</a><br><br>&nbsp;&nbsp;&nbsp;
<a name="kqw" href="javascript:en2('A')">&nbsp;A&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('S')">&nbsp;S&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('D')">&nbsp;D&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('F')">&nbsp;F&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('G')">&nbsp;G&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('H')">&nbsp;H&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('J')">&nbsp;J &nbsp;</a>
<a name="kqw" href="javascript:en2('K')">&nbsp;K&nbsp;</a><br><br>&nbsp;
<a name="kqw" href="javascript:en2('P')">&nbsp;P&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('Y')">&nbsp;Y&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('X')">&nbsp;X&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('C')">&nbsp;C&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('V')">&nbsp;V&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('B')">&nbsp;B&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('N')">&nbsp;N&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('M')">&nbsp;M&nbsp;</a>&nbsp;
<a name="kqw" href="javascript:en2('L')">&nbsp;L&nbsp;</a><br><br>
<span style="font-size:0.8em; color:#a52a2a; text-align:right">Click on buttons or enter here: <input type="text" name="inpqw" title="Einfügen mit Strg+V" size="1" style="text-align:center" onKeyUp="var s=this.value; this.value=''; en2(s);"></span>
</div></div></td>

<!-- Ende QWERTZU -->

<td id="walz">
  <table class="wlzbk">
    <tr><td colspan="3" align="center"> [ <select id="ukw" size="1" style="text-align:center;font-family:serif;font-size:12px;background-color:#c0c0c0;color:blue" onChange="ukwlz(this.value)">
       <option value="A">UKW: A</option>
       <option selected value="B">UKW: B</option>
       <option value="C">UKW: C</option>
       </select> ] </td>
    </tr>
    <tr><td class="wbk"><select name="s3" onMouseOver="this.title= winfo[0]+winfo[this.value]" size="1" style="text-align:center;font-family:serif;font-size:12px;color:blue;background-color:#c0c0c0" onChange="{this.style.backgroundColor=(Number(this.value)>5)?'#fff':'#c0c0c0'; w3sel(this.value)}">
       <option value="1" onMouseOver="this.title=winfo[0]+winfo[1]">I</option>
       <option value="2" onMouseOver="this.title=winfo[0]+winfo[2]">II</option>
       <option selected value="3" onMouseOver="this.title=winfo[0]+winfo[3]">III</option>
       <option value="4" onMouseOver="this.title=winfo[0]+winfo[4]">IV</option>
       <option value="5" onMouseOver="this.title=winfo[0]+winfo[5]">V</option>
       <option value="6" onMouseOver="this.title=winfo[0]+winfo[6]">VI</option>
       <option value="7" onMouseOver="this.title=winfo[0]+winfo[7]">VII</option>
       <option value="8" onMouseOver="this.title=winfo[0]+winfo[8]">VIII</option>
      </select><br>
    <input type="button" value=" - " onClick="set3(set('-'))"><br><input type="text" name="w3" size="1" maxlength="1" value="A" style="text-align:center" onClick="this.select()" onKeyUp="this.value=this.value.toUpperCase(); set3(set(this.value))" onMouseOver="this.title=ttw(this.value)"><br><input type="button" value=" + " onClick="set3(set('+'))"></td>
    <td class="wbk"><select name="s2" onMouseOver="this.title= winfo[0]+winfo[this.value]" size="1" style="text-align:center;font-family:serif;font-size:12px;color:blue;background-color:#c0c0c0" onChange="{this.style.backgroundColor=(Number(this.value)>5)?'#fff':'#c0c0c0'; w2sel(this.value)}">
       <option value="1" onMouseOver="this.title=winfo[0]+winfo[1]">I</option>
       <option selected value="2" onMouseOver="this.title=winfo[0]+winfo[2]">II</option>
       <option value="3" onMouseOver="this.title=winfo[0]+winfo[3]">III</option>
       <option value="4" onMouseOver="this.title=winfo[0]+winfo[4]">IV</option>
       <option value="5" onMouseOver="this.title=winfo[0]+winfo[5]">V</option>
       <option value="6" onMouseOver="this.title=winfo[0]+winfo[6]">VI</option>
       <option value="7" onMouseOver="this.title=winfo[0]+winfo[7]">VII</option>
       <option value="8" onMouseOver="this.title=winfo[0]+winfo[8]">VIII</option>
      </select><br>
    <input type="button" value=" - " onClick="set2(set('-'))"><br><input type="text" name="w2" size="1" maxlength="1" value="A" style="text-align:center" onClick="this.select()" onKeyUp="this.value=this.value.toUpperCase(); set2(set(this.value))" onMouseOver="this.title=ttw(this.value)"><br><input type="button" value=" + " onClick="set2(set('+'))"></td>
    <td class="wbk"><select name="s1" onMouseOver="this.title= winfo[0]+winfo[this.value]" size="1" style="text-align:center;font-family:serif;font-size:12px;color:blue;background-color:#c0c0c0" onChange="{this.style.backgroundColor=(Number(this.value)>5)?'#fff':'#c0c0c0'; w1sel(this.value)}">
       <option selected value="1" onMouseOver="this.title=winfo[0]+winfo[1]">I</option>
       <option value="2" onMouseOver="this.title=winfo[0]+winfo[2]">II</option>
       <option value="3" onMouseOver="this.title=winfo[0]+winfo[3]">III</option>
       <option value="4" onMouseOver="this.title=winfo[0]+winfo[4]">IV</option>
       <option value="5" onMouseOver="this.title=winfo[0]+winfo[5]">V</option>
       <option value="6" onMouseOver="this.title=winfo[0]+winfo[6]">VI</option>
       <option value="7" onMouseOver="this.title=winfo[0]+winfo[7]">VII</option>
       <option value="8" onMouseOver="this.title=winfo[0]+winfo[8]">VIII</option>
      </select><br>
    <input type="button" value=" - " onClick="set1(set('-'))"><br><input type="text" name="w1" size="1" maxlength="1" value="A" style="text-align:center" onClick="this.select()" onKeyUp="this.value=this.value.toUpperCase(); set1(set(this.value))" onMouseOver="this.title=ttw(this.value)"><br><input type="button" value=" + " onClick="set1(set('+'))"></td>
    </tr>
    <tr><td colspan="3" align="center"><input type="checkbox" name="rotieren" checked="checked" onClick="walzenrot()"> <span id="walzenrot">Rotate rollers</span> &nbsp;</td>
    <tr><td colspan="3" align="center"><input type="button" name="resetknopf" onClick="wlzReset()" value="&nbsp; NULL &nbsp;"> &nbsp; <input type="button" name="ringst" onClick="switchWlzSettings(false)" value="Rings &raquo;"></td>
    </tr>
  </table>
</td>

<!--  Ring settings  -->

<td id="rngst" style="display:none">
  <table class="wlzbk">
    <tr><td colspan="3" align="center" style="text-align:center"> R i n g   S e t t i n g s:</td>
    </tr>
    <tr><td align="center" class="wbk"><span id="rng3">III</span><br><input type="button" value=" - " onClick="set3(-1)"><br><input type="text" name="r3" size="2" maxlength="2" value="1" style="text-align:center" onClick="this.select()" onKeyUp="set3(setr(this.value))" onMouseOver="this.title=ttw(this.value)"><br><input type="button" value=" + " onClick="set3(1)"></td>
    <td  align="center" class="wbk"><span id="rng2">II</span><br><input type="button" value=" - " onClick="set2(-1)"><br><input type="text" name="r2" size="2" maxlength="2" value="1" style="text-align:center" onClick="this.select()" onKeyUp="set2(setr(this.value))" onMouseOver="this.title=ttw(this.value)"><br><input type="button" value=" + " onClick="set2(1)"></td>
    <td align="center" class="wbk"><span id="rng1">I</span><br><input type="button" value=" - " onClick="set1(-1)"><br><input type="text" name="r1" size="2" maxlength="2" value="1" style="text-align:center" onClick="this.select()" onKeyUp="set1(setr(this.value))" onMouseOver="this.title=ttw(this.value)"><br><input type="button" value=" + " onClick="set1(1)"></td>
    </tr>
    <tr><td colspan="3" align="center" ><input type="button" name="rreset" onClick="rngReset()" value=" Reset ring settings "></td></tr>
    <tr><td colspan="3" align="right"><input type="button" name="rueck" onClick="switchWlzSettings(true)" value=" &laquo; Roller Settings ">&nbsp;</td>
    </tr>
  </table>
</td>

<!-- End Ring settings -->

<td>
<textarea name="out" readonly="readonly" rows="10" cols="35" onMouseOver="this.title='Doppelklick: alles markieren';if (qwertzu) this.title+='. Zum Löschen Eingabemodus umschalten'" onDblClick="this.select()" style="border:solid 1px #b9b8b6;padding:5px;width:300px;height:180px"></textarea>
</td></tr>
</table>

</form>
</td></tr>

<tr><td align="center">
<form name="k" action="">
<div><input type="button" name="qw" title="Eingabemodus umschalten" onClick="fadeInp()" value="Qwertzu keys"> &nbsp; <input type="button" name="stl" onClick="fadeSt()" value="Plug connector"> &nbsp; <input type="button" name="knopf" onClick="fade()" value=" Monitor"> &nbsp; <input type="button" name="neuladen" onClick="window.location.href=window.location.href" value="Reset all"></div>
</form>
</td></tr>


<!-- Steckerleiste -->

<tr id="stecker" style="display:none"><td>
<form name="s" action="">

<table width="100%" border="0">
<tr><td colspan="3" class="rubrik" style="width:100%">C o n n e c t o r s t r i p &nbsp; ( e n  t e r &nbsp; p a i r s &nbsp; o f &nbsp; l e t t e r s &nbsp; t o &nbsp; b e &nbsp; e x c h a n g e d ! )</td>
</tr>
<tr><td>

<table style="width:100%; height:20px; border:solid 1px #b9b8b6;padding:0px; font-family:monospace; font-size:13px">
  <tr style="text-align:center">
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td>&nbsp;</td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}" onMouseOver="this.title=tts(this.value)"></td>
  <td>&nbsp;</td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" style="background-color:#f0f0f0" onMouseOver="this.title=tts(this.value)" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" style="background-color:#f0f0f0" onMouseOver="this.title=tts(this.value)" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}"></td>
  <td><input type="text" name="stf" size="2" maxlength="2" onClick="this.select()" style="background-color:#f0f0f0" onMouseOver="this.title=tts(this.value)" onKeyUp="{this.value=this.value.toUpperCase();stbMark()}"></td>
  </tr>
  <tr><td colspan="15" align="center"><input type="button" id="stb" value=" Activate " onClick="{if (this.value==' Activate ') steck(); else unsteck();}"> &nbsp; <input type="button" value=" Clear all " onClick="steckReset()">
  </td></tr>
</table>
</td></tr>
</table>

</form>
</td></tr>


<!-- Monitor -->

<tr id="monitor" style="display:none"><td>
<table style="width:100%; border:0px">
<tr><td class="rubrik" style="width:100%">M o n i t o r &nbsp; ( S i g n a l f l o w &nbsp;&amp; &nbsp;R o t o r  w i r i n g)</td>
</tr>
<tr><td>
<table style="width:100%; height:200px; border:solid 1px #b9b8b6;padding:0px; font-family:monospace; font-size:13px; background-color:#fff">
  <tr><td id="status0" style="width:29%; height:80px; text-align:center"></td>
  <td id="signal" style="width:44%"></td>
  <td id="time" style="width:27%; text-align:center"></td>
  </tr>
<tr><td colspan="3" valign="baseline" style="height:10px; text-align:center; text-decoration:underline; color:#b0b0b0">
  abcdefghijklmnopqrstuvwxyz &nbsp; &nbsp; abcdefghijklmnopqrstuvwxyz &nbsp; &nbsp; abcdefghijklmnopqrstuvwxyz</td>
  </tr>
  <tr><td id="walzen" colspan="3" align="center" valign="top"></td>
  </tr>
  <tr style="color:#b0b0b0; text-align:center"><td>last entry</td>
  <td>eff. Rotation (latest)</td>
  <td style="text-align:left">Coded characters</td>
  </tr>
  <tr><td id="status1" align="center">&nbsp;</td>
  <td id="status2" align="center">&nbsp;</td>
  <td id="status3" align="center">&nbsp;</td>
  </tr>
</table>
</td></tr>
</table>
</td></tr>

<!-- Fußzeile -->

<tr><td>
<table class="i" style="width:100%; border:0">
<tr><td class="rubrik" style="width:30px; height:20px"><small><a href="javascript:info()" title="Programm-Info">&nbsp;i&nbsp;</a> | <a href="http://people.physik.hu-berlin.de/~palloks/js/enigma/" title="Übersichtsseite (online)"> ? </a></small></td>
<td class="rubrik" style="height:20px; text-align:right"><small><em>&copy; 2007-11 Daniel Palloks</em> &nbsp; </small>
</td></tr>
</table>
</td></tr>
</table>

</div>

</body>
</html> 
Reply
#60
Still struggling with this code. The fact is, and I hate to admit it, my mind just doesn't work right anymore.
Ten years ago, I'd have done this in one evening. But it's slow now.
I'm going to post my latest attempt, so any help would be appreciated.
There are a lot of debugging printouts in this code that show exactly what's going on.
The code seems to work perfectly for the right rotor, but not for the middle or left.
The code should be pretty much the same for all three, except for the rotor advancement
before the first rotor encryption.

The setup for the test is (left to right):
Rings: 12, 4, 8
Roller Window: Q, U, O
PlugBoard: MZ, NS
Rotors: V, III, II
Reflector: B
Message: Enigma

-----------------------
The step by step operation should look like:
   
------------------------


import EnigmaPaths
import string
import collections
import json
import copy

class EncryptDammit:
    def __init__(self, plugboard_pairs, rotors, rings, rotor_window, reflector):
        self.rotors = rotors
        self.rings = rings
        self.rotor_window = rotor_window
        self.reflector = reflector
        self.epath = EnigmaPaths.EnigmaPaths()

        with self.epath.enigma_info.open() as f:
            self.init_data = json.load(f)

        # Set up ciphers for test, V, III, I (left to right)
        # Initial cipher shifted (ring setting - window letter index) =
        #  12 - abs((ord('O') - ord('A')))| =   for right rotor test
        self.rotor_info = {}
        self.set_up_rotor_info()
        self.window_incr = [0, 0, 0]

    def set_up_rotor_info(self):
        # Set up ciphers for test, V, III, I (left to right)
        # Initial cipher shifted by self.rotor_info[side]['current_offset']
        self.rotor_info['plugboard'] = {}
        self.rotor_info['plugboard']['cipher'] = collections.deque('ABCDEFGHIJKLZSOPQRNTUVWXYM')
        self.rotor_info['alpha'] = collections.deque(string.ascii_uppercase)
        self.rotor_info['reflector_cipher'] = collections.deque(self.init_data[f'reflector_{self.reflector}'])

        self.sides = {'left': 0, 'middle': 1, 'right': 2}

        # Keep three ciphers, one for ring offset, one for roller offset, one unmodified
        for side, side_idx in self.sides.items():
            self.rotor_info[side] = {}
            self.rotor_info[side]['rotor'] = self.rotors[side_idx]
            self.rotor_info[side]['ring_offset'] = self.rings[side_idx]
            self.rotor_info[side]['roller_window'] = copy.deepcopy(self.rotor_window[side_idx])
            self.rotor_info[side]['roller_window_offset'] = ord(self.rotor_info[side]['roller_window']) - ord('A')
            self.rotor_info[side]['alpha'] = collections.deque(string.ascii_uppercase)
            rotor_name = f"rotor{self.rotor_info[side]['rotor']}_info"
            self.rotor_info[side]['notch'] = self.init_data['rotor_info'][rotor_name]['notches'][0]
            self.rotor_info[side]['cipher'] = collections.deque(self.init_data['rotor_info'][rotor_name]['cipher'])
        # self.rotate_ring_cipher()

        # for side, side_idx in self.sides.items():
        #     self.rotate_roller_cipher(side, self.rotor_info[side]['roller_window_offset'])

    def rotate_ring_cipher(self):
        """
        Rotate ring cipher (call once only)
        :return: None
        """
        for side, side_idx in self.sides.items():
            self.rotor_info[side]['ring_cipher'].rotate(-self.rotor_info[side]['ring_offset'])

    def next_letter(self, letter):
        """
        Perpetual letter incrementor
        :param letter:
        :return: Next letter in alphabet, rotates to 'A' if input is 'Z'
        """
        return chr(((ord(letter) - ord('A') + 1) % 26) + ord('A'))

    def incr_roller(self, side):
        letter = self.rotor_info[side]['roller_window'] = self.next_letter(self.rotor_info[side]['roller_window'])
        self.rotor_info[side]['roller_window_offset'] = ord(self.rotor_info[side]['roller_window']) - ord('A')
        return letter

    def rotate_roller(self, side):
        letter = self.incr_roller(side)
        if letter == self.rotor_info[side]['notch']:
            if side == 'right':
                letter = self.incr_roller('middle')
                if letter == self.rotor_info['middle']['notch']:
                    letter = self.incr_roller('left')
            elif side == 'middle':
                letter = self.incr_roller('left')


    # def update_roller_windows(self, side):
    #     self.rotor_info[side]['roller_window'] = self.rotor_info[side]['roller_cipher'][0]
    #     self.rotor_info[side]['roller_window_offset'] = ord(self.rotor_info[side]['roller_cipher'][0]) - ord('A')

    def get_alpha_index(self, letter):
        return ord(letter) - ord('A')

    def show_current_settings(self):
        pass
        print(f"\nPlugBoard cipher:........ {self.rotor_info['plugboard']['cipher']}")

        for side in ('left', 'middle', 'right'):
            print(f"\n{side} rotor:................ {self.rotor_info[side]['rotor']}")
            print(f"{side} ring offset:.......... {self.rotor_info[side]['ring_offset']}")
            print(f"{side} roller window:........ {self.rotor_info[side]['roller_window']}")
            print(f"{side} roller window offset:. {self.rotor_info[side]['roller_window_offset']}")
            print(f"{side}_alpha:................ {self.rotor_info[side]['alpha']}")
            print(f"{side}_cipher.......:........ {self.rotor_info[side]['cipher']}")
            print(f"{side}_notch:................ {self.rotor_info[side]['notch']}")

        print(f"\nreflector_cipher:............ {self.rotor_info['reflector_cipher']}")
            # print(f"self.current_{side}_offset:.. {self.rotor_info[side]['current_offset']}")

    def plugboard_encrypt(self, letter):
        idx = self.get_alpha_index(letter)
        return self.rotor_info['plugboard']['cipher'][idx]

    def rotor_encrypt(self, side, inchar):
        # Values needed
        print(f'\nrotor_encrypt - side: {side} input character: {inchar}')
        ring_offset = self.rotor_info[side]['ring_offset']
        cipher = self.rotor_info[side]['cipher']
        alpha_index = (self.get_alpha_index(inchar) + ring_offset) % 26

        # Alpha_char serves no purpose except for test aid
        alpha_char = self.rotor_info[side]['alpha'][alpha_index]
        cipher_char = cipher[alpha_index]

        print(f'add rotor {self.sides[side]} offset: alpha_index: {alpha_index}, alpha_char: {alpha_char}')
        print(f'rotor {self.sides[side]} from right: cipher_char: {cipher_char}')

        cipher_char_idx = (self.get_alpha_index(cipher_char) - (ring_offset + 1)) % 26
        outchar = cipher[cipher_char_idx]
        print(f'subtract rotor {self.sides[side]} offset: cipher_char_idx: {cipher_char_idx}, outchar: {outchar}')

        print(f'{outchar} <-- {side} ring encrypt <-- {inchar}')
        return outchar

    def encrypt_forward(self, letter):
        # run through patchboard
        pbchar = self.plugboard_encrypt(letter)
        print(f'\nplugboard --> {letter}')

        self.rotate_roller('right')

        rightchar = self.rotor_encrypt('right', pbchar)
        middlechar = self.rotor_encrypt('middle', rightchar)
        leftchar = self.rotor_encrypt('left', middlechar)



        # iidx = self.rotor_info[side]['ring_offset'] + (self.get_alpha_index(tchar) % 26)
        # output_letter = self.rotor_info[side]['cipher'][iidx]  # O
        # print(f'right output_letter: {output_letter}')
        # out_ltr_index = self.get_alpha_index(output_letter)
        # print(f'out_ltr_index: {out_ltr_index}')
        # rightchar = self.rotor_info[side]['cipher'][self.get_alpha_index(output_letter) -
        #                                         (self.rotor_info[side]['ring_offset'] + 1)]

        # side = 'middle'
        # ochar = rightchar
        # iidx = self.rotor_info[side]['ring_offset'] + (self.get_alpha_index(rightchar) % 26)
        # output_letter = self.rotor_info[side]['cipher'][iidx]  # O
        # middlechar = self.rotor_info[side]['cipher'][((self.get_alpha_index(output_letter) -
        #                                                (self.rotor_info[side]['ring_offset'] + 1)) % 26)]
        # print(f'\n{middlechar} <-- middle ring encrypt <-- {ochar}')
        #
        # side = 'left'
        # ochar = middlechar
        # iidx = self.rotor_info[side]['ring_offset'] + (self.get_alpha_index(middlechar) % 26)
        # output_letter = self.rotor_info[side]['cipher'][iidx]  # O
        # idx1 = self.get_alpha_index(output_letter)
        # stepn = ((self.rotor_info[side]['ring_offset'] + 1) % 26)
        # leftchar = self.rotor_info[side]['cipher'][(idx1 - stepn) % 26]
        # print(f'iidx: {iidx}, output_letter: {output_letter}, idx1: {idx1}, stepn: {stepn}')

        # leftchar = self.rotor_info[side]['cipher'][((self.get_alpha_index(output_letter) -
        #                                                (self.rotor_info[side]['ring_offset'] + 1)) % 26)]

        # print(f'\n{leftchar} <-- middle ring encrypt <-- {ochar}')

        # Should have a T at this point
        #     UKW  W.3   W.2   W.1   ETW   STK
        # ┌- t <-- s <-- o <-- e <-- e <-- e (REIN)
        # └> m --> y --> q --> g --> g --> g (RAUS)

        return 'A'

    def encrypt_message(self, message):
        for letter in message:
            self.show_current_settings()
            outchar = self.encrypt_forward(letter)

if __name__ == '__main__':
    # message = 'ENIGMA'
    message = 'E'
    az = EncryptDammit(plugboard_pairs=[['M', 'Z'], ['N', 'S']], rotors=[5, 3, 1],
              rings=[12, 4, 8], rotor_window=['Q', 'U', 'O'], reflector='B')
    # az.show_current_settings()
    az.encrypt_message(message)
EnigmaPaths.py
from pathlib import Path

class EnigmaPaths:
    def __init__(self):
        self.homepath = Path('.')
        self.datapath = self.homepath / 'data'
        self.imagepath = self.homepath / 'image'
        self.enigma_info = self.datapath / 'enigma_info.json'
        self.color_info = self.datapath / 'color_info.json'
        self.patchboard_image = self.imagepath / 'patchboard.ppm'

Attached Files

.json   enigma_info.json (Size: 908 bytes / Downloads: 201)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Numeric Enigma Machine idev 9 545 Mar-29-2024, 06:15 PM
Last Post: idev
  Enigma Decoding Problem krisarmstrong 4 747 Dec-14-2023, 10:42 AM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020