Animate the Tower of Hanoi problem in C#

[Tower of Hanoi]

This example is similar to the example Recursively solve the Tower of Hanoi problem in C# except it uses animation to show how the disks move from one peg to another.

The following AnimateMovement method moves a disk in a straight line from its current location to a new one.

// Move the moving disk to this location.
private void AnimateMovement(int end_x, int end_y)
{
    int start_x = MovingDiskRect.X;
    int start_y = MovingDiskRect.Y;

    const int pixels_per_second = 400;
    float dx = end_x - MovingDiskRect.X;
    float dy = end_y - MovingDiskRect.Y;
    float dist = (float)Math.Sqrt(dx * dx + dy * dy);

    // Calculate distance moved per second.
    dx = pixels_per_second * dx / dist;
    dy = pixels_per_second * dy / dist;

    // See how long the total move will take.
    float seconds = dist / pixels_per_second;
    DateTime start_time = DateTime.Now;

    // Start moving.
    for (; ; )
    {
        // Redraw.
        this.Refresh();

        // Wait a little while.
        System.Threading.Thread.Sleep(10);

        // See how much time has passed.
        TimeSpan elapsed = DateTime.Now - start_time;
        if (elapsed.TotalSeconds > seconds) break;

        // Update the rectangle's position.
        MovingDiskRect.X =
            (int)(start_x + elapsed.TotalSeconds * dx);
        MovingDiskRect.Y =
            (int)(start_y + elapsed.TotalSeconds * dy);
    }

    MovingDiskRect.X = end_x;
    MovingDiskRect.Y = end_y;
}

The code calculates the number of pixels per second it should add to the disk’s X and Y coordinates. It then enters a loop where it adds the needed number of pixels, depending on how much time has elapsed. It pauses 10 milliseconds during each pass through the loop.

The following method uses AnimateMovement to move a disk off of one peg and onto another.

// Animate moving a disk from peg from_peg to peg to_peg.
private void AnimateDiskMove(int from_peg, int to_peg)
{
    // Remove the disk so Paint doesn't draw it.
    int disk_width = PegStack[from_peg].Pop();

    // Move the disk above from_peg.
    int y = PegLocation[from_peg].Bottom -
        (PegStack[from_peg].Count + 1) * (DiskThickness + 2);
    int x = PegLocation[from_peg].X + DiskThickness / 2 -
        disk_width / 2;
    MovingDiskRect = new Rectangle(
        x, y, disk_width, DiskThickness);

    // Move the disk up above the peg.
    int to_y = 10;
    AnimateMovement(x, to_y);

    // Move the disk over the new peg.
    int to_x = PegLocation[to_peg].X + DiskThickness / 2 -
        disk_width / 2;
    AnimateMovement(to_x, to_y);

    // Move the disk down onto the peg.
    to_y = PegLocation[to_peg].Bottom -
        (PegStack[to_peg].Count + 1) * (DiskThickness + 2);
    AnimateMovement(to_x, to_y);

    // Redraw.
    this.Refresh();

    // Add the disk to its new peg.
    MovingDiskRect.X = -1;
    PegStack[to_peg].Push(disk_width);
}

This method removes the top disk from the source peg and calculates its location. It then calls AnimateMovement to move the disk up above the source peg.

Next the code uses AnimateMovement to move the disk over the destination peg. It finishes by using AnimateMovement again to move the disk down onto the destination peg.

Download the example for additional details.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in algorithms, animation, drawing, graphics, multimedia, recursion and tagged , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *