Make silly eyes that track the mouse in C#

[track the mouse]

This example uses a Timer named tmrTick to track the mouse. Its Tick event handler, which is shown in the following code, updates the eyes.

// The previous mouse location.
private Point OldMousePos = new Point(-1, -1);

// See if the mouse has moved.
private void tmrTick_Tick(object sender, EventArgs e)
{
    // See if the cursor has moved.
    Point new_pos = Control.MousePosition;
    if (new_pos.Equals(OldMousePos)) return;
    OldMousePos = new_pos;

    // Redraw.
    this.Invalidate();
}

The Tick event handler uses the MousePosition method to track the mouse position. If the position has changed since the last time this event handler ran, the code invalidates the form to make the following Paint event handler redraw the form.

// Draw the eyes.
private void Form1_Paint(object sender, PaintEventArgs e)
{
    DrawEyes(e.Graphics);
}

The Paint event handler simply calls the DrawEyes method shown in the following code.

// Draw the eyes.
private void DrawEyes(Graphics gr)
{
    // Convert the cursor position into form units.
    Point local_pos = this.PointToClient(OldMousePos);

    // Calculate the size of the eye.
    int hgt = (int)(this.ClientSize.Height * 0.9);
    int wid = (int)(this.ClientSize.Width * 0.45);

    // Find the positions of the eyes.
    int y = (this.ClientSize.Height - hgt) / 2;
    int x1 = (int)((this.ClientSize.Width - wid * 2) / 3);
    int x2 = wid + 2 * x1;

    // Create a Bitmap on which to draw.
    gr.SmoothingMode = SmoothingMode.AntiAlias;
    gr.Clear(this.BackColor);

    // Draw the eyes.
    DrawEye(gr, local_pos, x1, y, wid, hgt);
    DrawEye(gr, local_pos, x2, y, wid, hgt);
}

The DrawEyes method performs some calculations to see where the eyes should be drawn so they track the mouse position. It uses the PointToClient method to convert the mouse’s position into the form’s coordinate system. It then calculates the size for the eyes, determines their positions, and calls the following DrawEye method twice to actually draw the eyes.

private Pen ThickPen = new Pen(Color.Black, 3);
...
// Draw an eye here.
private void DrawEye(Graphics gr, Point local_pos,
    int x1, int y1, int wid, int hgt)
{
    // Draw the outside.
    gr.FillEllipse(Brushes.White, x1, y1, wid, hgt);
    gr.DrawEllipse(ThickPen, x1, y1, wid, hgt);

    // Find the center of the eye.
    int cx = x1 + wid / 2;
    int cy = y1 + hgt / 2;

    // Get the unit vector pointing towards the mouse position.
    double dx  = local_pos.X - cx;
    double dy  = local_pos.Y - cy;
    double dist  = Math.Sqrt(dx * dx + dy * dy);
    dx /= dist;
    dy /= dist;

    // This point is 1/4 of the way
    // from the center to the edge of the eye.
    double px = cx + dx * wid / 4;
    double py = cy + dy * hgt / 4;

    // Draw an ellipse 1/2 the size of the eye
    // centered at (px, py).
    gr.FillEllipse(Brushes.Blue, (int)(px - wid / 4),
        (int)(py - hgt / 4), wid / 2, hgt / 2);
}

The DrawEye method draws a white exterior for an eye. It then calculates a unit vector pointing from the eye’s center towards the mouse’s current position. It moves along this direction 1/4 of the way from the eye’s center to its edge. The routine then draws the pupil centered at this position.

If you run the program, you will probably notice a slight flicker as the eyes move. In my next post I’ll show you the amazingly easy way to fix that. See if you can figure out how to fix it before you read the next post.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in games, geometry, graphics | Tagged , , , , , , , , , , , , | Leave a comment

Compare the performance of simple arithmetic operations in C#

[performance]

I saw a post the other day that said division was the slowest arithmetic operation so I wrote this example to see exactly how the performance of multiplication, division, addition, and subtraction differ with floating point numbers.

When you click the Go button, the program executes loops that test each of the operations. The following code shows how the program tests the performance of multiplication.

Stopwatch watch = new Stopwatch();
int num_trials = int.Parse(txtNumTrials.Text);
float x = 13, y, z;

y = 1 / 7f;
watch.Start();
for (int i = 0; i < num_trials; i++)
{
    z = x * y;
}
watch.Stop();
txtTimeMult.Text = watch.Elapsed.TotalSeconds.ToString("0.00") +
    " secs";

The other loops are similar. If you look closely at the picture, you’ll see that division is indeed the slowest of the four operations. Multiplication, addition, and subtraction all have roughly the same performance.

Note that all of the operations are extremely fast. Even division took only 3.41 seconds to perform 1 billion trials, so in most programs the difference in performance doesn’t matter much. If your program must perform a huge number of operations, however, you may gain a slight performance increase if you use multiplication instead of division. For example, instead of dividing by 4, you could multiply by 0.25.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in mathematics, performance | Tagged , , , , , , , , , , , | 1 Comment

Make a 3D globe in WPF and C#

[3D globe]

This example shows how you can draw a 3D globe. More generally it shows how you can make a three-dimensional textured sphere in WPF.

The example Draw smooth spheres using WPF and C# shows how to make smooth colored spheres. This example modifies that technique to make a textured sphere.

The following code shows how the example program builds the 3D globe.

// Add the model to the Model3DGroup.
private void DefineModel(Model3DGroup model_group)
{
    // Globe. Place it in a new model so we can transform it.
    Model3DGroup globe_model = new Model3DGroup();
    model_group.Children.Add(globe_model);

    ImageBrush globe_brush = new ImageBrush(new BitmapImage(
        new Uri("pack://application:,,,/world.jpg")));
    Material globe_material = new DiffuseMaterial(globe_brush);
    MeshGeometry3D globe_mesh = null;
    MakeSphere(globe_model, ref globe_mesh, globe_material,
        1, 0, 0, 0, 20, 30);
}

This code creates a Model3DGroup to hold the 3D globe and adds it to the program’s model group.

Next the code creates a brush that uses the image file world.jpg. It uses the brush to make a material for the 3D globe and then calls the MakeSphere method to create the sphere.

The code shows the MakeSphere method.

// Make a sphere.
private void MakeSphere(Model3DGroup model_group,
    ref MeshGeometry3D sphere_mesh, Material sphere_material,
    double radius, double cx, double cy, double cz, int num_phi,
    int num_theta)
{
    // Make the mesh if we must.
    if (sphere_mesh == null)
    {
        sphere_mesh = new MeshGeometry3D();
        GeometryModel3D new_model =
            new GeometryModel3D(sphere_mesh, sphere_material);
        model_group.Children.Add(new_model);
    }

    double dphi = Math.PI / num_phi;
    double dtheta = 2 * Math.PI / num_theta;

    // Remember the first point.
    int pt0 = sphere_mesh.Positions.Count;

    // Make the points.
    double phi1 = Math.PI / 2;
    for (int p = 0; p <= num_phi; p++)
    {
        double r1 = radius * Math.Cos(phi1);
        double y1 = radius * Math.Sin(phi1);

        double theta = 0;
        for (int t = 0; t <= num_theta; t++)
        {
            sphere_mesh.Positions.Add(new Point3D(
                cx + r1 * Math.Cos(theta),
                cy + y1,
                cz + -r1 * Math.Sin(theta)));
            sphere_mesh.TextureCoordinates.Add(new Point(
                (double)t / num_theta, (double)p / num_phi));
            theta += dtheta;
        }
        phi1 -= dphi;
    }

    // Make the triangles.
    int i1, i2, i3, i4;
    for (int p = 0; p <= num_phi - 1; p++)
    {
        i1 = p * (num_theta + 1);
        i2 = i1 + (num_theta + 1);
        for (int t = 0; t <= num_theta - 1; t++)
        {
            i3 = i1 + 1;
            i4 = i2 + 1;
            sphere_mesh.TriangleIndices.Add(pt0 + i1);
            sphere_mesh.TriangleIndices.Add(pt0 + i2);
            sphere_mesh.TriangleIndices.Add(pt0 + i4);

            sphere_mesh.TriangleIndices.Add(pt0 + i1);
            sphere_mesh.TriangleIndices.Add(pt0 + i4);
            sphere_mesh.TriangleIndices.Add(pt0 + i3);
            i1 += 1;
            i2 += 1;
        }
    }
}

The method starts by creating a mesh if necessary. It then uses spherical coordinates to generate points on the sphere. It loops through phi values between 0 and π/2, and theta values between 0 and 2π.

As it generates the points, it adds them to the mesh’s Positions collection. It also adds their texture coordinates to the mesh’s TextureCoordinates collection. The texture coordinates are scaled so they range from 0 to 1 for the phi and theta values.

After is finishes defining the points, the code loops through the phi and theta values again and defines the sphere’s triangles. It takes some non-trivial bookkeeping to keep track of which points should be combined to make the triangles.

Because adjacent triangles share vertices, the sphere is smooth.

It may not be obvious, but finding a good image to wrap around the sphere is one of the harder parts of the program. This example uses the best globe image I could find after a fair amount of searching.

[3D globe]

When the program is working with the top and bottom of the sphere, the trapezoids it uses to build the sphere degenerate into triangles as shown in the picture on the right. That means the texture image fits the sides reasonably well but it probably won’t fit the top or bottom very well.



There are several ways you can address that problem.

[3D globe]

  • You can use a lot of phi values. That makes the triangles at the sphere’s top and bottom smaller so any mismatch is smaller.
  • You can pick a texture image that has a solid color at the top and bottom. If the triangles are solid colors, then they will match up well.
  • You can explicitly pick a texture designed to exactly fit the sphere. Its top and bottom would be warped to fit triangular areas. Unfortunately mapping the points to places on the warped image would be hard.
  • You could use a geodesic tiling of the sphere. In theory that would provide the best result but I don’t even know where you would get a texture map for that.
  • You can just ignore the issue. If the texture is chaotic, the user probably won’t notice.

This is why there are so many different kinds of maps of the globe. None of them are perfectly accurate everywhere. The most accurate map of the Earth is a globe.

This example relies on the fact that the North Pole is mostly water, the South Pole is mostly land, and that most people don’t really know what the poles look like in detail.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in algorithms, drawing, geometry, graphics, mathematics, wpf, XAML | Tagged , , , , , , , , , , , , , , , , | Leave a comment

Graph event probabilities in C#

[event probabilities]

The example Calculate the probability of an event occurring in a given number of trials in C# shows how to calculate event probabilities. This example graphs the results. You can use the example to get some feel for how the probabilities change.

Enter the event probability and the maximum number of trials to perform. When you click Go, the program executes the following code.

// The probability data.
private PointF[] Points = {};

// Calculate and display probabilities.
private void btnGo_Click(object sender, EventArgs e)
{
    // Make room for the probabilities.
    int num_events = int.Parse(txtMaxNumberEvents.Text);
    Points = new PointF[num_events + 1];

    // Get the event probability.
    double event_prob =
        double.Parse(txtEventProb.Text.Replace("%", ""));
    if (txtEventProb.Text.Contains("%")) event_prob /= 100.0;

    // Get the probability of the event not happening.
    double non_prob = 1.0 - event_prob;

    for (int i = 0; i <= num_events; i++)
    {
        Points[i].X = i;
        Points[i].Y = 100 * (float)(1.0 - Math.Pow(non_prob, i));
    }

    // Redraw.
    picGraph.Refresh();
}

The Points array holds the data for the current probability parameters. The Go button’s Click event handler parses the number of events you entered and makes the Points array big enough to hold the event probabilities. The code then parses the event probability and converts it into a decimal value (as in 0.5 instead 50%).

Next the code loops over the desired events calculating the event probabilities and saving the results in the Points array. For drawing convenience, the code stores the probability value as a percentage.

After it has calculated all of the event probabilities, the code refreshes the picGraph PictureBox to make it display the results. The following code shows how the picGraph control’s Paint event handler draws the graph.

// Draw the data.
private void picGraph_Paint(object sender, PaintEventArgs e)
{
    // Clear.
    e.Graphics.Clear(picGraph.BackColor);
    if (Points.Length < 2) return;
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

    // Transform from world coordinates to screen coordinates.
    RectangleF rect = new RectangleF(0, 0, Points.Length + 1, 100);
    PointF[] pts =
    {
        new PointF(0, picGraph.ClientSize.Height),
        new PointF(picGraph.ClientSize.Width,
                   picGraph.ClientSize.Height),
        new PointF(0, 0)
    };
    Matrix transform = new Matrix(rect, pts);

    using (Pen pen = new Pen(Color.Gray, 0))
    {
        // Draw the axes.
        using (StringFormat sf = new StringFormat())
        {
            sf.LineAlignment = StringAlignment.Center;
            for (int i = 0; i <= 100; i += 10)
            {
                // See where this should be.
                pts = new PointF[]
                {
                    new PointF(0, i),
                    new PointF(Points.Length, i),
                };
                transform.TransformPoints(pts);
                e.Graphics.DrawLine(pen, pts[0], pts[1]);
                e.Graphics.DrawString(i.ToString(), this.Font,
                    Brushes.Green, pts[0], sf);
            }

            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Far;
            int skip = (int)(Points.Length / 10);
            skip = 5 * (int)(skip / 5);
            if (skip < 1) skip = 1;
            for (int i = 0; i < Points.Length; i += skip)
            {
                // See where this should be.
                pts = new PointF[]
                {
                    new PointF(i, 0),
                    new PointF(i, 5),
                };
                transform.TransformPoints(pts);
                e.Graphics.DrawLine(pen, pts[0], pts[1]);
                e.Graphics.DrawString(i.ToString(), this.Font,
                    Brushes.Green, pts[0], sf);
            }
        }

        // Draw the graph.
        pen.Color = Color.Blue;
        e.Graphics.Transform = transform;
        e.Graphics.DrawLines(pen, Points);
    }
}

This code first clears the PictureBox. Then if there are no data points it simply returns.

The code then creates a transformation matrix to transform the data to fit the PictureBox. To do that it creates a RectangleF representing the points’ world coordinate bounds. Those ranges from 0 to 100 in the Y direction (the percentages) and 0 to the number of events in the X direction.

The code also creates an array of points indicating where on the PictureBox the upper left, upper right, and lower left corners of the world coordinate bounds should be mapped. It uses the RectangleF and the array of points to create a Matrix that maps from world coordinates to PictureBox coordinates.

The program then draws the graph. It creates a thin pen to draw with and makes a StringFormat object for use when drawing text.

Next the code draws horizontal lines for every multiple 10% probability. It draws a line connecting the points (0, i) - (Points.Length, i) for i = 10, 20, 30, and so forth. To do this, the code must transform the coordinates of the points so they match up with the transformed points in the graph. It does that by calling the transformation matrix’s TransformPoints method.

After it draws each horizontal line, the code also draws text giving the line’s probability. It positions the text at the line’s left end point (0, i) and centered vertically on the line.

Next the code draws the X axis. It loops over values between 0 and the number of events drawing vertical tick marks and the event numbers.

After drawing the axes and their labels, drawing the actual graph is simple. The code applies the transformation matrix to the Graphics object and calls that object’s DrawLines method to draw the lines.

When you resize the form, the PictureBox control’s Resize event handler also refreshes the PictureBox so you can make the graph bigger if you like.


Download Example   Follow me on Twitter   RSS feed   Donate




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

Find the number of trials for an event probability in C#

[probability]

The post Understand probabilities of unrelated events (and escaping zombies) explains how to calculate the number of trials necessary to reach a certain probability of an event occurring. It explains that if an event has a probability P of occurring at each trial, then after N trials the probability that at least one trial resulted in the event is 1 – (1 – P)N.

Suppose you want to know how many trials are necessary for this probability to equal some value Q so Q = 1 – (1 – P)N. Solving for N gives N = Log(1 – P)(1 – Q).

This example uses the following code to calculate this number of trials.

// See how many trials it takes to get to the target probability.
private void btnGo_Click(object sender, EventArgs e)
{
    lvwResults.Items.Clear();

    // See if the event probability contains a % sign.
    bool percent = txtEventProb.Text.Contains("%");

    // Get the event and target probabilities.
    double event_prob = ParseProbability(txtEventProb.Text);
    double target_prob = ParseProbability(txtTargetProb.Text);

    // Get the probability of the event not happening.
    double non_prob = 1 - event_prob;

    // target_prob = 1 - non_prob ^ power. Solving for power gives
    // power = Log(1 - target_prob) base non_prob.
    double calculated_trial = Math.Log(1 - target_prob, non_prob);

    // Display probaility for 1 less trial.
    double trial = (int)calculated_trial;
    double prob = 1.0 - Math.Pow(non_prob, trial);
    DisplayTrial(trial, prob, percent);

    // Display probaility for the calculated trial.
    trial = calculated_trial;
    prob = 1.0 - Math.Pow(non_prob, trial);
    DisplayTrial(trial, prob, percent);

    // Display probaility for 1 more trial.
    trial = (int)calculated_trial + 1;
    prob = 1.0 - Math.Pow(non_prob, trial);
    DisplayTrial(trial, prob, percent);
}

The user enters the event probability and the desired target probability and clicks Go. The code determines whether the event probability contains a % sign to decide whether it should display values as percentages (50%) or decimal values (0.5). It then calls the ParseProbability method to read the event and target probabilities.

Next the code calculates 1 minus the event probability, 1 – P in the equations shown above. It uses the equation N = Log(1 – P)(1 – Q) to calculate the number of trials necessary to reach the target probability. Finally the program uses the DisplayTrial method to display the probability for the calculated number of trials plus the probabilities of the next smaller and larger integer number of trials. For example, if the calculated result is 68.9 trials, the program displays the probability for that number of trials plus those for 68 and 69 trials.

The following code shows the ParseProbability method that reads the probability values entered by the user.

// Parse a probability that may include a percent sign.
private double ParseProbability(string txt)
{
    // See if the probability contains a % sign.
    bool percent = txt.Contains("%");

    // Get the probability.
    double prob = double.Parse(txt.Replace("%", ""));

    // If we're using percents, divide by 100.
    if (percent) prob /= 100.0;

    return prob;
}

This method determines whether the text includes a % sign and converts the text into a number. If the text includes the % sign, the method divides the result by 100 to return a decimal value (for example, 0.25 instead of 25%).

The following code shows the DisplayTrial method that displays a trials number and a probability in the form’s ListView control.

// Display a trial and its probability.
private void DisplayTrial(double trial, double prob, bool percent)
{
    ListViewItem new_item = lvwResults.Items.Add(trial.ToString());
    if (percent)
    {
        prob *= 100.0;
        new_item.SubItems.Add(prob.ToString() + "%");
    }
    else
    {
        new_item.SubItems.Add(prob.ToString());
    }
}

The code creates a new ListViewItem to display the number of trials. It then creates a subitem to show the corresponding probability. If the boolean parameter percent is true, the code formats the probability as a percentage (30%) instead of as a decimal value (0.30).


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in mathematics | Tagged , , , , , , , , | Leave a comment

Calculate the probability of an event occurring in a given number of trials in C#

[probability]

The post Understand probabilities of unrelated events (and escaping zombies) explains how to calculate the probability of an event occurring in a certain number of trials. It explains that if an event has a probability P of occurring at each trial, then after N trials the probability that at least one trial resulted in the event is 1 – (1 – P)N.

This example uses the following code to list probabilities of an event after a given numbers of trials.

// Calculate and display probabilities.
private void btnGo_Click(object sender, EventArgs e)
{
    // See if the probability contains a % sign.
    bool percent = txtEventProb.Text.Contains("%");

    // Get the event probability.
    double event_prob =
        double.Parse(txtEventProb.Text.Replace("%", ""));

    // If we're using percents, divide by 100.
    if (percent) event_prob /= 100.0;

    // Get the probability of the event not happening.
    double non_prob = 1.0 - event_prob;

    lvwResults.Items.Clear();
    for (int i = 0; i <= 100; i++)
    {
        double prob = 1.0 - Math.Pow(non_prob, i);
        ListViewItem new_item = lvwResults.Items.Add(i.ToString());

        if (percent)
        {
            prob *= 100.0;
            new_item.SubItems.Add(prob.ToString("0.0000") + "%");
        }
        else
        {
            new_item.SubItems.Add(prob.ToString("0.000000"));
        }
    }
}

The code first determines whether the probability entered by the user contains the % symbol. If it does, then the program displays its output as a percentage. Otherwise it assumes the probabilities are entered as decimals values less than 1.

The code then parses the probability entered by the user and converts it into a value less than 1 if it is a percentage.

The code subtracts the probability from 1 to get the probability of the event not occurring and then enters a loop. For i = 0 to 100 the program calculates 1 minus the probability of the event not occurring to the ith power, converts the result into a percentage if necessary, and displays the result in a ListView control.

If you look closely at the picture, you’ll see that the probability of a 1% event occurring after 100 trials is about 63%.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in mathematics | Tagged , , , , , , , , | 1 Comment

Understand probabilities of unrelated events (and escaping zombies)

[probability]

Given some event with a relatively low probability, what is the probability that the event will occur if you perform many trials? For example, suppose the zombie apocalypse has arrived and there’s a 1% chance that the zombies will get you with every trip you make to the store for supplies. What’s the probability that they get you if you go 10 times? 100 times? How many trips would you need to make before the probability of being caught is 50%?

For a more intuitive example, consider coin flips. At every flip, there’s a 50% chance that you’ll get heads. What is the probability that you’ll get at least one heads in 2 flips? 5 flips?

To figure this out, you need to know a little bit about the probabilities of multiple events. If two events (such as two coin flips) are unrelated, then the probability of getting a specific result in one event AND another is the product of the probabilities of getting the events separately.

For example, what is the probability of getting heads in a coin flip and then getting heads again in a second flip? There’s a 50% or 0.5 probability of getting heads on each flip, so the probability of getting heads and then heads again is 0.5 * 0.5 = 0.25.

This also makes sense if you consider all of the possible combinations of flips. You could get: HH, HT, TH, or TT. There are 4 possible outcomes and only 1 is the one you’re looking for (HH) so the probability is 1/4 = 0.25.

Now consider a case more similar to the original zombie scenario. If you flip a coin twice, what is the probability that you get heads in the first flip OR in the second flip? In other words, in two coin flips what is the probability that at least 1 will be heads? Many people intuitively think that you can add the probabilities of the two separate events. In this case, that would be 0.5 + 0.5 = 1. Clearly that’s not right because a probability of 1 means the result must occur, but clearly there is a chance that you will not get heads in two flips.

Looking at the possible outcomes (HH. HT, TH, TT) you can see that 3 of the 4 possible outcomes includes at least one heads, so the probability should be 3/4 = 0.75.

So how do you figure this out mathematically? The key is to look at the logical operator words AND and OR. Suppose you have two events E1 and E2 with probabilities P1 and P2. The probability of E1 and E2 is P1 * P2. Simple. Unfortunately you cannot simply add probabilities to find the probability of E1 or E2.

Fortunately there’s a way around this. Logically E1 or E2 is equivalent to NOT ((NOT E1) AND (NOT E2)). For example, Heads OR Heads is equivalent to NOT (Tails AND Tails). (You may need to think about this for a while to convince yourself.)

We already know you can calculate the AND probability by multiplying two probabilities. Fortunately handling the NOTs is also easy. If an event has probability P, then the probability of the event not occurring is 1 – P.

To get back to the E1/E2 example, this means the probability of E1 OR E2 is 1 – ((1 – P1) * (1 – P2)).

For coin flips, this gives 1 – (0.5 * 0.5) = 1 – 0.25 = 0.75, which we saw earlier was correct.

You can use the same approach for greater numbers of events. For example, the probability of getting heads at least once in 3 coin flips is 1 – (0.5 * 0.5 * 0.5) = 1 – 0.875.

In general if an event has a probability P of occurring at each trial, then after N trials the probability that at least one trial resulted in the event is 1 – (1 – P)N.

Now we can finally get back to the zombie problem. If the probability of getting caught in 1 trip to the store is 0.01, then the probability of NOT getting caught is 0.99. That means the probability of not caught in two trips it’s 1 – (probability of NOT getting caught)2 = 1 – 0.992 = 0.0199. In three trips it’s 1 – 0.993 = 0.029701. In general the probability of being caught after N trips is 1 – 0.99N.

Trips % Caught
1 1.00%
2 1.99%
3 2.97%
4 3.94%
5 4.90%
6 5.85%
7 6.79%
8 7.73%
9 8.65%
10 9.56%

So the next question is, how many trips do you need to make before the probability of getting caught is 50%? The equation for the probability is 0.5 = 1 – 0.99N. Solving for N gives N = Log0.99(1 – 0.5) = 68.967563. Because you can’t make fractional trips (well, I suppose it would be a fractional trip if you got caught halfway there), the probability of being caught is less than 50% after 68 trips and more than 50% after 69 trips.

In the next couple of days, I’ll post programs to perform these calculations. If you want, you can try to write programs to calculate these on your own first.


Follow me on Twitter   RSS feed   Donate




Posted in mathematics | Tagged , , , , , , , , , | 2 Comments

Display reusable dialog forms in C#

[dialog]

The example Make a dialog with standard dialog features in C# shows the most common approach to making dialogs. Whenever it needs to display the dialog, the main program initializes a new instance of it and displays it. If the user clicks OK, the main program saves the dialog’s values.

This example shows another approach. Here the program creates an instance of the dialog when the main program starts and then it reuses the same instance whenever it needs to display the dialog.

If the main program is going to be able to reuse the dialog, the dialog cannot be destroyed when the users closes it. Instead of destroying the dialog, the program hides it so it can be reused later.

To let the user hide the dialog, it displays a Hide button that executes the following code.

// Hide the dialog.
private void btnHide_Click(object sender, EventArgs e)
{
    this.Hide();
}

The user could still try to close the dialog in other ways such as pressing Alt+F4 or clicking the X button in the form’s title bar. One way to prevent that is to set the dialog’s ControlBox property to false to remove the X, minimize, and maximize buttons. This works well if you don’t need to allow the user to minimize or maximize the dialog, but it’s inconvenient if the user may want to make the dialog really big.

This example takes another approach. It uses the following code to catch the dialog’s FormClosing event.

// Don't close, hide.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    e.Cancel = true;
    this.Hide();
}

This code cancels the close and then hides the dialog instead of closing it.

The following code shows how the main program displays the dialog.

// The reusable form.
private ReusableForm TheReusableForm = new ReusableForm();

// Display the reusable form.
private void btnReusableForm_Click(object sender, EventArgs e)
{
    TheReusableForm.Show();
    TheReusableForm.Activate();
}

The class-level variable TheReusableForm holds a reference to the dialog and is initialized when the form loads.

When you click the Reusable Form button, the event handler displays the dialog and then calls its Activate method. That method sets focus to the dialog and pops it to the top. That is useful if the form is already visible and possibly behind the program’s main form or another program on the desktop.

You could pass the main form into the Show method to make the main form the dialog’s owner but that causes some problems. The trickiest is that the main form won’t close until its owned forms close. Because the dialog’s FormClosing event handler doesn’t allow the dialog to close, this is a problem. Working around that issue is a big enough hassle that it’s probably not worth it.

So why would you use this technique instead of the previous one that uses a new instance of the dialog every time it is needed? This method has the advantage that the dialog is displayed non-modally so the user could keep it up in the background at all times. (Note that you could also display it modally if you like.) That might make it useful for displaying and setting parameters that are used by the main program.

This technique also doesn’t require the main program to copy settings into and out of the dialog whenever it is displayed. That may be useful if the settings on the dialog are very complex and take a while to set up.

However, this technique is somewhat awkward and requires extra coordination between the main program and the dialog.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in dialogs, user interface | Tagged , , , , , , , , , , , | Leave a comment

Make a TextBox with auto-complete in C#

[auto-complete]

It’s not too hard to make a TextBox provide an auto-complete feature. In fact, the TextBox control offers three auto-complete styles. This example demonstrates those styles.

To provide auto-complete, you need to set the following three TextBox properties.

  • AutoCompleteMode – This indicates the style that TextBox uses. The options are:
    • None – The user types everything.
    • Append – The TextBox fills in a suggestion. The user can press Tab to accept the suggestion.
    • Suggest – The TextBox displays a dropdown holding possible matches. The user can arrow down to a choice and press Tab to accept it.
    • SuggestAppend – The TextBox both fills in a suggestion and displays a dropdown.
  • AutoCompleteSource – This indicates where the TextBox gets its auto-complete values. The options are:
    • None – The control doesn’t provide auto-complete.
    • FileSystem – Uses the file system.
    • FileSystemDirectories – Uses directories in the file system.
    • HistoryList – Uses URIs in the history list.
    • RecentlyUsedList – Uses most recently used URIs in the history list.
    • AllUrl – HistoryList plus RecentlyUsedList.
    • AllSystemSources – FileSystem plus AllUrl.
    • CustomSource – An AutoCompleteStringCollection provided by the code. This is the value demonstrated by this example.
  • AutoCompleteCustomSource The AutoCompleteStringCollection to use when AutoCompleteSource is CustomSource.

When the program starts, it uses the following code to prepare the program’s TextBox controls.

private void Form1_Load(object sender, EventArgs e)
{
    // Make the collection of day names.
    AutoCompleteStringCollection day_source =
        new AutoCompleteStringCollection();
    day_source.AddRange(Enum.GetNames(typeof(DayOfWeek)));

    // Prepare the TextBox.
    PrepareTextBox(txtAppend, day_source, AutoCompleteMode.Append);
    PrepareTextBox(txtSuggest, day_source, AutoCompleteMode.Suggest);
    PrepareTextBox(txtSuggestAppend, day_source,
        AutoCompleteMode.SuggestAppend);
}

This code creates a new AutoCompleteStringCollection object. It then uses Enum.GetNames to get the names of the days of the week from the DayOfWeek enumeration and adds them to the source.

The code then calls the following PrepareTextBox method for three of the program’s TextBox controls.

// Prepare a TextBox for auto-completion.
private void PrepareTextBox(TextBox txt, 
    AutoCompleteStringCollection source, AutoCompleteMode mode)
{
    txt.AutoCompleteSource = AutoCompleteSource.CustomSource;
    txt.AutoCompleteCustomSource = source;
    txt.AutoCompleteMode = mode;
}

This method simply sets the TextBox control’s auto-complete properties.

Download the example and experiment with it to see which auto-complete style you prefer.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, user interface | Tagged , , , , , , , , , | Leave a comment

Compare the performance of the int, long, and byte data types in C#

[performance]

The example Compare the performance of the float, double, and decimal data types in C# compares the performance of the float, double, and decimal data types. This example performs a similar test for the int, long, and byte data types.

When you enter the number of trials that you want to perform and click the Go button, the following code executes.

// Compare performances.
private void btnGo_Click(object sender, EventArgs e)
{
    txtTimeFloat.Clear();
    txtTimeInt.Clear();
    txtTimeLong.Clear();
    txtTimeByte.Clear();
    Cursor = Cursors.WaitCursor;
    Refresh();

    int num_trials = int.Parse(txtNumTrials.Text);
    Stopwatch watch = new Stopwatch();
    float float1, float2, float3;
    int int1, int2, int3;
    long long1, long2, long3;
    byte byte1, byte2, byte3;

    watch.Start();
    int float_trials = num_trials / 10;
    for (int i = 0; i < num_trials; i++)
    {
        float1 = 1.23f;
        float2 = 4.56f;
        float3 = float1 / float2;
    }
    watch.Stop();
    txtTimeFloat.Text = "~" +
        (10 * watch.Elapsed.TotalSeconds).ToString() + " sec";
    txtTimeFloat.Refresh();

    watch.Reset();
    watch.Start();
    for (int i = 0; i < num_trials; i++)
    {
        int1 = 7331;
        int2 = 1337;
        int3 = int1 / int2;
    }
    watch.Stop();
    txtTimeInt.Text =
        watch.Elapsed.TotalSeconds.ToString() + " sec";
    txtTimeInt.Refresh();

    watch.Reset();
    watch.Start();
    for (int i = 0; i < num_trials; i++)
    {
        long1 = 73317331;
        long2 = 13371337;
        long3 = long1 / long2;
    }
    watch.Stop();
    txtTimeLong.Text =
        watch.Elapsed.TotalSeconds.ToString() + " sec";
    txtTimeLong.Refresh();

    watch.Reset();
    watch.Start();
    for (int i = 0; i < num_trials; i++)
    {
        byte1 = 231;
        byte2 = 123;
        byte3 = (byte)(byte1 / byte2);
    }
    watch.Stop();
    txtTimeByte.Text =
        watch.Elapsed.TotalSeconds.ToString() + " sec";
    txtTimeByte.Refresh();

    Cursor = Cursors.Default;
}

The most interesting part of the code performs a simple mathematical operation inside loops for each of the data types. The program also executes a similar loop for the float data type for comparison. Because the float loop is a lot slower than those that use the other data types, the code divides the number of iterations by 10 for float and then multiplies the elapsed time by 10.

Before running the program I thought that int would be faster than long, but I didn’t expect int to take only a third as long as long. I also didn’t expect the byte data type to have roughly the same performance as the int data type.

Note that operations involving byte always return the int data type so the code must cast the result back into the byte data type. Even with the extra cast operation, byte is about as fast as int.

The moral is, use the int type instead of long if you can. (Note that the results may be different on different computers.)


Download Example   Follow me on Twitter   RSS feed   Donate




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