Title: Encode and decode Futurama's alienese in C#
My last two posts explained a program can pull out pieces of an image. In those examples, the image was a collection of glyphs and the program saved the individual glyphs in png files. This post uses the glyphs to encode and decode messages using Futurama's alienese language.
The user interface uses a TableLayoutPanel with two columns and six rows to hold the program's other controls. I'll let you look over the user interface to see exactly how it works.
The program creates the following form-level dictionary to map characters to glyphs.
// Dictionary to map characters to glyph buttons.
private Dictionary<char, Image> GlyphDict =
new Dictionary<char, Image>();
When the program starts, the following code prepares the program for use.
private void Form1_Load(object sender, EventArgs e)
{
// Create the decoding buttons.
for (char ch = 'A'; ch <= 'M'; ch++)
MakeButton(GlyphDict, flpButtons1, ch.ToString());
for (char ch = 'N'; ch <= 'Z'; ch++)
MakeButton(GlyphDict, flpButtons2, ch.ToString());
for (char ch = '0'; ch <= '9'; ch++)
MakeButton(GlyphDict, flpButtons3, ch.ToString());
foreach (char ch in "\'!“”:-.; ")
MakeButton(GlyphDict, flpButtons4, ch.ToString());
Button btnCl = new Button();
btnCl.Font = this.Font;
btnCl.Parent = flpButtons4;
btnCl.Size = new Size(54, 24);
btnCl.Text = "CL";
btnCl.Click += btnCl_Click;
Button btnBs = new Button();
btnBs.Font = this.Font;
btnBs.Parent = flpButtons4;
btnBs.Size = new Size(54, 24);
btnBs.Text = "BS";
btnBs.Click += btnBs_Click;
}
This code uses several loops that call the MakeButton method described shortly to create glyph buttons. It then creates two buttons to clear the current message and to act as a backspace.
The following code shows the MakeButton method.
// Make a button.
private const int BTN_WID = 24;
private void MakeButton(
Dictionary<char, Image> glyph_dict,
Control parent, string text)
{
// Make the button.
Button btn = new Button();
btn.Parent = parent;
btn.Size = new Size(BTN_WID, BTN_WID);
btn.Tag = text;
btn.Font = this.Font;
btn.Click += btnDecode_Click;
ttip.SetToolTip(btn, text);
// Get the button's image.
string name = ResourceName(text);
Bitmap bm = Properties.Resources.ResourceManager.GetObject(name)
as Bitmap;
Bitmap new_bm = new Bitmap(BTN_WID, BTN_WID);
using (Graphics gr = Graphics.FromImage(new_bm))
{
gr.InterpolationMode = InterpolationMode.High;
gr.Clear(Color.White);
Point[] dest_points =
{
new Point(2, 2),
new Point(btn.ClientSize.Width - 3, 2),
new Point(2, btn.ClientSize.Height - 3),
};
gr.DrawImage(bm, dest_points);
}
btn.Image = new_bm;
// Save the image in the glyph dictionary.
glyph_dict.Add(text[0], new_bm);
}
This method makes a new button, adds it to a FlowLayoutPanel control, and sets various button properties. In particular, it stores the glyph's text value in the button's Tag property and uses the same text for the button's tooltip.
The method then gets the button's image from the project's resources. The Properties.Resources.ResourceManager.GetObject method gets the object by that name. The code resizes the image resource to fit the button.
The method finishes by adding the button's image to the dictionary using the button's text as a key. Later, when the program needs to encode a message, it uses the letter to look up the glyph in the dictionary.
Most of the project's image resources are named after the glyphs they represent. For example, the glyph representing A is stored in the file A.png and its resource is named A. However, special characters such as ! and ; have different names. The following ResourceName method converts a button's text into its resource name.
// Convert a character into its resource name.
private string ResourceName(string text)
{
char ch = text[0];
if ((ch >= 'A') && (ch <= 'Z')) return text;
if ((ch >= '0') && (ch <= '9')) return "_" + text;
switch (ch)
{
case '\'': return "Apostrophe";
case '!': return "Bang";
case '“': return "OpenQuote";
case '”': return "OpenQuote";
case ':': return "Colon";
case '-': return "Dash";
case '.': return "Period";
case ';': return "SemiColon";
case ' ': return "Space";
default: return null;
}
}
If the text is a letter, the method simply returns it.
If the text is a digit, Visual Studio prepends an underscore to the digit to make the resource name, so this method does the same.
If the text is a special character, the method uses a switch statement to return the appropriate name.
If the text is none of those, the method returns null. (That should not happen, but that statement makes Visual Studio happy because it means the method always returns something.)
All of that setup makes it relatively easy to encode and decode messages. The program's glyph buttons all execute the following event handler.
// Add a character to the decoded message.
private void btnDecode_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
txtDecode.AppendText(btn.Tag as string);
}
This method simply appends the button's text value (as stores in its Tag property) to the txtDecode text box.
When you change the text in the encoding text box, the following code displays the text's encoding.
// Add a character to the decoded message.
private void txtEncode_TextChanged(object sender, EventArgs e)
{
flpEncoding.Controls.Clear();
foreach (char ch in txtEncode.Text.ToUpper())
{
if (GlyphDict.ContainsKey(ch))
{
PictureBox pic = new PictureBox();
pic.SizeMode = PictureBoxSizeMode.AutoSize;
pic.Image = GlyphDict[ch];
pic.Parent = flpEncoding;
}
}
}
This method clears the FlowLayoutPanel named flpEncoding. It then loops through the messages characters. It creates a PictureBox, uses the character to look up the corresponding glyph image in the program's dictionary GlyphDict, and makes the PictureBox display it.
That's about all there is how this program encodes and decodes messages. Download the example to see additional details.
There are plenty of modifications that you could make to this program. For example, you could trim the glyph images so they contain less spaces around their edges and produce a tighter encoding. You could also make the program save the encoding in a single image and allow the user to specify dimensions for that output so, for example, you could display long messages on a single line. If you make those modifications or others, or if you have suggestions for changes that might be interesting, please post a note in the comments below.
Download the example to experiment with it and to see additional details.
|