Understand string equality testing in C#

[example]

To really understand this example, you need to know about string interning, equality testing, and operator overloading.

Interning

First, interning. To save space, .NET uses an intern pool to store literal strings at compile time. If the program contains a string literal, it is added at compile time to the intern pool. Later, if another string literal contains the same value, it uses the same instance within the intern pool.

Note that this only happens to literal values defined at design time. If the program builds a string at run time, it is not placed in the intern pool because that might slow the program down.

Equality Testing

Next, equality testing. There are two kinds of equality: reference equality and value equality. In reference quality, two variables are compared to see if they point to the same object. In value equality, two variables are compared to see if the things they point to havhe the same values.

For example, suppose you have two different Person objects that both contain the same data. They are equal using value equality because they represent the same values. They are different using reference equality because they are two separate Person objects that just happen to contain the same values.

Operator Overloading

Finally, operator overloading. Classes can overload operators such as == so they perform some specific action. The string class overloads == to make it call the Equals method. That method compares the contents of two strings.

The object class does not overload == and it uses reference equality testing.

The Example

With that as background, you can understand the example. When the program runs, it executes the following code.

// Two equal strings created at run time.
string A = "ABCDEFGHIJ";
string B = "ABCDEFGHIJ";
bool a_eq_b = A == B;
bool a_equals_b = A.Equals(B);
txtAeqB.Text = a_eq_b.ToString();
txtAequalsB.Text = a_equals_b.ToString();

// Two equal strings created at
// design time but stored as objects.
object C = A;
object D = B;
bool c_eq_d = C == D;
bool c_equals_d = C.Equals(D);
txtCeqD.Text = c_eq_d.ToString();
txtCequalsD.Text = c_equals_d.ToString();

// Two equal strings created at run time.
string E = A.Substring(2, 4);
string F = A.Substring(2, 4);
bool e_eq_f = E == F;
bool e_equals_f = E.Equals(F);
txtEeqF.Text = e_eq_f.ToString();
txtEequalsF.Text = e_equals_f.ToString();

// Two equal strings created at
// run time but stored as objects.
object G = E;
object H = F;
bool g_eq_h = G == H;
bool g_equals_h = G.Equals(H);
txtGeqH.Text = g_eq_h.ToString();
txtGequalsH.Text = g_equals_h.ToString();

The code first creates two strings A and B. Because they are literals, they are placed in the intern pool.

Next the code tests A == B. The string class overloads == to use the Equals method, so the test A == B invokes that method and the program knows that they are the same.

When the code tests A.Equals(B), it obviously uses the Equals method so again the program knows that the two values are the same.

Now the program creates object variables C and D, makes them refer to A and B, and then checks C == D. Other discussions I’ve seen of this on the internet gloss over this test but it’s probably the strangest. The test C == D uses reference equality because the two variables are objects. But because A and B were interned, they refer to the same location in the intern pool. That means C and D also refer to the same location in the intern pool and therefore the reference equality test C == D returns true.

Next the program creates two strings at run time by taking a substring of the value A. Because these strings only exist at run time, they are not literals so they are not interned. They refer to different string objects that happen to contain the same values.

The test E == F uses string variables and the string class overloads == to use Equals, so that test returns true.

The test E.Equals(F) also uses Equals so it returns true.

Next the code creates two object variables G and H and sets them equal to E and F. When it tests G == H, the two variables refer to different objects. The == operator tests reference equality for object variables so this test returns false.

Finally the program tests G.Equals(H). The Equals method is virtual, so the code calls the string object’s version of the method even though the variable G is a non-specific object. The string version of the method compares the string values so it returns true.

Yes it’s complicated. If you don’t see why each of the tests returns what it does, you should read the explanation again.

The Moral

So what’s the moral of the story? Normally if you treat strings like strings, you don’t need to worry about this. You can use == to keep your code easier to read.

However, if you save a string value in an object variable, you need to use Equals to test equality. Some people use Equals all of the time so they don’t need to worry about the difference. That seems a bit silly because a typical program will use string variables a lot but will rarely store a string in an object variable. You also can’t test A.Equals(B) if A is null.

One time where this makes more sense is if you have a generic method that might need to work with strings as in the following code.

private void Test(T a, T b) where T : class
{
    if (a == b)
    {
        ...
    }
}

The constraint : class means a and b must be classes and string is a class.

If you pass string literals into this method, it works as expected. However, if you pass strings created at run time into the method, it will not notice if the strings are the same.

As is usually the case, you can avoid the problem most of the time if you use common sense. Use strings when you can and don’t make generic methods overly general. If you need to pass objects into a generic method as in this case, use Equals instead of ==. Hopefully if you do run into this weird situation, you’ll remember this post and be able to figure out what’s happening.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in strings, syntax | Tagged , , , , , , , , , , , , | Leave a comment

Use a Dictionary to store and retrieve items in C#

[dictionary]

This example demonstrates a Dictionary. A Dictionary is basically a strongly typed Hashtable.

A Hashtable stores key/value pairs in a way that makes looking up values extremely fast. For example, suppose you have an employee database that uses EmployeeId values to look up Employee object. If you use a Hashtable to store the values, you can find a particular employee very quickly.

The problem with the Hashtable class is that it works with the non-specific object class. That means your code needs to cast items from the object class to a specific class (for example, Employee) when you get an item from the Hashtable.

It also means the Hashtable doesn’t perform type checking so your code could add anything anything to the Employees Hashtable. It could add Employee objects as intended, or it could accidentally add Customer, Invoice, or DogFood objects to the Hashtable.

The Dictionary class provides features similar to a Hashtable but it is a generic class so it is strongly typed. That means your code doesn’t need to convert from generic objects into specific types. It also means the Dictionary ensures that your code passes the right kinds of objects to it.

The following code declares and initializes the Dictionary.

// The dictionary.
private Dictionary Words = new Dictionary();

The Dictionary class’s type parameters give the types of the keys and values stored in the Dictionary. In this example, they are both strings.

If you enter a key and value and click the Add button, the program uses the following code to add the value to the Dictionary.

// Add a value to the dictionary.
private void btnAdd_Click(object sender, EventArgs e)
{
    if (Words.ContainsKey(txtKey.Text))
    {
        MessageBox.Show(
            "The dictionary already contains this key.");
    }
    else
    {
        Words.Add(txtKey.Text, txtValue.Text);
        txtKey.Clear();
        txtValue.Clear();
        txtKey.Focus();
        ListValues();
    }
}

A Dictionary can hold only one value for a given key and throws an exception if you try to add an entry with an existing key. To protect itself from that exception, the code uses the Dictionary object’s ContainsKey method to see if the key is already in the Dictionary. If the key is already present, the program displays a message. If the key is not present, the program calls the object’s Add method, passing it the new key and value.

If you enter a key and click the Find button, the following code displays the corresponding value in the Dictionary.

// Look up a value.
private void btnFind_Click(object sender, EventArgs e)
{
    if (!Words.ContainsKey(txtKey.Text))
    {
        txtValue.Text = "";
    }
    else
    {
        txtValue.Text = Words[txtKey.Text];
    }
}

If you try to use a value for a key that isn’t present in a Dictionary, the Dictionary again throws an exception. To protect itself, this code first uses the Dictionary object’s ContainsKey method to see if the key is present. If the key is missing, the code displays a message. If the key is present, the code displays the corresponding value.

If you enter a key and click the Delete button, the following code executes.

// Remove an item from the dictionary.
private void btnDelete_Click(object sender, EventArgs e)
{
    if (!Words.ContainsKey(txtKey.Text))
    {
        MessageBox.Show("Item not found");
    }
    else
    {
        Words.Remove(txtKey.Text);
        ListValues();
    }
}

If you try to delete a value with a key that isn’t in the Dictionary, the Dictionary once again throws an exception so, again, this code uses the Contains method to protect itself. If the key is not in the Dictionary, the code displays a message. If the key is in the Dictionary, the code deletes it and its value.

Whenever the program changes the contents of the Dictionary, it calls the following ListValues method to display all of the keys and their values.

// List the dictionary's current values.
private void ListValues()
{
    lstValues.Items.Clear();
    foreach (string key in Words.Keys)
    {
        lstValues.Items.Add(key + ": " + Words[key]);
    }
}

The code loops through the Dictionary object’s keys. For each key, it adds the key plus the corresponding value to the ListBox named lstValues.

Note that by default the Dictionary class is case-sensitive. That means you could have an entry with key “ID 123” and a second entry with key “Id 123.” In my next post I’ll explain an easy way to make a case-insensitive Dictionary.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, strings | Tagged , , , , , , , , , , | Leave a comment

Compare the performance of string comparison methods in C#


[performance]

This example uses the following code to make four strings:

string value0 = "AAAAAAAAAAAAAAAAAAAAAA";
string value1 = "AAAAAAAAAAAAAAAAAAAAAA";
string value2 = "AAAAAAAAAAAAAAAAAAAAAB";
string value3 = "BAAAAAAAAAAAAAAAAAAAAA";

It then uses several methods for comparing the first string with the others. For example, it uses the following code to compare the strings by using ==.

start_time = DateTime.Now;
for (int i = 1; i <= iterations; i++)
{
    if (value0 == value1) { }
    if (value0 == value2) { }
    if (value0 == value3) { }
}
elapsed = DateTime.Now - start_time;
txtEqEq.Text = elapsed.TotalSeconds.ToString("0.000") + " sec";

The following code fragment shows the statements the program uses to perform the different comparisons. The last three methods perform case-insensitive comparisons. (I've combined them all to one place here. They are not all together in the code.)

if (value0 == value1) { }
if (String.Compare(value0, value1, false) == 0) { }
if (value0.Equals(value1)) { }

if (String.Compare(value0, value1, true) == 0) { }
if (value0.Equals(value1,
    StringComparison.CurrentCultureIgnoreCase)) { }
if (value0.ToLower() == value1) { }

You can see from the results that == gave the fastest performance, followed closely by .Equals. The String.Compare method was much slower.

I think the reason == is so fast is due to the way C# handles strings. When you create a string in .NET, it is interned and placed in an intern pool. Later if you create another string containing the same text, the new string refers to the same instance in the intern pool. That makes it relatively quick and easy to compare two strings.

Among the case-insensitive tests, String.Equals gave the fastest performance. Converting the test string to lower case for every iteration was quite slow, however if you need to compare a string to many other values and you can convert the test string to lower case only once before all of the tests, then the ToLower method basically converts into the == case and performance will be much better. If the run time is just an aggregate over a large number of comparisons with different test values, then that technique won't work.

If you need to look up a particular string, rather than comparing a test value to a bunch of other values, consider using a Dictionary.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in performance, strings | Tagged , , , , , , , , , | Leave a comment

Compare the performance of switch and if statements in C#

[performance]

This example compares the performance of switch and if-else statements. Both do roughly the same thing: they check a series of conditions until they find one that is true and then skip the rest. This example compares the speeds of these two constructs. When you click the Go button, the program executes the following code.

private void btnGo_Click(object sender, EventArgs e)
{
    // Get ready.
    txtIfThen.Clear();
    txtSwitch.Clear();
    this.Cursor = Cursors.WaitCursor;
    Refresh();
    int iterations = int.Parse(txtIterations.Text);
    DateTime start_time;
    TimeSpan elapsed;

    // If then.
    start_time = DateTime.Now;
    for (int i = 1; i <= iterations; i++)
    {
        for (int num = 0; num < 50; num++)
        {
            int value;
            if (num == 0) { value = num; }
            else if (num == 1) { value = num; }
            else if (num == 2) { value = num; }
            ...
            else if (num == 49) { value = num; }
            else { value = num; }
            if (value > 1000) Console.WriteLine(value);
        }
    }
    elapsed = DateTime.Now - start_time;
    txtIfThen.Text = elapsed.TotalSeconds.ToString() + " sec";
    txtIfThen.Refresh();

    // Switch.
    start_time = DateTime.Now;
    for (int i = 1; i <= iterations; i++)
    {
        for (int num = 0; num < 50; num++)
        {
            int value;
            switch (num)
            {
                case 0:
                    value = num; break;
                case 1:
                    value = num; break;
                case 2:
                    value = num; break;
                ...
                case 49:
                    value = num; break;
                default:
                    value = num; break;
            }
            if (value > 1000) Console.WriteLine(value);
        }
    }
    elapsed = DateTime.Now - start_time;
    txtSwitch.Text = elapsed.TotalSeconds.ToString() + " sec";
    txtSwitch.Refresh();

    this.Cursor = Cursors.Default;
}

After some preliminaries such as saving the starting time, the code loops over the desired number of iterations. For each iteration, the code loops over the values 1 through 50 and uses a series of if-then statements to find the loop’s value. It saves the value in a variable just to be sure that C# cannot optimize the statement out of existence.

After finishing the required number of iterations, the program repeats the same steps with a switch statement.

Because the two methods logically perform the same steps, I was surprised that the switch statement was so much faster. In the test shown here, the if-then statements took 2.03 seconds to perform 1 million iterations while the switch statement took only 0.32 seconds. I also tried a similar program with strings and, while both methods took much longer and the difference wasn’t as great (3.099 seconds and 1.193 seconds for 100,000 iterations), the switch statement was still much faster. I’ll leave making that version of the program as an exercise.

If you use ildasm to look at the IL code, you can see that the compiled code uses an IL switch statement to branch to a number of pre-computed locations depending on the switch variable’s value. (Although the compiler may not always generate a switch statement depending on the particular code.)

That’s the big catch. The values used by the switch statement must be calculatable at compile time. A series of if-then statements is much more flexible and can evaluate complicated expressions involving variables whose values can change at run time.

The conclusion is that if you have a long sequence of if-then statements as in this example, you’ll probably get better performance from the switch statement. If you need greater flexibility, then you need to use an if-else sequence.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in performance, syntax | Tagged , , , , , , , , , , , , , , | Leave a comment

Draw, move, and delete line segments in VB.NET

[line editor]

This progra lets you draw, move, and delete line segments from a drawing. It’s a Visual Basic .NET version of the example Draw, move, and delete line segments in C# made by request.

Click and drag to draw line segments. If you click on a segment’s end point, you can drag it into a new position. If you click on a segment’s body, you can move the whole segment. Finally if you drag a segment onto the trash can icon, the program asks if you want to delete the segment.

See the original post for an explanation of how the program works.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in drawing, graphics | Tagged , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Convert a Rectangle into a RectangleF and vice versa in C#

[rectangle]

The RectangleF structure has an overloaded assignment operator = that lets you simply set a RectangleF equal to a Rectangle, so converting a Rectangle into a RectangleF is easy.

That makes sense because converting from Rectangle to RectangleF is a widening conversion. The integer values that define a Rectangle can be placed within float values without losing any precision.

Converting a RectangleF to a Rectangle is only slightly harder. The RectangleF class provides two methods, Round and Truncate, that perform this conversion.

This is a narrowing conversion because the float values that define the RectangleF don’t necessarily fit in the Rectangle structure’s integer properties.

This example uses the following code to convert a Rectangle into a RectangleF and back, and draw to all three rectangles.

private void Form1_Paint(object sender, PaintEventArgs e)
{
    // Make a rectangle.
    Rectangle rect1 = new Rectangle(20, 20,
        this.ClientSize.Width - 40,
        this.ClientSize.Height - 40);

    // Convert to RectangleF.
    RectangleF rectf = rect1;

    // Convert back to Rectangle.
    Rectangle rect2 = Rectangle.Round(rectf);
    //Rectangle rect2 = Rectangle.Truncate(rectf);

    // Draw them.
    using (Pen the_pen = new Pen(Color.Red, 20))
    {
        e.Graphics.DrawRectangle(the_pen, rect1);

        the_pen.Color = Color.Lime;
        the_pen.Width=10;
        e.Graphics.DrawRectangle(the_pen,
            rectf.X, rectf.Y, rectf.Width, rectf.Height);

        the_pen.Color = Color.Blue;
        the_pen.Width = 1;
        e.Graphics.DrawRectangle(the_pen, rect2);
    }
}

The code first defines a Rectangle. It uses assignment to convert it into a RectangleF and then uses the RectangleF structure’s Round method to convert it back into a Rectangle. The program then draws all three rectangles on top of each other with different line widths and colors so you can see them all.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in drawing, graphics | Tagged , , , , , , , , , , | Leave a comment

Make a hangman game in C#


[hangman]

Special thanks to Jeff Scarterfield for the skeleton drawing used by the program.

This example builds a simple hangman game that uses the dictionary created by the example Use LINQ to select words of certain lengths from a file in C#.

If you don’t know how hangman works, the program shows you blank spaces at the top where the letters in a word go and you have to guess the letters. Each time you make a wrong guess, the program displays another part of the hanged man, or in this example, a skeleton. If you build the entire skeleton, you lose. If you guess all of the letters first, you win.

This program isn’t too complicated but it is fairly long. The following code shows how the program initializes.

// PictureBoxes holding skeleton pictures.
private PictureBox[] PictureBoxes;

// The index of the current skeleton picture.
private int CurrentPictureIndex = 0;

// Words.
private string[] Words;

// The current word.
private string CurrentWord = "";

// Labels to show the current word's letters.
private List<Label> LetterLabels = new List<Label>();

// A list holding the letter buttons.
private List<Button> KeyboardButtons;

// Prepare to play.
private void Form1_Load(object sender, EventArgs e)
{
    // Save references to the PictureBoxes in the array.
    PictureBoxes = new PictureBox[]
    {
        picSkeleton0, picSkeleton1, picSkeleton2, picSkeleton3,
        picSkeleton4, picSkeleton5, picSkeleton6
    };

    // Load the words.
    Words = File.ReadAllLines("Words.txt");

    // Make button images.
    MakeButtonImages();
}

The program uses the following class-level variables to keep track of what’s happening:

  • PictureBoxes – An array that holds a series of 7 PictureBox controls that display skeleton images of varying completeness ranging from a blank white picture to the full skeleton.
  • CurrentPicture – The index of the currently visible PictureBox. When this equals the index of the last PictureBox, the user is seeing the full skeleton and therefore has lost the game.
  • Words – An array holding the word dictionary.
  • CurrentWord – The current word that the user is trying to guess.
  • LetterLabels – The Label controls that display the current word’s letters or the blank spots where the letters will go.
  • KeyboardButtons – The buttons that act as a keyboard.

The form’s Load event handler initializes the PictureBoxes array, uses File.ReadAllLines to load the Words array, and calls the following MakeButtonImages method to prepare the keyboard buttons.

// Make the button images.
private void MakeButtonImages()
{
    // Prepare the buttons.
    KeyboardButtons = new List<Button>();
    foreach (Control ctl in this.Controls)
    {
        if ((ctl is Button) && (!(ctl == btnNewGame)))
        {
            // Set the button's name.
            ctl.Name = "btn" + ctl.Text;

            // Attach the Click event handler.
            ctl.Click += btnKey_Click;

            // Make the button's image.
            MakeButtonImage(ctl as Button);

            // Save in the Buttons list for later use.
            KeyboardButtons.Add(ctl as Button);
        }
    }
}

When I first built the keyboard buttons, the letters didn’t center nicely over the buttons for some reason, possibly because the buttons were so small. To make them look nicer, I decided to make each button display an image holding its letter. The MakeButtonImages method creates the button’s images.

The MakeButtonImages method loops through the controls on the form. For every control that is a button except the New Game button, the program sets the button’s name to btn plus its letter. It adds the btnKey_Click event handler to the button’s Click event, and calls the MakeButtonImage method to make the button’s image. Finally it adds the button to the KeyboardButtons list.

The following code shows the MakeButtonImage method

// Give this button an image thet fits better than its letter.
private void MakeButtonImage(Button btn)
{
    Bitmap bm = new Bitmap(
        btn.ClientSize.Width,
        btn.ClientSize.Height);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        gr.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
        using (StringFormat string_format = new StringFormat())
        {
            string_format.Alignment = StringAlignment.Center;
            string_format.LineAlignment = StringAlignment.Center;
            gr.DrawString(btn.Text, btn.Font, Brushes.Black,
                btn.ClientRectangle, string_format);
        }
    }
    btn.Tag = btn.Text;
    btn.Image = bm;
    btn.Text = "";
}

This method creates a Bitmap to fit the button’s client area. It makes an associated Graphics object and draws the button’s text centered on the Bitmap. It then saves the button’s letter in its Tag property, sets the button’s Image property to the Bitmap, and clears the button’s Text property so it displays only the image.

At this point the program is ready to run, although all of the keyboard buttons are initially disabled and the letter labels list is empty. When the user clicks the New Game button, the following code prepares the program for a new hangman game.

// Prepare for a new game.
private void btnNewGame_Click(object sender, EventArgs e)
{
    // Delete old letter labels.
    foreach (Label lbl in LetterLabels)
    {
        flpLetters.Controls.Remove(lbl);
        lbl.Dispose();
    }

    // Pick a new word.
    Random rand = new Random();
    CurrentWord = Words[rand.Next(Words.Length)].ToUpper();
    // Console.WriteLine(CurrentWord);

    // Create new letter labels.
    LetterLabels = new List<Label>();
    foreach (char ch in CurrentWord)
    {
        Label lbl = new Label();
        flpLetters.Controls.Add(lbl);
        lbl.Tag = ch.ToString();
        lbl.Size = btnQ.Size;
        lbl.TextAlign = ContentAlignment.MiddleCenter; 
        lbl.BackColor = Color.White;
        lbl.BorderStyle = BorderStyle.Fixed3D;
        LetterLabels.Add(lbl);
    }

    // Hide the won/lost labels.
    lblWon.Visible = false;
    lblLost.Visible = false;

    // Enable the letter buttons.
    foreach (Button letter_btn in KeyboardButtons)
        letter_btn.Enabled = true;

    // Display the first picture.
    PictureBoxes[CurrentPictureIndex].Visible = false;
    CurrentPictureIndex = 0;
    PictureBoxes[CurrentPictureIndex].Visible = true;
}

The code starts by deleting any letter labels that were created for the previous word. Those labels were contained in a FlowLayoutPanel named flpLetters so the code removes them from that control’s Controls collection and then disposes of each label.

The code then picks a random word from the Words list for the next game. It creates a new LetterLabels list and builds a Label for each of the new word’s letters. For each letter, the code:

  • Creates the label
  • Adds the label to the FlowLayoutPanel
  • Sets the label’s Tag property to the word’s corresponding letter
  • Centers the label’s text
  • Sets the label’s foreground and background colors
  • Adds the label to the LetterLabels list

Note that the code does not set the new labels’ Text properties.

The btnNewGame_Click event handler continues by hiding the labels that indicate that the user won or lost. It then enables the keyboard buttons.

Finally the code hides the previously displayed skeleton picture, sets CurrentPictureIndex to 0 (the index of the blank picture), and displays the blank picture.

The last piece of the program is the following btnKey_Click event handler, which executes when the user clicks a keyboard button.

// A key was clicked.
private void btnKey_Click(object sender, EventArgs e)
{
    // Disable this button so the user can't click it again.
    Button btn = sender as Button;
    btn.Enabled = false;

    // See if this letter is in the current word.
    string ch = btn.Tag.ToString();
    if (CurrentWord.Contains(ch))
    {
        // Good guess. Display matching letters.
        bool has_won = true;
        foreach (Label lbl in LetterLabels)
        {
            // See if this letter matches the current guess.
            if (lbl.Tag.ToString() == ch) lbl.Text = ch.ToString();

            // See if the user has found this letter.
            if (lbl.Text == "") has_won = false;
        }
        
        // See if the user has won.
        if (has_won)
        {
            lblWon.Visible = true;
            foreach (Button letter_btn in KeyboardButtons)
                letter_btn.Enabled = false;
        }
    }
    else
    {
        // Bad guess. Show the next picture.
        PictureBoxes[CurrentPictureIndex].Visible = false;
        CurrentPictureIndex++;
        PictureBoxes[CurrentPictureIndex].Visible = true;

        // See if the user has lost.
        if (CurrentPictureIndex == PictureBoxes.Length - 1)
        {
            lblLost.Visible = true;
            foreach (Button letter_btn in KeyboardButtons)
                letter_btn.Enabled = false;
            foreach (Label lbl in LetterLabels)
                lbl.Text = lbl.Tag.ToString();
        }
    }
}

The event handler first disables the clicked button so the user can’t click it again. It then gets the button’s Tag property, converts it to the button’s letter, and determines whether the letter is in the current word.

If the letter is in the word, the program loops through the letters labels. If a label corresponds to the letter, the code displays the letter in the label. If any label’s text is still blank, then the user has not guessed all of the letters yet and the game continues. If the user has guessed all of the letters, the program displays the “you won” message and disables all of the keyboard buttons.

If the guessed letter is not in the word, the program hides the currently displayed skeleton image, increments CurrentPictureIndex to show the next skeleton image, and displays that image. Then if the current image is the last one, the program displays the “you lost” message, disables all of the keyboard buttons, and makes each label letter display its letter.

If you like you can invent a scoring system for the game and save statistics such as high scores and win/loss percentages in the registry or in program settings.

Also note that the dictionary that the program uses comes from words that are common to several dictionaries. That means a lot of the words are unusual so the game is fairly hard. You can change the dictionary if you like to make the game easier. For example, if you want to give the game to third graders, you might want to use easier words. It might also be interesting to use a domain-specific dictionary containing words about a particular topic such as programming.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, files, games, graphics, strings | Tagged , , , , , , , , , , , , | Leave a comment

Use LINQ to select words of certain lengths from a file in C#

[LINQ]

This example uses LINQ to read a file, remove unwanted characters, select words of a specified length, and save the result in a new file.

Recently I needed a big word list so I searched around for public domain dictionaries. I found one that was close to what I needed in the file 6of12.txt in the 12Dicts package available here. That file has several problems that make it not quite prefect for my use:

  • It contains words that are too short and too long for my purposes.
  • It includes non-alphabetic characters at the end of some words to give extra information about them.
  • Some words contain embedded non-alphabetic characters as in A-bomb and bric-a-brac.

The following code shows how the program processes the file.

// Select words that have the given minimum length.
private void btnSelect_Click(object sender, EventArgs e)
{
    // Remove non-alphabetic characters at the ends of words.
    Regex end_regex = new Regex("[^a-zA-Z]+$");
    string[] all_lines = File.ReadAllLines("6of12.txt");
    var end_query =
        from string word in all_lines
        select end_regex.Replace(word, "");

    // Remove words that still contain non-alphabetic characters.
    Regex middle_regex = new Regex("[^a-zA-Z]");
    var middle_query =
        from string word in end_query
        where !middle_regex.IsMatch(word)
        select word;

    // Make a query to select lines of the desired length.
    int min_length = (int)nudMinLength.Value;
    int max_length = (int)nudMaxLength.Value;
    var length_query =
        from string word in middle_query
        where (word.Length >= min_length) &&
              (word.Length <= max_length)
        select word;

    // Write the selected lines into a new file.
    string[] selected_lines = length_query.ToArray();
    File.WriteAllLines("Words.txt", selected_lines);

    MessageBox.Show("Selected " + selected_lines.Length +
        " words out of " + all_lines.Length + ".");
}

The code starts by using a LINQ query to remove non-alphabetic characters from the ends of words.

It then uses a second LINQ query to select only words that now contain no non-alphabetic characters. (That eliminates A-bomb and bric-a-brac.)

Next a third LINQ query selects words with lengths between those indicated by the user.

Finally the code invokes the final query’s ToArray method to convert the results into an array of words. It then uses File.WriteAllLines to write the words into a new file named Words.txt.

The code finishes by displaying the number of words in the new and original files.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, files, LINQ | Tagged , , , , , , , , , , , | 2 Comments

Draw a golden spiral in C#

[example]

This example shows how to draw a golden spiral (or phi spiral) in C#. The example Draw a nested series of golden rectangles in C# draws nested rectangles and connects their corners to make a square “spiral.” This example makes a smooth spiral.

If you check the Circular Spiral box, the program approximates the phi spiral by using circular arcs. For each square that is removed from a rectangle, it uses the following code to draw an arc connecting two of the square’s corners.

if (chkCircularSpiral.Checked)
{
    // Draw a circular arc from the spiral.
    RectangleF rect;
    switch (orientation)
    {
        case RectOrientations.RemoveLeft:
            rect = new RectangleF(
                (float)x, (float)y,
                (float)(2 * hgt), (float)(2 * hgt));
            gr.DrawArc(Pens.Red, rect, 180, 90);
            break;
        case RectOrientations.RemoveTop:
            rect = new RectangleF(
                (float)(x - wid), (float)y,
                (float)(2 * wid), (float)(2 * wid));
            gr.DrawArc(Pens.Red, rect, -90, 90);
            break;
        case RectOrientations.RemoveRight:
            rect = new RectangleF(
                (float)(x + wid - 2 * hgt),
                (float)(y - hgt), (float)(2 * hgt),
                (float)(2 * hgt));
            gr.DrawArc(Pens.Red, rect, 0, 90);
            break;
        case RectOrientations.RemoveBottom:
            rect = new RectangleF(
                (float)x, (float)(y + hgt - 2 * wid),
                (float)(2 * wid), (float)(2 * wid));
            gr.DrawArc(Pens.Red, rect, 90, 90);
            break;
    }
}

This code simply draws an appropriate arc depending on the position of the square inside its rectangle.

If you check the True Spiral box, the program draws a logarithmic spiral with growth factor φ so its radius increases by a factor of the golden ratio φ for every quarter turn. (Actually I wonder if the growth factor shouldn’t be the factor by which it grows in a complete circle.)

In any case, the program uses the following code to draw a logarithmic spiral.

if (chkTrueSpiral.Checked && points.Count > 1)
{
    // Draw the true spiral.
    PointF start = points[0];
    PointF origin = points[points.Count - 1];
    float dx = start.X - origin.X;
    float dy = start.Y - origin.Y;
    double radius = Math.Sqrt(dx * dx + dy * dy);


    double theta = Math.Atan2(dy, dx);
    const int num_slices = 1000;
    double dtheta = Math.PI / 2 / num_slices;
    double factor = 1 - (1 / phi) / num_slices * 0.78;
    List<PointF> new_points = new List<PointF>();

    // Repeat until dist is too small to see.
    while (radius > 0.1)
    {
        PointF new_point = new PointF(
            (float)(origin.X + radius * Math.Cos(theta)),
            (float)(origin.Y + radius * Math.Sin(theta)));
        new_points.Add(new_point);
        theta += dtheta;
        radius *= factor;
    }
    gr.DrawLines(Pens.Blue, new_points.ToArray());
}

This code sets the spiral’s outermost point to be the first point used by the square spiral. It uses the last point found (where the rectangles become vanishingly small) as the spiral’s origin.

Next the code calculates the factor by which it will reduce the radius for each change in angle dtheta. With a change in angle of π / 2, the radius should ideally decrease by a factor of 1 – (1 / φ). The program divides both dtheta and this factor by num_slices to make a smooth curve.

I honestly don’t know why I need the factor of 0.78 here to make the curve fit the rectangles well. If you leave it out, the curve draws a nice spiral but it lies well inside the rectangles. If you have any ideas, post a comment below.

After setting up the parameters, the program enters a loop where it generates a new point on the spiral and multiplies the spiral’s radius by the scale factor to move to the next point. It continues the loop until the radius becomes too small to see and then connects the points.

With the mystery factor of 0.78, the spiral does a good job of fitting the rectangles. If you draw both spirals at the same time, you’ll see that the circular approximation is remarkably close to the true spiral.

Download the example program to see the rest of the code.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, drawing, graphics, mathematics | Tagged , , , , , , , , , , , , , , | 3 Comments

Draw a nested series of golden rectangles in C#

[golden rectangles]

This program draws golden rectangles, rectangles whose side ratio is equal to φ. For information on φ, see Examine the relationship between the Fibonacci sequence and phi in C#.

The program first draws a golden rectangle. It then removes the square from one end of the rectangle to produce another golden rectangle. It continues removing the squares at the ends of rectangles to make new golden rectangles until the rectangles are too small to see.

The program starts by building a Bitmap and doing some set up such as defining the largest golden rectangle that the program will draw. The most interesting part of the program is the following DrawPhiRectanglesOnGraphics method.

// Draw rectangles on a Graphics object.
private void DrawPhiRectanglesOnGraphics(Graphics gr,
    List<PointF> points, float x, float y, float wid,
    float hgt, RectOrientations orientation)
{
    if ((wid < 1) || (hgt < 1)) return;

    // Draw this rectangle.
    gr.DrawRectangle(Pens.Blue, x, y, wid, hgt);

    // Recursively draw the next rectangle.
    switch (orientation)
    {
        case RectOrientations.RemoveLeft:
            points.Add(new PointF(x, y + hgt));
            x += hgt;
            wid -= hgt;
            orientation = RectOrientations.RemoveTop;
            break;
        case RectOrientations.RemoveTop:
            points.Add(new PointF(x, y));
            y += wid;
            hgt -= wid;
            orientation = RectOrientations.RemoveRight;
            break;
        case RectOrientations.RemoveRight:
            points.Add(new PointF(x + wid, y));
            wid -= hgt;
            orientation = RectOrientations.RemoveBottom;
            break;
        case RectOrientations.RemoveBottom:
            points.Add(new PointF(x + wid, y + hgt));
            hgt -= wid;
            orientation = RectOrientations.RemoveLeft;
            break;
    }
    DrawPhiRectanglesOnGraphics(gr, points,
        x, y, wid, hgt, orientation);
}

If the rectangle is smaller than one pixel wide or tall, the method simply exits. Otherwise it draws the rectangle.

Next the program checks the rectangle’s orientation. The following code shows the RectOrientation enumeration.

// Orientations for the rectangles.
private enum RectOrientations
{
    RemoveLeft,
    RemoveTop,
    RemoveRight,
    RemoveBottom
}

These enumerations determine which part of a golden rectangle to remove. For example, the first rectangle is wider than it is tall. The program removes the square on the rectangle’s left end to create a new smaller rectangle on the right end. That rectangle is taller than it is wide so the program removes the square from its top end.

The DrawPhiRectanglesOnGraphics method uses a switch statement to determine which part of the current rectangle it should remove to make the next one. It also updates the orientation parameter so the next call to DrawPhiRectanglesOnGraphics draws the next rectangle correctly.

The enumeration defines its values in the order in which the program removes the rectangle ends: left, top, right, bottom. That keeps the new rectangles in the center of the original rectangle.

The code in the switch statement also saves an “origin” point for each rectangle in a point list.

After calculating the new rectangle’s size, position, and orientation, the DrawPhiRectanglesOnGraphics method calls itself recursively to draw the next golden rectangle.

After the original call to DrawPhiRectanglesOnGraphics returns, the calling code connects the saved “origin” points to draw a spiral. (I tried drawing the spiral smoothly but a simple call to DrawCurve doesn’t work. More about this in my next post.)


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, drawing, graphics, mathematics | Tagged , , , , , , , , , , , , | 2 Comments