/* TowersOfHanoi.java ** Author: R. McCloskey ** Date: Oct. 2018 ** ** This Java class is inspired by the "Towers Of Hanoi" puzzle/game. The ** premise is that there are three pegs/spindles, one of which has a stack of ** disks on it. (The disks have holes in the middle, like doughnuts, so that ** they can slide down a peg). The disks are of distinct sizes (diameters), ** and at no time can a disk be on top of a smaller disk. ** The goal is to transfer the stack of disks from one peg to another one, ** through a sequence of disk moves. In a disk move, a single disk is ** taken from the top of the stack on one peg and placed on top of the ** stack lying on a distinct peg. ** ** An instance of this class, when created, produces output describing a ** sequence of disk moves that would suffice to transfer a stack of disks ** of a specified height from a specified peg to another specified peg. ** (Pegs are identified by distinct char values, say A, B, and C. The ** height of a stack is simply the number of disks on the stack.) ** Afterwards, it can tell you how many disk moves it made in performing ** the transfer. ** ** A main() method is included; it simply creates an object of the class ** and tells it to transfer a stack of disks from peg A to peg B. The ** height of the stack is given by a command line argument. It then ** reports how many disk moves were performed. */ public class TowersOfHanoi { // instance variables // ------------------ private int numberOfDisks; // # of disks to transfer private char sourceName, destName, auxName; // names of the three pegs private int moveCntr; // # of disk moves that have been performed private int recurDepth; // current depth of recursion private boolean verbose; // whether or not to print // constructor // ----------- /* Creates a Towers of Hanoi object, and associates the given Strings ** (as names) to the three pegs/spindles. */ public TowersOfHanoi(char source, char dest, char aux) { sourceName = source; destName = dest; auxName = aux; } /* Creates a Towers of Hanoi object whose source, destination, and ** auxiliary pegs are named A, B, and C, respectively. */ public TowersOfHanoi() { this('A', 'B', 'C'); } // observers // --------- /* Returns the height of the stack of disks (i.e. the number of disks ** in that stack) that were transferred as a result of the most recent ** call to the start() method. */ public int stackHeight() { return numberOfDisks; } /* Returns the number of disk moves performed as a result of the ** most recent call to the start() method. */ public int numDiskMoves() { return moveCntr; } // mutator // ------- /* Goes through the motions of transferring a stack of disks of the ** specified height from the source peg to the destination peg. If the ** second parameter is true, a narration of the process is printed. */ public void start(int numDisks, boolean verbose) { this.verbose = verbose; numberOfDisks = numDisks; moveCntr = 0; recurDepth = 0; transferStack(numberOfDisks, sourceName, destName, auxName); } /* Prints a narration describing a sequence of disk moves that has the ** effect of transferring a stack of the specified number of disks ** from the source peg to the destination peg. */ public void start(int numDisks) { start(numDisks, false); } // private methods // --------------- /* Prints a sequence of disk moves sufficient to transfer a stack of ** disks of the given height from the specified "source" peg to the ** specified "destination" peg (using the other peg as an auxiliary). ** ** pre: the three pegs specified are distinct and every disk already ** on either the destination or auxiliary peg is larger than the ** largest disk on the source peg. ** Also, height > 0 */ private void transferStack(int numDisks, // # disks to transfer char source, // ID of source peg char destination, // ID of destination peg char auxiliary) // ID of auxiliary peg { if (verbose) { printRepeat("| ", recurDepth); System.out.println("Transferring " + numDisks + " disks from peg " + source + " to peg " + destination); } recurDepth = recurDepth + 1; //RWM: Include the next line (and put an 'else' on the line after that) // if you want to allow for numDisks being zero. // if (numDisks == 0) { } if (numDisks == 1) { moveDisk(source, destination); } else { // Transfer to the auxiliary peg all but the largest disk on the // source peg. transferStack(numDisks-1, source, auxiliary, destination); moveDisk(source, destination); // Transfer to the destination peg all the disks on the // auxiliary peg. transferStack(numDisks-1, auxiliary, destination, source); } recurDepth = recurDepth - 1; if (verbose) { printRepeat("| ", recurDepth); System.out.println("Finished transferring " + numDisks + " disks from peg " + source + " to peg " + destination); } } /* Records that a move took place and, if in verbose mode, reports ** from which peg a disk was removed and onto which peg it was placed. ** pre: There is at least one disk on the 'from' peg and, if there is ** a disk on the 'to' peg, the former is smaller than the latter. */ private void moveDisk(char from, char to) { if (verbose) { printRepeat("| ",recurDepth); System.out.println(from + " --> " + to); } moveCntr++; } /* Prints the specified String the specified # of times. */ private void printRepeat(String s, int n) { for (int i=0; i != n; i++) { System.out.print(s); } } /* Prints a sequence of disk moves sufficient to transfer, from peg A ** to peg B, a stack of disks having height specified by the command ** line argument. Then reports the number of disk moves that were ** performed in doing so. */ public static void main(String[] args) { int stackHeight = Integer.parseInt(args[0]); TowersOfHanoi toh = new TowersOfHanoi(); toh.start(stackHeight); System.out.println("\nA stack of " + toh.stackHeight() + " disks was transferred using " + toh.numDiskMoves() + " disk moves."); } }