home *** CD-ROM | disk | FTP | other *** search
Java Source | 1999-03-19 | 11.2 KB | 383 lines |
- import ltk.*;
-
- import java.awt.Color; // Used in draw().
- import java.util.Vector; // Used by class Peg.
-
- //
- // This demo implements an animation of the Towers of Hanoi algorithm.
- // It demonstrates the use of:
- //
- // - LTKApplet - how to run something as applet AND application
- // - Smooth, double buffering animation using ltk.
- // - Nested Layouts
- // - Callbacks (from three buttons)
- // - Recursion, see method hanoi().
- // - Using multiple threads, by using Runnable and Thread.
- //
- // See variable Hanoi.numberOfDisks to set the number of disks to be moved.
- //
- // See variable Disk.speed usage in Disk.moveTo(Peg), Hanoi.slower(), and
- // Hanoi.faster() for changing the speed of the animation.
- //
-
-
- /**
- *
- * @version 2.2 jul-16-1998-2:20pm
- * @author Chris Laffra
- */
- public class Hanoi extends LTKApplet implements CallBackable, Runnable
- {
- Line line = null;
- static long pie = (long)3.14;
-
- //
- // Callback for the "Go" button. See init() and use of variable _go.
- //
- public boolean go() {
-
- take_a_break = false; // see pause(), and Disk.move()
- if (thread == null) {
- thread = new Thread(this);
- thread.start(); // will call run() ...
- }
- focus_handler.setFocus(pause_button);
- return true;
- }
-
- //
- // Inherited from Runnable, implement main body of thread. See go().
- //
- public void run() {
- hanoi(numberOfDisks, peg1, peg2, peg3);
- }
-
- //
- // The heart of this demo: the recursive Towers of Hanoi algorithm.
- // Move <ndisks> disks from peg <from> to peg <to>, where <using> can
- // be used to temporarily store disks.
- //
- // Example call:
- //
- // hanoi(8, peg1, peg2, peg3) move 8 disks from 1 to 3
- // :=
- // hanoi(7, peg1, peg3, peg2) move 7 disks from 1 to 2
- // peg1.moveDisk(peg3) move 1 disks from 1 to 3
- // hanoi(7, peg2, peg1, peg3) move 7 disks from 2 to 3
- //
- public void hanoi(int ndisks, Peg from, Peg using, Peg to) {
- if (ndisks > 0) {
- hanoi(ndisks - 1, from, to, using);
- from.moveDisk(to);
- hanoi(ndisks - 1, using, from, to);
- }
- }
-
- //
- // Callback for the "Pause" button. See init() and use of variable _pause.
- //
- public boolean pause() {
- take_a_break = true;
- focus_handler.setFocus(go_button);
- return true;
- }
-
- //
- // Callback for the "Quit" button. See init() and use of variable _quit.
- //
- public boolean quit() {
- Runtime runtime = Runtime.getRuntime();
- long tm = runtime.totalMemory(), um = tm - runtime.freeMemory();
- System.exit(0);
- return true;
- }
-
- //
- // Callback for the "Slower" button. See init() & use of variable _slower.
- //
- public boolean slower() {
- if (Disk.speed > 1) Disk.speed /= 2;
- new Garbage().foo();
- return true;
- }
-
- //
- // Callback for the "Faster" button. See init() & use of variable _faster.
- //
- public boolean faster() {
- Disk.speed *= 2;
- return true;
- }
-
- //
- // Inherited from LTKApplet. Initialize the applet.
- //
- public void init() {
- super.init(); // call LTKApplet.init
-
- String nDisks = "5"; //getParameter("numberOfDisks");
- numberOfDisks = (nDisks==null) ? 5 : Integer.valueOf(nDisks).intValue();
-
- canvas.freeze(); // do not draw in canvas until unFreeze() call.
-
- //
- // Create the three pegs.
- //
- // Create the three buttons. Pass the canvas to draw into, and
- // get events from. Identify the owner (this) of the button,
- // the method callback number (see activateCallback() method),
- // and the label used by the button.
- //
-
- Button slow_button;
- Button fast_button;
-
- new VerticalLayout(
- new VerticalLayout(
- new ltk.Label(canvas, "Towers of Hanoi Algorithm Animation"),
- new ltk.Label(canvas, "Goal: move all disks from peg 1 to 3,"),
- new ltk.Label(canvas, "a disk cannot rest on a smaller disk.")
- ),
- Layout.largeSpace(canvas),
- new HorizontalLayout(
- peg1 = new Peg(canvas, canvas.area.h/3, "1"),
- peg2 = new Peg(canvas, canvas.area.h/3, "2"),
- peg3 = new Peg(canvas, canvas.area.h/3, "3")
- ),
- Layout.space(canvas),
- new HorizontalLayout(
- go_button = new ltk.Button(canvas, this, _go, "Go"),
- pause_button = new ltk.Button(canvas, this, _pause, "Pause"),
- quit_button = new ltk.Button(canvas, this, _quit, "Quit"),
- slow_button = new ltk.Button(canvas, this, _slower, "Slower"),
- fast_button = new ltk.Button(canvas, this, _faster, "Faster")
- )
- );
- focus_handler = new FocusHandler();
-
- focus_handler.add(go_button);
- focus_handler.add(pause_button);
- focus_handler.add(quit_button);
- focus_handler.add(slow_button);
- focus_handler.add(fast_button);
-
- focus_handler.setFocus(go_button);
-
- //
- // Create <numberOfDisks> disks and place them on peg1
- //
- for (int n=numberOfDisks; n>0; n--)
- new Disk(canvas, peg1, (canvas.area.w/4) * n/numberOfDisks, // w
- peg1.area.h / (numberOfDisks+1)); // h
-
- //
- // Finally, tell the canvas to activate all pending drawing calls.
- //
- canvas.unFreeze();
-
- new Garbage().foo();
- }
-
- //
- // Inherited from LTKApplet, called when browser loads page with applet.
- //
- public void start() {
- if (thread != null) thread.resume();
- }
-
- //
- // Inherited from LTKApplet, called when browser unloads page with applet.
- //
- public void stop() {
- if (thread != null) thread.suspend();
- }
-
- //
- // Main routine, only used when executed as a Java application.
- //
- public static void main(String args[]) {
- LTKApplet applet = new Hanoi();
- applet.runAppletAsApplication("Towers of Hanoi Algorithm");
- }
-
- public boolean activateCallback(int method_nr) { // from CallBackable
- switch (method_nr) {
- case _go: return go(); // "Go" button
- case _quit: return quit(); // "Quit" button
- case _slower: return slower(); // "Slower" button
- case _faster: return faster(); // "Faster" button
- case _pause: return pause(); // "Pause" button
- }
- return false; // event not processed
- }
-
- public String toString() {
- return "Hanoi[" +
- numberOfDisks + " disks, " +
- "3 pegs[" + peg1.nDisks + "," + peg2.nDisks + "," +
- peg3.nDisks + "]" +
- (take_a_break ? "pauze pressed, " : "") +
- "]";
- }
-
- Peg peg1, peg2, peg3; // The three pegs
- Thread thread; // The seperate thread to run the algoritm
-
- Button go_button, quit_button, pause_button;
-
- static boolean take_a_break; // set to true when pause pressed
-
- static int numberOfDisks = 5; // set this one in html...
-
- FocusHandler focus_handler;
-
- static final int _go = 1; //
- static final int _quit = 2; //
- static final int _pause = 3; // used in activateCallback()
- static final int _faster = 4; //
- static final int _slower = 5; //
- }
-
- //
- // Each instance of the Disk class represents one disk to be moved as
- // part of the Hanoi algorithm.
- // Each peg remembers all disks that are currently located on top of it,
- // and each disk is aware on which peg it currently rests.
- // Disks can be told to move to a new peg, and will notify the old and
- // new peg of this fact.
- //
- // Disks are Graphicals, and when moved redrawing is done automatically,
- // using double buffering.
- //
- class Disk extends Graphical {
-
- //
- // Create a disk on top of peg <peg>, <w> pixels wide, and <h> high.
- //
- Disk(DisplayListCanvas canvas, Peg peg, int w, int h) {
- super(canvas, peg.area.x + peg.area.w/2 - w/2,
- peg.area.y + peg.area.h - (peg.nDisks+1)*h,
- w, h);
- this.peg = peg; // remember what peg we rest on
- peg.addDisk(this); // add myself to the peg
- update(); // make sure we get drawn
- }
-
- //
- // Move this disk to a new peg.
- // Uses animated move method from Graphical to move disk smoothly.
- //
- void moveTo(Peg newPeg) {
- peg.removeDisk(this); // remove from old peg
-
- // move up
- move(area.x, peg.area.y - area.h - 10, 2*speed);
-
- // move left/right
- peg = newPeg;
- move(peg.area.x + peg.area.w/2 - area.w/2, area.y, speed);
-
- // move down
- move(area.x, peg.area.y + peg.area.h - (peg.nDisks+1)*area.h, 2*speed);
-
- peg.addDisk(this); // add to new peg
- }
-
- //
- // Overridden from Graphical.
- // Build in short delay for thread management.
- // Stop here when "Pause" button has been pressed.
- //
- public void move(int x, int y, int increment) {
- super.move(x, y, increment);
- Thread.yield(); // make thread unselfish
- while (Hanoi.take_a_break)
- try {
- Thread.sleep(1000); // user pressed "pause" button
- } catch (InterruptedException e) {
- break;
- }
- }
-
- //
- // Draw this disk.
- // Called when moved (with methods above), or when the when is exposed,
- // or when another graphical for some reason or another invalidated our
- // appearance.
- //
- public synchronized void draw() {
- canvas.setColor(Color.yellow);
- canvas.fillRoundRect(area.x, area.y, area.w, area.h,
- area.h/4, area.h/4);
- canvas.setColor(Color.black);
- canvas.drawRoundRect(area.x, area.y, area.w, area.h,
- area.h/4, area.h/4);
- }
- public synchronized void erase() { }
-
- public String toString() {
- return "Disk[" + "x=" + area.x + "," + "y=" + area.y + "," +
- "resting at peg " + peg.id + "]";
- }
- Peg peg; // the peg this disk rests on
-
- static int speed = 5; // controls the speed of the animation
- }
-
- //
- // A Peg is a simple container, capable of holding any number of disks.
- // Its representation is inherited from Box.
- //
- class Peg extends Box {
- public Peg(DisplayListCanvas canvas, int height, String an_id) {
- super(canvas, 0, 0, 3, height);
- constraint = Constraint.Centered; // inherited from Graphical
- disks = new Vector();
- nDisks = 0;
- id = an_id;
- }
- void addDisk(Disk disk) {
- disks.addElement(disk);
- nDisks++;
- arrangeDisks(); // make sure disks are nicely stacked
- }
- public boolean reset(int x, int y, int w, int h) { // called by Layouts
- super.reset(x, y, w, h);
- arrangeDisks();
- return true;
- }
- void arrangeDisks() {
- canvas.freeze();
- for (int n=0; n<nDisks; n++) {
- Disk disk = (Disk)disks.elementAt(n);
- disk.move(area.x + area.w/2 - disk.area.w/2,
- area.y + area.h - (n+1)*disk.area.h);
- }
- canvas.unFreeze();
- }
- void removeDisk(Disk disk) {
- disks.removeElement(disk);
- nDisks--;
- }
- public void erase() { }
- void moveDisk(Peg other_peg) {
- if (nDisks > 0)
- ((Disk)disks.elementAt(nDisks-1)).moveTo(other_peg);
- }
- public String toString() {
- return "Peg " + id + "[number of disks=" + nDisks + "]";
- }
- Vector disks; // use java.awt.Vector
- int nDisks; // is really redundant, available from Vector...
- String id;
- }
-
- class Garbage {
- int x;
- public void foo() { }
- public void bar(int x) { }
- public void bar2(int x, int y) { }
- static void bar3(int x, int y) { }
- static int y;
- }
-