Click here to Skip to main content
15,884,176 members
Articles / Desktop Programming / WPF
Tip/Trick

Hanoi Tower

Rate me:
Please Sign up or sign in to vote.
4.77/5 (8 votes)
18 Oct 2013CPOL3 min read 32K   1.8K   3   9
A full functional Hanoi Tower game base on WPF

Introduction

From wiki http://en.wikipedia.org/wiki/Hanoi_tower


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.

Image 1


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.

Image 2

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.

C#
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.

C#
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.

C#
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:

C#
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.

C#
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.   

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Aprimo
China 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.

Comments and Discussions

 
Questiondon't know how can i open it Pin
Member 1276788129-Sep-16 15:32
Member 1276788129-Sep-16 15:32 
AnswerRe: don't know how can i open it Pin
ryowu18-Dec-16 21:53
professionalryowu18-Dec-16 21:53 
GeneralMy vote of 5 Pin
Gun Gun Febrianza16-Nov-13 7:16
Gun Gun Febrianza16-Nov-13 7:16 
Vote 5 for you.. Smile | :)
Generalremember me when i was child Pin
Gun Gun Febrianza16-Nov-13 7:16
Gun Gun Febrianza16-Nov-13 7:16 
GeneralNostaligic... Pin
Bruno Tabbia19-Oct-13 5:52
Bruno Tabbia19-Oct-13 5:52 
GeneralRe: Nostaligic... Pin
ryowu20-Oct-13 2:31
professionalryowu20-Oct-13 2:31 
Questionnice Pin
BillW3318-Oct-13 7:40
professionalBillW3318-Oct-13 7:40 
AnswerRe: nice Pin
ryowu20-Oct-13 2:33
professionalryowu20-Oct-13 2:33 
GeneralRe: nice Pin
BillW3320-Oct-13 4:59
professionalBillW3320-Oct-13 4:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.