Jump to content
  • entries
    63
  • comments
    51
  • views
    20,411

The Software Enigma Machine blog Pt. 4: The GUI

Mira Yurizaki

1,231 views

Part 4 in the making of the Software Enigma Machine. This last part deals with the graphical interface.

 

The Outline

A recap on the outline.

  • Part 1
    • What is the Enigma Machine?
    • Why did I choose to implement the Enigma machine?
    • Before Programming Begins:
      • Understanding the theory of the Enigma Machine
      • Finding a programming environment
  • Part 2
    • Programming the features
    • Rotors
    • Rotor housing
  • Part 3
    • Plug Board
  • Part 4
    • GUI

If you'd like to look at the source code, it's uploaded on GitHub.

 

Programming the GUI

With Visual Studio, designing the GUI was pretty easy. Originally it looked like this:

 

old-gui.png.d9cbecf53768b2a0160d2b166f213d2c.png

 

The rotors were chosen as numeric spinner to both be an input and an output. An issue I was facing was at first I wanted the rotor position control to update the rotors internally if the value changed. This worked fine, but when I wanted to change their positions, I wasn't sure if I actually modified them or not (the "Set rotors" button originally didn't exist). So to fix this, I use the value change event handler to mark if the value is different from the rotor's position, but not update the rotor positions themselves. The user has to press the "Set Rotors" button to set the rotors and clear the highlighting. That ensures the user knows the rotors on the GUI report the correct position.

 

The "Seed" spinner is to set the randomization. If this changes, it creates a new set of rotors, and the rotors are tied to the seed. This helps increase the entropy (or randomness) of the system. If I did my math right, in theory there should be 637,876,516,893,491,200 possible combinations between the rotor settings (456,976 possible combinations), their wiring (650 permutations), and the random seed (2^32)

 

This version of the GUI is the "simple" version, in that you feed something in the Input textbox and the app will spit out the "scrambled" message in the Output textbox. To "decode" a message, the scrambled output is fed in as the input and the rotors are set back to the original position.

 

I knew this wouldn't really be a good Enigma Machine app if it didn't have the keyboard, lights, and plug board so that was next. The final design ended up having a tabbed interface for switching between the simple and the full versions:

 

enigma_full.png.88acf5de04f1cee56f8653125627354e.png

 

The top section is the lamps for the letters, the middle for buttons, and the bottom for the plug board. The plug board also has three buttons for shuffling the wiring (produces a random output every time without affecting the RNG seed), resets the wiring to the first randomized position, or clears the board so the letters map to themselves.

 

So the biggest problem I had with making this GUI was while I'm sure there's a way to programmatically add elements, I still placed them all piece by piece (well, with some copy and paste for good measure). And then I had to rename them all with useful sounding names. But here came the worst part: how do I handle all of the necessary event handlers? I needed a handler for all of the keyboard key presses and one when one of the plug board letter mapping changes.

 

In Visual Studio, if you double click on a GUI element, it creates a default event handler for you for the most common action that would happen. So if you do this to a button, it will create an event handler for clicking on the button. Sure, I could do this for every button, and I can do this for every one of the plug board drop down menus. But here's the problem, now I have 56 handlers to edit. And 26 each have basically the same code, just using a different parameter. This is a classic case of repeating myself which is against the DRY principle (Don't Repeat Yourself). The biggest reason why this is a problem is if I need to change what an event handler does, I have go back and change it for all of them. That's error prone and gets old fast.

 

There was also a related situation on how I would light up a lamp. I could have something like this:

string outputLetter = machine.ScrambleText(Input);
switch(outputLetter){
  case 'A':
    ALampLabel.BackColor = Color.Yellow;
    break;
  case 'B':
    BLampLabel.BackColor = Color.Yellow;
    break;
  ...
  case 'Z':
    ZLampLabel.BackColor = Color.Yellow;
    break;
}

Despite that I'm manipulating a different object in each case, this is still an example of violating the DRY principle. What if I wanted the lamp to show a different color for a scrambled letter? Now I have to change 26 of them.

 

At this point I realize C# Lists don't care what data type they store. They can store a collection of any data type. A programmatic solution can be done by having a collection of Labels, Buttons, and ComboBox types:

  • Create a new List of the appropriate class type
  • Use the List.Add method to add the objects. The caveat is that they have to be added in the correct order. This is where smart naming of the objects come into play. Since the letter mapping I feed the rotor housing and plug board is the English alphabet, I start with whatever represents A, then B, etc.
  • At the end, if the elements need to be initialized to something, I use an iterator over the List and add what I need.

For the buttons and drop down menus, they needed an event handler to handle the a click and a value change respectively. Fortunately, the way they handle the event is the same. For example, key presses just need to do this:

keyLetter = plugBoard.GetRewiredLetter(keyLetter);
encodeKeyPress(keyLetter);

But where does keyLetter come from? I found out that every GUI element object has its own name as a property. So even though in code the object for say the keyboard key A is called AKeyboardButton, if I invoke AKeyboardButton.Name, it gives me "AKeyboardButton." And since the way I named the elements are the same, their schema is such that I pluck the first letter out and get the letter the key represents. This changes the code to:

string keyLetter = keyButton.Name.Substring(0, 1);
keyLetter = plugBoard.GetRewiredLetter(keyLetter);
encodeKeyPress(keyLetter);

Oh, but where did keyButton come from? That was taken from a parameter passed in the event handler. Event handlers have a parameter called sender of a generic object type. Casting sender to the appropriate object type (in this case, Button) figuratively turns the data type from a generic object type to Button. Now I can use sender as if it were the button I pressed. So the code is now:

Button keyButton = ((Button)sender);
string keyLetter = keyButton.Name.Substring(0, 1);
keyLetter = plugBoard.GetRewiredLetter(keyLetter);
encodeKeyPress(keyLetter);

Using this technique probably saved not only a ton of lines of code, but a ton of headache needing to go back to change up anything should I needed to update how an event handler works. And I've already updated the event handlers a few times.

0 Comments

There are no comments to display.

×