Towers of Hanoi
This is a program I made for fun trying to understand the recursion of the Towers of Hanoi problem. The solution to the puzzle is very simple from a recursion point of view. Without recursion the solution seems difficult to conceptualize/develop.
It was programmed using the Processing library made for Java. It is a very simple application which is a visual representation of the solution to the problem.
There are buttons which allow you to modify the puzzle. The first two buttons decrease/increase the solution speed. The other two buttons decrease/increase the number of pegs. The more pegs, the harder the puzzle in real life, but the recursion is the same.
Your screen resolution is too small to display this program
The following is the source code for the Towers of Hanoi problem. Since it uses Processing, most of the drawing code is abstracted (so only the algorithm is truly relevant).
Your screen resolution is too small to display the program code
final int diskHeight = 10; final int diskWidthMult = 30; final int margin = 25; final int pegWidth = 10; /** * Used as a snapshot for playing the steps of the solution */ class Group { ArrayList A; ArrayList B; ArrayList C; Group(ArrayList theA, ArrayList theB, ArrayList theC) { A = cloneArrayList(theA); B = cloneArrayList(theB); C = cloneArrayList(theC); } ArrayList cloneArrayList(ArrayList theList) { ArrayList newList = new ArrayList(theList.size()); for (int i = 0; i < theList.size(); ++i) { Disk theDisk = (Disk) theList.get(i); newList.add(theDisk.clone()); } return newList; } } /** * Represents a disc displayed on the screen */ class Disk { float x, y; int wid; color diskColour; Disk(float theX, float theY, int theNum, color col) { x = theX; y = theY; wid = theNum * diskWidthMult; diskColour = col; } Disk clone() { Disk newDisk = new Disk(x, y, 0, diskColour); newDisk.wid = wid; return newDisk; } void draw() { fill(diskColour); rect(x - wid / 2.0f, y, wid, diskHeight); } } /** * The puzzle itself, solves it and plays it */ class Game { ArrayList PegA; ArrayList PegB; ArrayList PegC; // bad: needed for drawing each step ArrayList STATE; int currentState; int pegACenter; int pegBCenter; int pegCCenter; int theBottom; int theN; boolean solved; Game(int n) { PegA = new ArrayList(n); PegB = new ArrayList(n); PegC = new ArrayList(n); theN = n; theBottom = 200; STATE = new ArrayList(10); currentState = 0; solved = false; // Set up PegA pegACenter = (diskWidthMult / 2 * n) + margin; float frequency = n / 10.0f; for (int i = n - 1; i >= 0 ; --i) { color col = color(sin(frequency*i + -2) * 127 + 128, sin(frequency*i + 0) * 127 + 128, sin(frequency*i + 2) * 127 + 128); PegA.add(new Disk(pegACenter, theBottom + i*diskHeight, i + 1, col)); } STATE.add(new Group(PegA, PegB, PegC)); // Set up PegB pegBCenter = pegACenter + (diskWidthMult * n) + margin * 2; // Set up PegC pegCCenter = pegBCenter + (diskWidthMult * n) + margin * 2; } void draw() { background(255, 255, 255); // peg A fill(255, 228, 181); int pegHeight = theN * diskHeight + 25; int pegX = pegACenter - pegWidth / 2; rect(pegX, theBottom - 25, pegWidth, pegHeight); Group theState = (Group)STATE.get(currentState); for (int i = 0; i < theState.A.size(); ++i) { Disk d = (Disk)theState.A.get(i); d.draw(); } // peg B fill(255, 228, 181); pegX = pegBCenter - pegWidth / 2; rect(pegX, theBottom - 25, pegWidth, pegHeight); for (int i = 0; i < theState.B.size(); ++i) { Disk d = (Disk)theState.B.get(i); d.draw(); } // peg C fill(255, 228, 181); pegX = pegCCenter - pegWidth / 2; rect(pegX, theBottom - 25, pegWidth, pegHeight); for (int i = 0; i < theState.C.size(); ++i) { Disk d = (Disk)theState.C.get(i); d.draw(); } } void solveProblem() { solve(PegA, PegC, PegB, theN); } void solve(ArrayList Starting, ArrayList Ending, ArrayList Extra, int numLeft) { if (numLeft == 1) { // If there's only one peg left move it to the end moveDisk(Starting, Ending); } else { // First move from the starting peg to the extra peg solve(Starting, Extra, Ending, numLeft - 1); // When that's done move the last one to the end peg moveDisk(Starting, Ending); // Then move all the disks on the extra peg to the end peg solve(Extra, Ending, Starting, numLeft - 1); } } void moveDisk(ArrayList Starting, ArrayList Ending) { // Take the last element (the one on top) of starting and put it at the end of ending Disk d = (Disk)Starting.get(Starting.size() - 1); // Move the disk to the right x location if (Ending == PegA) { d.x = pegACenter; } else if (Ending == PegB) { d.x = pegBCenter; } else if (Ending == PegC) { d.x = pegCCenter; } Starting.remove(Starting.size() - 1); Ending.add(d); // Move the disk to the right y location d.y = theBottom + (theN * diskHeight) - Ending.size() * diskHeight; STATE.add(new Group(PegA, PegB, PegC)); } } Game g; int initialNum = 2; int initialSolveRate = 5; void setup() { size(1250, 600); background(255, 255, 255); g = new Game(initialNum); frameRate(initialSolveRate); g.solveProblem(); } final int buttonSize = 20; void draw() { background(255, 255, 255); // Draw game g.draw(); ++g.currentState; if (g.currentState == g.STATE.size()) { g.currentState = 0; } // Draw buttons ////////////// // decrease solverate fill(123,104,238); rect(20,20,buttonSize,buttonSize); // increase solverate fill(238,64,0); rect(80,20,buttonSize,buttonSize); line(120,10,120,30+buttonSize); // increase number of disks fill(123,104,238); rect(140,20,buttonSize,buttonSize); // decrease number of disks fill(238,64,0); rect(200,20, buttonSize,buttonSize); } void mouseClicked() { if (mouseY >= 20 && mouseY <= 20 + buttonSize) { boolean recreateGame = false; // decrease solveRate if (mouseX >= 20 && mouseX <= 20 + buttonSize) { if (initialSolveRate != 1) { frameRate(initialSolveRate); } } // increase solveRate else if (mouseX > 80 && mouseX <= 80 + buttonSize) { frameRate(++initialSolveRate); } // decrease num disks else if (mouseX > 140 && mouseX <= 140 + buttonSize) { if (initialNum != 2) { --initialNum; recreateGame = true; } } // increase num disks else if (mouseX > 200 && mouseX <= 200 + buttonSize) { ++initialNum; recreateGame = true; } if (recreateGame) { g = new Game(initialNum); g.solveProblem(); } } }