Introduction
Towers of Hanoi is a puzzle game where there are three stands, each holds number of plates.
The idea here is that you have to move plates in the first stand to the third one, while moving plates you must consider:
- Size order, meaning when moving a plate you can't put it on a smaller one.
- Only one plate can be moved at each step.
Please note that I used the recursive method.
Background
Formally, Towers of Hanoi recursive function was given by :
void Hanoi(int platesCount, int from, int dest, int by)
{
if (platesCount==1)
{
printf(
"Move the plate from %d to %d through %d"
, from, dest, by);
}
else
{
Hanoi(platesCount -1, from, by, dest);
Hanoi(1, from, dest, by);
Hanoi(platesCount -1, by, dest, from);
}
}
And here is a conceptual image :
Credits:
MG from Wikipedia
Using the Program
When you launch the application, you will see the next screen:
Then you have to select whether to let the program step into the solution automatically or not.
Using the Code
While implementing the program, I faced a problem in separating steps since I used the recursive version, so I decided to keep the recursive way. But the call to Hanoi method will happen just first time when "next" or "solve" button is pressed. Inside the Hanoi method, I stored the states of the solution, meaning each time a call happens, the solution of the current step is stored in a list of integers. Since each step in the Hanoi method requires 4 parameters as mentioned above, 4 integers represent parameter is added to the list. Then each time SolveNextStep
method is called, the program reads from the list 4 items that represent the state.
Available classes are as follows:
HanoiDrawer
PlateGUIInfo
Tools
Anyway I'll describe methods in HanoiDrawer
class that are responsible directly for solving the puzzle.
HanoiDrawer Class
void HanoiDrawer::SolveNextStep()
{
int platesCount
, source
, destination
, intermediate;
if(listSavedState.size()==0)
{
this->Hanoi(this->iPlatesCount, HanoiDrawer::SOURCE
, HanoiDrawer::DESTINATION, HanoiDrawer::INTERMEDIATE);
}
if(listSavedState.size() % 4 != 0 )
{
return;
}
platesCount = listSavedState.front();
listSavedState.pop_front();
source = listSavedState.front();
listSavedState.pop_front();
destination = listSavedState.front();
listSavedState.pop_front();
intermediate = listSavedState.front();
listSavedState.pop_front();
MovePlateFromTo(source, destination);
this->iMovesCount++;
if(iMovesCount == this->GetTotalMovesCount())
{
this->solved = true;
}
SetDlgItemInt(this->hWnd, this->countContainerResourceId,
GetMovesCount(), FALSE);
SetDlgItemText(this->hWnd, this->fromContainerResourceId
, PlaceIntToString(source).c_str() );
SetDlgItemText(this->hWnd, this->toContainerResourceId
, PlaceIntToString(destination).c_str() );
SetDlgItemText(this->hWnd, this->throughContainerResourceId
, PlaceIntToString(intermediate).c_str() );
}
void HanoiDrawer::ReDraw()
{
DrawStands();
DrawPlates();
Invalidate();
}
void HanoiDrawer::Hanoi(int platesCount, int source, int destination, int intermediate)
{
if (platesCount == 1)
{
listSavedState.push_back(platesCount);
listSavedState.push_back(source);
listSavedState.push_back(destination);
listSavedState.push_back(intermediate);
return;
}
else
{
Hanoi(platesCount - 1, source, intermediate, destination);
Hanoi(1, source, destination, intermediate);
Hanoi(platesCount - 1, intermediate, destination, source);
return;
}
}
Improvements
- The user has the ability to drag and drop the plates, then the program should verify user choice.
Notices
- I tried to focus into the main idea of how I implemented the puzzle to ease understanding of my code. I didn't mention anything about window related tasks.
- Conceptual image is created by MG from Wikipedia:
History
- v1.0 14/7/2007: Main core and functionality