home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 October / pcp156b.iso / alphawrk / JAX / DOC53.ZIP / doc53 / demo / Hanoi.java < prev    next >
Encoding:
Java Source  |  1999-04-29  |  11.2 KB  |  383 lines

  1. import ltk.*;
  2.  
  3. import java.awt.Color;        // Used in draw().
  4. import java.util.Vector;    // Used by class Peg.
  5.  
  6. //
  7. // This demo implements an animation of the Towers of Hanoi algorithm.
  8. // It demonstrates the use of:
  9. //
  10. //   -  LTKApplet - how to run something as applet AND application
  11. //   -  Smooth, double buffering animation using ltk.
  12. //   -  Nested Layouts
  13. //   -  Callbacks (from three buttons)
  14. //   -  Recursion, see method hanoi().
  15. //   -  Using multiple threads, by using Runnable and Thread.
  16. //
  17. // See variable Hanoi.numberOfDisks to set the number of disks to be moved.
  18. //
  19. // See variable Disk.speed usage in Disk.moveTo(Peg), Hanoi.slower(), and
  20. // Hanoi.faster() for changing the speed of the animation.
  21. //
  22.  
  23.  
  24. /**
  25.  *
  26.  * @version  2.2 jul-16-1998-2:20pm 
  27.  * @author         Chris Laffra
  28.  */
  29. public class Hanoi extends LTKApplet implements CallBackable, Runnable
  30. {
  31.     Line line = null;
  32.     static long pie = (long)3.14;
  33.  
  34.     //
  35.     // Callback for the "Go" button. See init() and use of variable _go.
  36.     //
  37.     public boolean go() {
  38.  
  39.     take_a_break = false;        // see pause(), and Disk.move()
  40.     if (thread == null) {
  41.         thread = new Thread(this);
  42.         thread.start();        // will call run() ...
  43.     }
  44.     focus_handler.setFocus(pause_button);
  45.     return true;
  46.     }
  47.  
  48.     //
  49.     // Inherited from Runnable, implement main body of thread. See go().
  50.     //
  51.     public void run() {
  52.     hanoi(numberOfDisks, peg1, peg2, peg3);
  53.     }
  54.  
  55.     //
  56.     // The heart of this demo: the recursive Towers of Hanoi algorithm.
  57.     // Move <ndisks> disks from peg <from> to peg <to>, where <using> can
  58.     // be used to temporarily store disks.
  59.     //
  60.     // Example call:
  61.     //
  62.     //     hanoi(8, peg1, peg2, peg3)       move 8 disks from 1 to 3
  63.     //     :=
  64.     //        hanoi(7, peg1, peg3, peg2)    move 7 disks from 1 to 2
  65.     //        peg1.moveDisk(peg3)            move 1 disks from 1 to 3
  66.     //        hanoi(7, peg2, peg1, peg3)    move 7 disks from 2 to 3
  67.     //
  68.     public void hanoi(int ndisks, Peg from, Peg using, Peg to) {
  69.     if (ndisks > 0) {
  70.         hanoi(ndisks - 1, from, to, using);
  71.         from.moveDisk(to);
  72.         hanoi(ndisks - 1, using, from, to);
  73.         }
  74.     }
  75.  
  76.     //
  77.     // Callback for the "Pause" button. See init() and use of variable _pause.
  78.     //
  79.     public boolean pause() {
  80.     take_a_break = true;
  81.     focus_handler.setFocus(go_button);
  82.     return true;
  83.     }
  84.  
  85.     //
  86.     // Callback for the "Quit" button. See init() and use of variable _quit.
  87.     //
  88.     public boolean quit() {
  89.     Runtime runtime = Runtime.getRuntime();
  90.     long tm = runtime.totalMemory(), um = tm - runtime.freeMemory();
  91.     System.exit(0);
  92.     return true;
  93.     }
  94.  
  95.     //
  96.     // Callback for the "Slower" button. See init() & use of variable _slower.
  97.     //
  98.     public boolean slower() {
  99.     if (Disk.speed > 1) Disk.speed /= 2;
  100.     new Garbage().foo();
  101.     return true;
  102.     }
  103.  
  104.     //
  105.     // Callback for the "Faster" button. See init() & use of variable _faster.
  106.     //
  107.     public boolean faster() {
  108.     Disk.speed *= 2;
  109.     return true;
  110.     }
  111.  
  112.     //
  113.     // Inherited from LTKApplet. Initialize the applet.
  114.     //
  115.     public void init() {
  116.     super.init();                    // call LTKApplet.init
  117.  
  118.     String nDisks = "5"; //getParameter("numberOfDisks");
  119.     numberOfDisks = (nDisks==null) ? 5 : Integer.valueOf(nDisks).intValue();
  120.  
  121.     canvas.freeze();  // do not draw in canvas until unFreeze() call.
  122.  
  123.         //
  124.     // Create the three pegs.
  125.     //
  126.     // Create the three buttons. Pass the canvas to draw into, and
  127.     // get events from. Identify the owner (this) of the button,
  128.     // the method callback number (see activateCallback() method),
  129.     // and the label used by the button.
  130.         //
  131.  
  132.     Button slow_button;
  133.     Button fast_button;
  134.  
  135.     new VerticalLayout(
  136.         new VerticalLayout(
  137.             new ltk.Label(canvas, "Towers of Hanoi Algorithm Animation"),
  138.             new ltk.Label(canvas, "Goal: move all disks from peg 1 to 3,"),
  139.             new ltk.Label(canvas, "a disk cannot rest on a smaller disk.")
  140.         ),
  141.         Layout.largeSpace(canvas),
  142.         new HorizontalLayout(
  143.             peg1 = new Peg(canvas, canvas.area.h/3, "1"),
  144.             peg2 = new Peg(canvas, canvas.area.h/3, "2"),
  145.             peg3 = new Peg(canvas, canvas.area.h/3, "3")
  146.         ),
  147.         Layout.space(canvas),
  148.         new HorizontalLayout(
  149.             go_button    = new ltk.Button(canvas, this, _go,      "Go"),
  150.             pause_button = new ltk.Button(canvas, this, _pause,   "Pause"),
  151.             quit_button  = new ltk.Button(canvas, this, _quit,    "Quit"),
  152.             slow_button  = new ltk.Button(canvas, this, _slower,  "Slower"),
  153.             fast_button  = new ltk.Button(canvas, this, _faster,  "Faster")
  154.         )
  155.     );
  156.     focus_handler = new FocusHandler();
  157.  
  158.     focus_handler.add(go_button);
  159.     focus_handler.add(pause_button);
  160.     focus_handler.add(quit_button);
  161.     focus_handler.add(slow_button);
  162.     focus_handler.add(fast_button);
  163.  
  164.     focus_handler.setFocus(go_button);
  165.  
  166.     //
  167.     // Create <numberOfDisks> disks and place them on peg1
  168.     //
  169.     for (int n=numberOfDisks; n>0; n--)
  170.         new Disk(canvas, peg1, (canvas.area.w/4) * n/numberOfDisks, // w
  171.                    peg1.area.h / (numberOfDisks+1));    // h
  172.  
  173.     //
  174.     // Finally, tell the canvas to activate all pending drawing calls.
  175.     //
  176.     canvas.unFreeze();
  177.  
  178.     new Garbage().foo();
  179.     }
  180.  
  181.     //
  182.     // Inherited from LTKApplet, called when browser loads page with applet.
  183.     //
  184.     public void start() {
  185.         if (thread != null) thread.resume();
  186.     }
  187.  
  188.     //
  189.     // Inherited from LTKApplet, called when browser unloads page with applet.
  190.     //
  191.     public void stop() {
  192.         if (thread != null) thread.suspend();
  193.     }
  194.  
  195.     //
  196.     // Main routine, only used when executed as a Java application.
  197.     //
  198.     public static void main(String args[]) {
  199.     LTKApplet applet = new Hanoi();
  200.         applet.runAppletAsApplication("Towers of Hanoi Algorithm");
  201.     }
  202.  
  203.     public boolean activateCallback(int method_nr) {    // from CallBackable
  204.     switch (method_nr) {
  205.         case _go:      return go();            // "Go" button
  206.         case _quit:    return quit();        // "Quit" button
  207.         case _slower:  return slower();        // "Slower" button
  208.         case _faster:  return faster();        // "Faster" button
  209.         case _pause:   return pause();        // "Pause" button
  210.     }
  211.     return false;                    // event not processed
  212.     }
  213.  
  214.     public String toString() {
  215.         return  "Hanoi[" +
  216.         numberOfDisks + " disks, " +
  217.         "3 pegs[" + peg1.nDisks + "," + peg2.nDisks + "," +
  218.                         peg3.nDisks + "]" +
  219.         (take_a_break ? "pauze pressed, " : "") +
  220.         "]";
  221.     }
  222.  
  223.     Peg  peg1, peg2, peg3;    // The three pegs
  224.     Thread thread;        // The seperate thread to run the algoritm
  225.  
  226.     Button go_button, quit_button, pause_button;
  227.  
  228.     static boolean take_a_break;    // set to true when pause pressed
  229.  
  230.     static int numberOfDisks = 5;    // set this one in html...
  231.  
  232.     FocusHandler focus_handler;
  233.  
  234.     static final int _go     = 1;    //
  235.     static final int _quit   = 2;       //
  236.     static final int _pause  = 3;         // used in activateCallback()
  237.     static final int _faster = 4;       //
  238.     static final int _slower = 5;     //
  239. }
  240.  
  241. //
  242. // Each instance of the Disk class represents one disk to be moved as
  243. // part of the Hanoi algorithm.
  244. // Each peg remembers all disks that are currently located on top of it,
  245. // and each disk is aware on which peg it currently rests.
  246. // Disks can be told to move to a new peg, and will notify the old and
  247. // new peg of this fact.
  248. //
  249. // Disks are Graphicals, and when moved redrawing is done automatically,
  250. // using double buffering.
  251. //
  252. class Disk extends Graphical {
  253.  
  254.     //
  255.     // Create a disk on top of peg <peg>, <w> pixels wide, and <h> high.
  256.     //
  257.     Disk(DisplayListCanvas canvas, Peg peg, int w, int h) {
  258.     super(canvas, peg.area.x + peg.area.w/2 - w/2,
  259.               peg.area.y + peg.area.h - (peg.nDisks+1)*h,
  260.               w, h);
  261.     this.peg = peg;        // remember what peg we rest on
  262.     peg.addDisk(this);    // add myself to the peg
  263.     update();        // make sure we get drawn
  264.     }
  265.  
  266.     //
  267.     // Move this disk to a new peg.
  268.     // Uses animated move method from Graphical to move disk smoothly.
  269.     //
  270.     void moveTo(Peg newPeg) {
  271.     peg.removeDisk(this);    // remove from old peg
  272.  
  273.     // move up
  274.     move(area.x, peg.area.y - area.h - 10, 2*speed);
  275.  
  276.     // move left/right
  277.     peg = newPeg;
  278.     move(peg.area.x + peg.area.w/2 - area.w/2, area.y, speed);
  279.  
  280.     // move down
  281.     move(area.x, peg.area.y + peg.area.h - (peg.nDisks+1)*area.h, 2*speed);
  282.  
  283.     peg.addDisk(this);    // add to new peg
  284.     }
  285.  
  286.     //
  287.     // Overridden from Graphical.
  288.     // Build in short delay for thread management.
  289.     // Stop here when "Pause" button has been pressed.
  290.     //
  291.     public void move(int x, int y, int increment) {
  292.     super.move(x, y, increment);
  293.     Thread.yield();                 // make thread unselfish
  294.         while (Hanoi.take_a_break)
  295.         try {
  296.         Thread.sleep(1000);        // user pressed "pause" button
  297.         } catch (InterruptedException e) {
  298.         break;
  299.         }
  300.     }
  301.  
  302.     //
  303.     // Draw this disk.
  304.     // Called when moved (with methods above), or when the when is exposed,
  305.     // or when another graphical for some reason or another invalidated our
  306.     // appearance.
  307.     //
  308.     public synchronized void draw() {
  309.            canvas.setColor(Color.yellow);
  310.            canvas.fillRoundRect(area.x, area.y, area.w, area.h,
  311.                             area.h/4, area.h/4);
  312.            canvas.setColor(Color.black);
  313.            canvas.drawRoundRect(area.x, area.y, area.w, area.h,
  314.                             area.h/4, area.h/4);
  315.     }
  316.     public synchronized void erase() { }
  317.  
  318.     public String toString() {
  319.         return  "Disk[" + "x=" + area.x + "," + "y=" + area.y + "," +
  320.         "resting at peg " + peg.id + "]";
  321.     }
  322.     Peg peg;            // the peg this disk rests on
  323.  
  324.     static int speed = 5;      // controls the speed of the animation
  325. }
  326.  
  327. //
  328. // A Peg is a simple container, capable of holding any number of disks.
  329. // Its representation is inherited from Box.
  330. //
  331. class Peg extends Box {
  332.     public Peg(DisplayListCanvas canvas, int height, String an_id) {
  333.     super(canvas, 0, 0, 3, height);
  334.     constraint = Constraint.Centered;    // inherited from Graphical
  335.     disks = new Vector();
  336.     nDisks = 0;
  337.     id = an_id;
  338.     }
  339.     void addDisk(Disk disk) {
  340.     disks.addElement(disk);
  341.     nDisks++;
  342.     arrangeDisks();            // make sure disks are nicely stacked
  343.     }
  344.     public boolean reset(int x, int y, int w, int h) {    // called by Layouts
  345.     super.reset(x, y, w, h);
  346.     arrangeDisks();
  347.     return true;
  348.     }
  349.     void arrangeDisks() {
  350.     canvas.freeze();
  351.     for (int n=0; n<nDisks; n++) {
  352.         Disk disk = (Disk)disks.elementAt(n);
  353.         disk.move(area.x + area.w/2 - disk.area.w/2,
  354.               area.y + area.h - (n+1)*disk.area.h);
  355.     }
  356.     canvas.unFreeze();
  357.     }
  358.     void removeDisk(Disk disk) {
  359.     disks.removeElement(disk);
  360.     nDisks--;
  361.     }
  362.     public void erase() { }
  363.     void moveDisk(Peg other_peg) {
  364.     if (nDisks > 0)
  365.         ((Disk)disks.elementAt(nDisks-1)).moveTo(other_peg);
  366.     }
  367.     public String toString() {
  368.         return  "Peg " + id + "[number of disks=" + nDisks + "]";
  369.     }
  370.     Vector disks;    // use java.awt.Vector
  371.     int nDisks;        // is really redundant, available from Vector...
  372.     String id;
  373. }
  374.  
  375. class Garbage {
  376.     int x;
  377.     public void foo() { }
  378.     public void bar(int x) { }
  379.     public void bar2(int x, int y) { }
  380.     static void bar3(int x, int y) { }
  381.     static int y;
  382. }
  383.