13,149,073 members (49,129 online)
Tip/Trick
alternative version

#### Stats

15.4K views
3 bookmarked
Posted 18 Oct 2013

# Hanoi Tower

, 18 Oct 2013
 Rate this:
A full functional Hanoi Tower game base on WPF

## Introduction

The Tower of Hanoi (also called the Tower of Brahma or Lucas' Tower,[1] and sometimes pluralised) is a mathematical game or puzzle. It consists of three rods, and a number of disks of different sizes which can slide onto any rod. The puzzle starts with the disks in a neat stack in ascending order of size on one rod, the smallest at the top, thus making a conical shape.

The objective of the puzzle is to move the entire stack to another rod, obeying the following rules:

• Only one disk must be moved at a time.
• Each move consists of taking the upper disk from one of the rods and sliding it onto another rod, on top of the other disks that may already be present on that rod.
• No disk may be placed on top of a smaller disk.

With three disks, the puzzle can be solved in seven moves.

This article is not talking about the algorithm but the real game. This is WPF based and present a friendly GUI and control. You can use keyboard to move and drop disks. Let’s see how fast you can solve the Hanoi tower. I found that we already had some Hanoi projects here in past 8 years implemented by C++, VB.NET etc, however, this is the first WPF version and it even contains human voice! (TTS may not work in OS under Windows Vista) J Have fun.

## Background

I am interest in the 2D/Animation/Movie part. WPF structure is totally different from C# Winform, I encountered many problems when I try to apply my winform experience on WPF application. They are:

1. Where is the Left, Top properties? How can I move a form control in WPF?

We need to use Canvas.SetLeft/SetTop methods, Canvas is kind of root panel which supports absolutely location for controls (Elements).

2. How to add an image to an Image control programmingly?

In WPF, it calls uri. We need to set the image uri to Image.Source property.

3. Dispatcher Timer vs Timer

Dispatcher Timer, in a word, it can invoke UI Controls in the same thread. But original Timer can’t.

## Using the code

The code has been refactored from the original mess up. So I will show some code points here since the source code is simple to read. I think...

I create a class to describe the Tower which contains disks. Here I use Stack<int> to simulate it. Int represents the disk size.

`Stack<int> Tower1 = new Stack<int>();`

To move the disk between two columns, I compare the int numbers and use Stack.Pop and Stack.Push to simulate the moving. Atually Stack is really suitable because it is FILO like the real Hanoi Disks moving policy.

```public bool Move(Towers from, Towers to)
{
int fromStep = 0;
int toStep = 0;

Stack<int> fromTower = GetTower(from); ;
Stack<int> toTower = GetTower(to); ;

if (fromTower.Count < 1) return false;

fromStep = fromTower.Peek();

if (toTower.Count < 1) toStep = 10;
else toStep = toTower.Peek();

if (fromStep < toStep)
{
toTower.Push(fromTower.Pop());
return true;
}
else if (fromStep == toStep)
{
return true;
}
else
{
return false;
}
}
```

I try to decouple the logic from GUI, so I run the logic inside HanoiTowerClass and draw GUI everytime anything changes.

```private void RedrawTower(List<int> tower, int columns)
{
int j = 0;
for (int i = tower.Count - 1; i >= 0; i--)
{
Canvas.SetTop(rects[tower[i] - 1], Constant.BottomTop - Constant.StepThickness * ++j);
Canvas.SetLeft(rects[tower[i] - 1], Constant.ColumnWidth * columns - rects[tower[i] - 1].Width / 2 + Constant.Offset);
}
}

private void RedrawEnvironment()
{
List<int> towerLeft = tower.GetTowerLeft();
List<int> towerMiddle = tower.GetTowerMiddle();
List<int> towerRight = tower.GetTowerRight();

RedrawTower(towerLeft, 1);
RedrawTower(towerMiddle, 2);
RedrawTower(towerRight, 3);

Canvas.SetLeft(hand, Constant.ColumnWidth * (handPosition + 1));
Canvas.SetTop(hand, Constant.HandTop);

if (holdStep > 0)
{
Canvas.SetTop(rects[holdStep - 1], Constant.HandTop);
Canvas.SetLeft(rects[holdStep - 1], (handPosition + 1) * Constant.ColumnWidth - rects[holdStep - 1].Width / 2);
}
}
```

In Windows_KeyDown events, we can catch the user input and do some job:

```if (e.Key == Key.A || e.Key == Key.Left) //move left
{
if (handPosition > 0)
handPosition--;
else
handPosition = 2;
}
else if (e.Key == Key.D || e.Key == Key.Right) //move right
{
if (handPosition > 1)
handPosition = 0;
else
handPosition++;
}
else if (e.Key == Key.J || e.Key == Key.S || e.Key == Key.Down) // hold/drop
{
if (!timer.IsEnabled)
timer.Start();
if (holdStep == 0)
{
fromPosition = handPosition;
holdStep = tower.GetStep(GetTowerFromPos(fromPosition));
}
else if (holdStep > 0)
{
bool successMove = tower.Move(GetTowerFromPos(fromPosition), GetTowerFromPos(handPosition));
if (successMove)
{
holdStep = 0;
}
else
{
speaker.SpeakAsyncCancelAll();
speaker.SpeakAsync("Can not drop there.");
}
}
}
else if (e.Key == Key.D3)
{
StartNewGame(3);
}```

The last point is the timer, I use it to calculate how fast the player complete the puzzle.

```private void timer_Tick(object sender, EventArgs e)
{
miliseconds++;
if (miliseconds == 100)
{
if (seconds < 1000)
seconds++;
miliseconds = 0;
}
if (seconds > 999)
lblTime.Content = "More than 999s";
else
lblTime.Content = string.Format("TIME: {0}:{1}", seconds, miliseconds);
}
```

## Points of Interest

Let your application speak! I invoke the TTS engine to say some words in this application, it's easy to use.

## Share

 Software Developer (Senior) Aprimo China
I'm a dotnet developer who is interest in WPF, WCF base on C#.
I have worked for 11 years and have built different projects.
It is exciting working on code. Also management skill is an art which I am on it now.
Professional and efficient are always my goal.

## You may also be interested in...

 First Prev Next
 don't know how can i open it Member 1276788129-Sep-16 15:32 Member 12767881 29-Sep-16 15:32
 Re: don't know how can i open it ryowu18-Dec-16 21:53 ryowu 18-Dec-16 21:53
 My vote of 5 Gun Gun Febrianza16-Nov-13 7:16 Gun Gun Febrianza 16-Nov-13 7:16
 remember me when i was child Gun Gun Febrianza16-Nov-13 7:16 Gun Gun Febrianza 16-Nov-13 7:16
 Nostaligic... Bruno Tabbia19-Oct-13 5:52 Bruno Tabbia 19-Oct-13 5:52
 Re: Nostaligic... ryowu20-Oct-13 2:31 ryowu 20-Oct-13 2:31
 nice CIDev18-Oct-13 7:40 CIDev 18-Oct-13 7:40
 Re: nice ryowu20-Oct-13 2:33 ryowu 20-Oct-13 2:33
 Re: nice CIDev20-Oct-13 4:59 CIDev 20-Oct-13 4:59
 Last Visit: 31-Dec-99 18:00     Last Update: 25-Sep-17 2:52 Refresh 1