Skip to content

Instantly share code, notes, and snippets.

@gazmull
Created July 29, 2018 18:06
Show Gist options
  • Save gazmull/e05f2df6b889b9d10b4330de103608ca to your computer and use it in GitHub Desktop.
Save gazmull/e05f2df6b889b9d10b4330de103608ca to your computer and use it in GitHub Desktop.
Tower of Hanoi Case Study
/*
Author: gazmull <vescalaw@gmail.com>
Description: [Case Study] Tower of Hanoi with data structuring.
*/
#include <iostream>
#include <iomanip>
using namespace std;
int
inputSize
, moves
, * towers
, * towerSizes;
// Towers-related functions
void
printTowers()
, modifyTowers(int towerA, int towerB);
// I/O streaming functions
void pausePrint(string message = "\n");
// Tower functions
namespace Tower {
int index(int x, int y) { return (x * inputSize) + y; };
int size(int tower) { return towerSizes[tower]; };
int top(int tower) { return -1 * (size(tower) - inputSize); };
int topValue(int tower) { return towers[index(tower, top(tower))]; };
};
// Initialiser
int main() {
cout << "Number of towers: ";
cin >> inputSize;
if (inputSize < 3)
return main();
// Use 1D Array for storing tower numbers, with their respective tower size in another array
// Please refer to Tower::index for indexing
moves = 0;
towers = new int[inputSize * inputSize];
towerSizes = new int[inputSize];
// Print vertically
for (int i = 0; i < inputSize; i++)
for (int j = 0; j < inputSize; j++)
if (!i) {
towers[Tower::index(0, j)] = j + 1;
towerSizes[i] = inputSize;
}
else {
towers[Tower::index(i, j)] = 0;
towerSizes[i] = 0;
}
printTowers();
return 0;
}
// Display/Update towers sheet
void printTowers() {
system("cls");
cout
<< "Moves occurred: " << moves
<< "\nGame Rules:"
<< "\n * Only 1 number per move"
<< "\n * You cannot stack larger number with a smaller number"
<< "\n * You cannot win with getting all numbers back to tower 1 after scrambling them."
<< "\n\n";
for (int i = 1; i <= inputSize; i++)
cout << setw(5) << i;
cout << "\n\n";
for (int i = 0; i < inputSize; i++) {
for (int j = 0; j < inputSize; j++)
cout << setw(5) << towers[Tower::index(j, i)];
cout << endl;
}
int
towerA
, towerB;
// Ask for input with space character as separator
cout
<< endl
<< "[MOVE FROM] [MOVE TO]: ";
cin >> towerA >> towerB;
modifyTowers(towerA - 1, towerB - 1);
}
/*
Towers checker
- Malicious act checks
- Transferring of number between towers
- Check win condition
*/
void modifyTowers(int towerA, int towerB) {
// Malicious act checks
if (towerA == towerB) {
pausePrint("Wrong move. You cannot select the same tower.");
return printTowers();
} else if (!Tower::topValue(towerA)) {
pausePrint("Wrong move. You cannot move anything from an empty tower.");
return printTowers();
} else if (Tower::topValue(towerB) && Tower::topValue(towerA) > Tower::topValue(towerB)) {
pausePrint("Wrong move. Please move to an empty tower or a tower with higher top number.");
return printTowers();
}
/*
Transferring of number between towers
- For some reason, removing `- 1` and/or adding `-1` at `Tower::top` breaks these re-assignments.
I have yet to know why...
- Update tower sizes
- Track moves
*/
towers[Tower::index(towerB, Tower::top(towerB) - 1)] = Tower::topValue(towerA);
towers[Tower::index(towerA, Tower::top(towerA))] = 0;
towerSizes[towerA]--;
towerSizes[towerB]++;
moves++;
// Check win condition
if (Tower::size(towerB) == inputSize && towerB) {
cout << "You win. Moves occurred: " << moves;
pausePrint();
tryAgain:
char answer;
cout << "Try again? (y/n): ";
cin >> answer;
switch (answer) {
case 'y':
// Free memory && call main function
delete[] towers;
delete[] towerSizes;
system("cls");
main();
break;
case 'n':
exit(0);
break;
default: goto tryAgain;
}
}
printTowers();
}
void pausePrint(string message) {
cout << message << endl;
system("pause");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment