01 //HAHAHA.java -- Graphics Hanoi, by tsaiwn@cs.nctu.edu.tw 02 //javac HAHAHA.java 03 //java HAHAHA 04 //HTML: 05 import java.io.*; 06 import java.applet.*; 07 import java.awt.*; 08 import java.awt.event.*; 09 import java.net.*; 10 import java.util.*; 11 12 public class HAHAHA extends Applet { 13 static Frame f = null; 14 static boolean isApplet = true; 15 gHanoiOK ghok = null; 16 ControlPanel cp = null; 17 18 public static void main(String xxx[ ]) { 19 isApplet = false; // from Java application 20 f = new Frame("Tower of Hanoi"); 21 HAHAHA hhh = new HAHAHA( ); 22 f.add("Center", hhh); 23 f.setSize(gHanoiOK.X_SIZE+10, gHanoiOK.Y_SIZE+50); //510,550 24 f.setVisible(true); f.addWindowListener(new WCC( )); 25 //Then, Simulate the Applet behavior 26 hhh.init( ); 27 hhh.start( ); 28 }//main 29 30 public void init( ) { 31 ghok = new gHanoiOK(f); 32 cp = new ControlPanel(ghok); 33 setLayout(new BorderLayout( ) ); 34 add("Center", ghok); 35 add("South", cp); // the Control Panel 36 if(f!=null) { f.validate( ); f.setVisible(true); } 37 ghok.init( ); 38 ghok.start( ); 39 }//init( 40 public void start( ) { 41 if(!isApplet) ghok.main( ); // is application 42 else ghok.winHanoi(5); // isApplet 43 }//start( 44 45 public HAHAHA( ) { 46 }// HAHAHA constructor 47 }//class HAHAHA 48 49 class gHanoiOK extends Panel implements MouseListener { 50 //some constants for later use 51 public static final int X_SIZE=500, Y_SIZE=500; 52 public static final int Y_TOP = 28; 53 public static final Color bgColor = Color.white; 54 public static final int DELAY_TIME = 50; // 50/1000 second 55 public static final int MOVE_STEP = 58; // 58 points 56 public static final int MIN_STEP = 6; // 6 points 57 public static final int MAX_STEP = 158; // 88 points 58 public static final int MAX_DELAY = 88; // 88 milli sec 59 public static final int MIN_DELAY = 1; 60 61 public static Color haColor = Color.red; // variable 62 public static boolean speedUp = false; // speed up? 63 public static int delayTime = DELAY_TIME; 64 public static int step = MOVE_STEP; 65 int kkk=0; // used in paint( 66 boolean alreadyDone = false; // used in Applet mode 67 boolean isRunning = false; // doing Hanoi ? 68 69 /// 70 int nDisks = 0; // number of Disks 71 int nPeg[ ] = new int[3]; // height of the 3 piles 72 int xPosition[ ] = new int[3]; // central position of 3 pegs 73 int aX=38, aY= (Y_SIZE - 50); 74 int bX=(aX+(X_SIZE-50)/3), bY=aY; 75 int cX=(bX+(X_SIZE-50)/3), cY=aY; 76 77 int thick=22; // for disk thick 78 int width=33; // for disk width 79 int wUnit=2; // 128/nDisks == 2 80 81 Graphics bufferGraphics=null; // 用來畫在記憶體的圖 82 Image img=null; // The image that will contain everything that .. 83 /// .. has been drawn on bufferGraphics. 84 /// .. will be used in paint( ) 85 Dimension dim=null; // To get the width and height of the applet. 86 87 PrintStream cout=null; // 使其類似 C++ 的 88 BufferedReader cin = null; 89 90 public void init( ) { 91 addMouseListener(this); // handle MouseEvent 92 if(f==null) cout = System.out; // from Applet 93 }//init( 94 95 public void start( ) { 96 prepareIO( ); 97 prepareImagePaper( ); 98 }//start 99 100 Frame f=null; 101 //Panel myPanel; 102 103 public static void main(String xxx[ ]) { 104 Frame f = new Frame("Tower of Hanoi"); 105 gHanoiOK gok = new gHanoiOK(f); 106 f.add("Center", gok); 107 f.setSize(X_SIZE, Y_SIZE); //500,500 108 f.setVisible(true); 109 gok.init( ); // simulate Applet 110 gok.start( ); 111 gok.repaint( ); // force to initilize img 112 gok.prepareIO( ); 113 gok.main( ); 114 }//main 115 116 // constructors, one for from main( 117 public gHanoiOK( Frame f ) { 118 this.f = f; 119 addMouseListener(this); // handle MouseEvent 120 if(f==null) cout = System.out; // from Applet 121 }// gHanoiOK 122 123 public gHanoiOK( ) { // for Applet to call this 124 addMouseListener(this); // handle MouseEvent 125 } 126 127 void prepareIO( ){ 128 try{ 129 cout = System.out; 130 if(f==null) return; // is Applet 131 cin = new BufferedReader( 132 new InputStreamReader(System.in) ); 133 }catch(Exception e) { System.exit(38); } 134 }//prepareIO( 135 136 137 138 void prepareImagePaper( ) { 139 // Create an offscreen image to draw on , same size 140 setVisible(true); 141 dim = getSize( ); // obtain the width and height 142 if(dim.width == 0) return; // not ready, maybe later 143 img = createImage(dim.width, dim.height); 144 bufferGraphics = img.getGraphics( ); 145 // use Graphics methods to draw, this is double buffer 146 return; 147 }// prepareImagePaper 148 149 // hanoi.c -- Hanoi tower, @CopyLeft by tsaiwn@csie.nctu.edu.tw 150 //Hanoi Tower(河內之塔) -- 神奇的 Recursive -- 自己叫自己 ! 151 //關於 Hanoi Tower, 請用 http://gogle.com 打入 "hanoi tower" 查詢 152 //注意用雙引號夾住如 "hanoi tower" 查到的才是你要的 :-) 153 //或是直接看這 http://en.wikipedia.org/wiki/Tower_of_Hanoi 154 /// C/C++ requires declaraction before use the function 155 //void moveOne(int px, int py, int ); //3rd parameter is the disk# 156 void hanoi(int n, int pa, int pc, int pb) { 157 if(n==0) return; // there is no disk 158 if(shouldDie) return; // my Master want me to die :-( 159 hanoi(n-1, pa, pb, pc); // 先幫我把上面 n-1 disks 搬走 160 moveOne(pa, pc, n); /// move the n-th disk from pa to pc 161 hanoi(n-1, pb, pc, pa); // move n-1 disks from pb to pc 162 } // hanoi 163 void moveOne(int px, int py, int n ) { // the n-th disk 164 moveG(px, py, n); // Graphics version 165 String p123[ ] = {"th", "st", "nd", "rd"}; // -th, Fir-st, 166 // .. Seco-nd, 3-rd 167 int k = n%10; 168 if(k!=1 && k!=2 && k!=3) k = 0; // -th 169 cout.printf("Move %d-%s disk from %c to %c \n", 170 n, p123[k], px, py); 171 }//moveOne( 172 173 int getInt( ) { // static char buf[99]; 174 String buf = null; 175 int ans=0; 176 // fgets(buf, sizeof(buf), stdin); ans=atoi(buf); 177 try { 178 buf = cin.readLine( ); 179 ans = Integer.parseInt(buf); 180 }catch(Exception e) { ans = 3; } 181 // 如果把 ans = 3; 改為 ans = 64; 你認為會做多久? ? ? 182 return ans; // 若一秒只能搬一個動作, 183 // ..則需約 600 billion(六千億) (580+) years 184 }// getInt( 185 186 void haInit(int n) { 187 nDisks = n; if(n==0) n=2; 188 nPeg[0] = n; // initially all Disks on Peg-0 189 nPeg[1] = nPeg[2] = 0; // no Disks on Peg-1 and Peg-2 190 thick = (Y_SIZE -50)/n; // thick of each Disk 191 if(thick > 20) thick = 20; // disk thick limit 192 wUnit = 128/n; // Disk width = wUnit * Disk#number 193 if(wUnit < 2) wUnit=2; // minimum 2 points 194 xPosition[0] = aX + 64; // central position aX + 128/2 195 xPosition[1] = bX + 64; 196 xPosition[2] = cX + 64; 197 // 198 clearTower( ); 199 if(f != null) { f.validate( ); f.setVisible(true); } 200 initDisks( ); // draw the initial Disks 201 if(f != null) f.setVisible(true); // f.show( ); 202 }// haInit( 203 204 205 206 void doHanoi(int n) { 207 if(dim == null || img==null || bufferGraphics == null) { 208 prepareImagePaper( ); // create img paper 209 if( bufferGraphics == null) return; // give up 210 System.out.println("doHanoi.."); 211 } 212 if(n >= 65) return; 213 shouldDie = false; isRunning = true; pause=false; 214 haInit(n); 215 hanoi(n, 'A', 'C', 'B'); // move n disks on peg 'A' to peg 'C' 216 isRunning = false; 217 }// doHanoi( 218 219 220 int main( ) { // original main program in C Language 221 int n; int firstRun = 1; 222 while(true) { 223 if(firstRun != 0) { 224 firstRun = 0; 225 f.setVisible(false); // hide the window 226 }//if 227 cout.print(" n=? "); 228 n = getInt( ); // read an int into n 229 if(n<0) break; 230 f.setVisible(true); //f.requestFocus(true); 231 doHanoi(n); 232 try{Thread.sleep(58);}catch(Exception e) { } 233 //f.toBack( ); //f.setVisible(false); // hide the window 234 }//while 235 f.dispose( ); cout.println("Bye bye..."); 236 System.exit(0); return 0; 237 }// int main( ) 238 ////////////////////////// 239 240 void winHanoi(int n) { // do hanoi from Applet/Window 241 if(alreadyDone) return; // run only once 242 alreadyDone = true; pause=false; shouldDie=false; 243 System.out.println("applet paint..."); 244 //doHanoi(n); // 不要這樣做, 會陷入很久的 ... 245 //啟動另一個 thread Sister 去做才不會被卡住 246 new Sister(this, n).start( ); 247 // this 就是目前這 class 的物件 ( gHanoiOK ) 248 }// winHanoi( 249 250 void clearTower( ){ //initial status 251 if(dim == null || img==null || bufferGraphics == null) { 252 repaint( ); // force to prepare img/bufgraphics 253 if(dim==null) repaint( ); // try to prepare img again 254 if(img==null) repaint( ); 255 if(img==null) return; // still not READY yet 256 } 257 setBackground(Color.white); 258 bufferGraphics.clearRect(0,0,dim.width,dim.width); 259 bufferGraphics.setColor(Color.pink); 260 bufferGraphics.fillRect(aX-3, aY, 128+6, 18); 261 bufferGraphics.fillRect(bX-3, bY, 128+6, 18); 262 bufferGraphics.fillRect(cX-3, cY, 128+6, 18); 263 bufferGraphics.setColor(new Color(99, 58, 233)); 264 bufferGraphics.setFont(new Font("Courier", Font.BOLD, 18) ); 265 bufferGraphics.drawString( 266 "Tower of Hanoi, by tsaiwn@csie.nctu.edu.tw",20,20); 267 repaint( ); // have paint( ) to draw the image to screen 268 try{ Thread.sleep(delayTime); }catch(Exception e){ } 269 }//clearTower 270 271 272 273 274 // rewrite update( ) : 275 // Always required for good double-buffering. 276 // This will cause the Applet not to first wipe off previous 277 // ..drawings but to immediately repaint. 278 // The wiping off may also causes flickering. 279 // Update is called automatically when repaint( ) is called. 280 281 // comment out the update( ) function then try to run again 282 public void update(Graphics g) { paint(g); } // 直接叫 paint( ) 283 284 public void paint(Graphics g) { 285 if(dim == null || img==null || bufferGraphics == null) { 286 // This is the first call to here. 287 //System.out.println("paint...img null..."); 288 prepareImagePaper( ); 289 return; 290 }//if 291 g.drawImage(img, 0, 0, this); // 此時才畫到螢幕 292 //System.out.println(" paint "+ ++kkk); //for debug 293 }//paint( 294 295 void initDisks( ) { // draw the original Disks 296 if( img==null || bufferGraphics == null) return; 297 int x, y; 298 for(int n= nDisks; n>=1; --n) { 299 bufferGraphics.setColor(haColor); 300 x = xPosition[0] - wUnit*n/2; 301 y = aY - (nDisks -n+1)*thick; 302 bufferGraphics.fillRect(x, y, wUnit*n, thick); 303 }//for 304 repaint( ); 305 try{Thread.sleep(delayTime);}catch(Exception e){ } 306 } 307 308 void moveG(int px, int py, int n ) { // the n-th disk 309 if(shouldDie) return; 310 //if(img==null) return; // not ready yet 311 if(dim == null || img==null || bufferGraphics == null){ 312 repaint( ); 313 if(dim == null || img==null ) repaint( ); 314 if(bufferGraphics == null) repaint( ); 315 if(bufferGraphics == null) return; // give up :-) 316 } 317 int from = px - 'A'; 318 int to = py - 'A'; 319 width = wUnit * n; // width of n-th disk 320 if(width > 128) width = 128; // limit the width 321 moveYUp(from, to, n); // 編號 n 的 Disk 322 moveX(from, to, n); 323 moveYDown(from, to, n); 324 --nPeg[from]; // from == 0? 1? 2? 325 ++nPeg[to]; 326 //System.out.print("moveG--- "); 327 }//moveG( 328 329 void moveThere(int xs, int ys, int xt, int yt, 330 int width, int thick) { 331 if(shouldDie && dieIM) return; // my Master want me to die :-( 332 checkPause( ); 333 bufferGraphics.setColor(Color.white); // 擦掉 334 bufferGraphics.fillRect(xs, ys, width, thick); 335 bufferGraphics.setColor(haColor); // 然後畫新的 336 bufferGraphics.fillRect(xt, yt, width, thick); 337 repaint( ); // 顯示到螢幕 338 try{Thread.sleep(delayTime);}catch(Exception e){ } 339 }//moveThere 340 341 342 void moveYUp(int fm, int to, int n ) { // the n-th disk 343 // fm, to : 0, 1, 2 344 int x,y, y1, y2; 345 x = xPosition[fm] - width/2; 346 y2 = Y_TOP; 347 y1 = aY - nPeg[fm]*thick; // y-position of n-th disk 348 // move y from y1 to y2 349 y = y1; 350 while(y > y2+step) { 351 int y0 = y; 352 y -= step; 353 moveThere(x, y0, x, y, width, thick); 354 }//while( 355 moveThere(x, y, x, y2, width, thick); //提起到正上方 356 }//moveYUp 357 358 void moveX(int fm, int to, int n ) { // the n-th disk 359 int x,y, x1, x2; 360 y = Y_TOP; 361 x1 = xPosition[fm] - width/2; 362 x2 = xPosition[to] - width/2;; 363 //boolean toRight = true; // move from Left to Right 364 int rightLeft = 1; // 往右 ; fm ==> to 365 if(x2 < x1) rightLeft = -1; // 往左 to <== fm 366 x = x1; // move x from x1 to x2 367 while( 38==38 ) { // BUG fixed 368 int xtemp = x + step * rightLeft; // 向右走向左走? 369 if(rightLeft == 1) { // fm ====> to 370 if(xtemp > x2) break; 371 }else{ // to <====== fm 372 if(xtemp < x2) break; 373 } 374 int x0 = x; 375 x = xtemp; // 注意我們用臨時的 xtemp 376 moveThere(x0, y, x, y, width, thick); 377 }//while( 378 moveThere(x, y, x2, y, width, thick); // 到目的堆正上方 379 }//moveX 380 381 void moveYDown(int fm, int to, int n ) { // the n-th disk 382 int x,y, y1, y2; 383 x = xPosition[to] - width/2;; 384 y1 = Y_TOP; 385 y2 = aY - (nPeg[to]+1)*thick; // destination 386 y = y1; // move y from y1 to y2 387 while(y < y2-step) { 388 int y0 = y; 389 y += step; 390 moveThere(x, y0, x, y, width, thick); 391 }//while( 392 moveThere(x, y, x, y2, width, thick); // 到定位 393 }// moveYDown 394 395 396 void checkPause( ) { 397 while(true) { // Loop untill "Continue" 398 if( !pause ) break; 399 try{ Thread.sleep(18); }catch(Exception e){ } 400 }//while 401 }//checkPause( 402 403 ////////////////////////////////////////////////////////// 404 /// handling MouseEvent 405 public void mousePressed(MouseEvent e) { } 406 407 public void mouseReleased(MouseEvent e) { } 408 409 410 public void mouseEntered(MouseEvent e) { 411 step = MAX_STEP + 25; 412 delayTime = MIN_DELAY; 413 } 414 415 public void mouseExited(MouseEvent e) { 416 step = MIN_STEP; 417 delayTime = DELAY_TIME; // in milli seconds 418 } 419 420 public void mouseClicked(MouseEvent e) { 421 if(e.getButton( ) == MouseEvent.BUTTON3) { // Right Button 422 step = 1+(step/3); delayTime = delayTime*2; 423 speedUp = !speedUp; // toggle 424 }//if 425 if(speedUp){ 426 faster( ); 427 }else{ 428 slower( ); 429 }//if( 430 }//mouseClicked 431 432 public void faster( ) { // moving faster 433 ++step; if(step > MAX_STEP) step = MAX_STEP; 434 --delayTime; if(delayTime < MIN_DELAY) delayTime = MIN_DELAY; 435 if(delayTime == MIN_DELAY && step==MAX_STEP) speedUp = false; 436 }//faster 437 438 public void slower( ) { // moving slower 439 --step; if(step < MIN_STEP) step = MIN_STEP; 440 ++delayTime; if(delayTime > MAX_DELAY) delayTime = MAX_DELAY; 441 if(delayTime == MAX_DELAY && step==MIN_STEP) speedUp = true; 442 }//slower 443 boolean pause = false; // "Pause/Continue" ? 444 boolean shouldDie = false; // "Stop" pressed 445 boolean dieIM = false; // "StopIM" pressed 446 } // class gHanoiOK 447 //////////////////////////////////////////////////////////// 448 449 450 class ControlPanel extends Panel 451 implements ItemListener, ActionListener { 452 gHanoiOK target; 453 int nDisks = 2; 454 455 public ControlPanel(gHanoiOK target) { 456 this.target = target; 457 target.setBackground(Color.white); 458 target.setForeground(Color.red); 459 // 460 setLayout(new FlowLayout()); 461 setBackground(Color.yellow); 462 MyTimeBTN tm; add(tm=new MyTimeBTN( )); // for showing time 463 new Thread(tm).start( ); // start my Timer 464 addColorSelector( ); 465 addStartButton( ); 466 addChoices( ); 467 addMoreButtons( ); 468 }// ControlPanel( 469 470 void addStartButton( ) { 471 Button b = new Button("Start"); 472 b.setBackground(Color.pink); 473 b.setForeground(Color.black); 474 add(b); 475 b.addActionListener(this); // "Start" Button 476 }// addStartButton( 477 478 479 480 void addChoices( ) { 481 Choice shapes = new Choice(); // choice List 482 shapes.addItemListener(this); 483 shapes.addItem("1"); shapes.addItem("2"); 484 shapes.addItem("3"); shapes.addItem("5"); 485 shapes.addItem("8"); shapes.addItem("16"); 486 shapes.addItem("24"); shapes.addItem("32"); 487 shapes.addItem("50"); shapes.addItem("64"); 488 shapes.setBackground(Color.lightGray); 489 shapes.select("5"); nDisks = 5; 490 add(shapes); 491 }// 492 493 static Button bFast=null, bSlower=null; 494 void addMoreButtons( ) { 495 Button bq = new Button("Quit"); 496 bq.setForeground(Color.red); 497 add(bq); 498 bq.addActionListener(this); 499 Panel p = new Panel( ); 500 p.add(bFast = new Button("+")); // Faster 501 bFast.addActionListener(this); 502 p.add(bSlower = new Button("-")); // Slower 503 bSlower.addActionListener(this); 504 add(p); p.setBackground(new Color(238,168,158)); 505 //p.setBackground(bFast.getBackground( )); 506 Button bStop = new Button("Stop"); 507 bStop.setForeground(Color.red); 508 bStop.addActionListener(this); 509 add(bStop); 510 bStop = new Button(STOP_IM); 511 bStop.setFont(new Font("Courier", Font.BOLD, 12) ); 512 bStop.setForeground(Color.blue); 513 bStop.addActionListener(this); 514 add(bStop); 515 bStop = new Button(PAUSE_M); 516 bStop.setFont(new Font("Courier", Font.BOLD, 10) ); 517 bStop.setForeground(Color.red); 518 bStop.addActionListener(this); 519 add(bStop); 520 }// addMoreButtons( 521 522 void addColorSelector( ) { 523 Panel p = null; 524 CheckboxGroup group = new CheckboxGroup(); 525 Checkbox b; 526 p = new Panel( ); 527 p.add(b = new Checkbox(null, group, true)); 528 b.addItemListener(this); 529 b.setForeground(Color.red); 530 add(p); p.setBackground(Color.red); 531 p = new Panel( ); 532 p.add(b = new Checkbox(null, group, false)); 533 b.addItemListener(this); 534 b.setForeground(Color.green); 535 add(p); p.setBackground(Color.green); 536 p = new Panel( ); 537 p.add(b = new Checkbox(null, group, false)); 538 b.addItemListener(this); 539 b.setForeground(Color.blue); 540 add(p); p.setBackground(Color.blue); 541 /// 542 target.haColor = Color.red; // initial color 543 }// addColorSelector( 544 545 546 public void paint(Graphics g) { 547 Rectangle r = getBounds(); 548 g.setColor(Color.lightGray); 549 g.draw3DRect(0, 0, r.width, r.height, true); 550 int n = getComponentCount( ); 551 for(int i=0; i= 65 ) nDisks = 8; 579 String acCommand = e.getActionCommand( ); 580 if(acCommand.equals("Quit") ) System.exit(0); 581 else if(acCommand.equals("Start") ) pbStart( ); 582 else if(acCommand.equals("Stop") ) pbStop( ); 583 else if(acCommand.equals(STOP_IM) ) pbStopIM( ); 584 else if(acCommand.equals(PAUSE_M) ) pbPause(e); 585 else if(acCommand.equals(CONTINUE_M) ) pbContinue(e); 586 }//actionPerformed 587 588 private void pbStart( ) { 589 //target.doHanoi(nDisks); // not work to triger event 590 Sister hanoi = new Sister(target, nDisks); 591 hanoi.start( ); // 啟動另一個 Thread 去做 hanoi(nDisks) 592 // event handler 結束後其他 event 才有用 593 } // pbStart( 594 595 private void pbStop( ) { 596 target.pause = false; 597 target.shouldDie = true; target.dieIM = false; 598 }// pbStop( 599 600 private void pbStopIM( ) { 601 target.pause = false; 602 target.shouldDie = target.dieIM = true; 603 //try{Thread.sleep(8);}catch(Exception ee) { } 604 }// pbStopIM( 605 606 private void pbPause(ActionEvent e) { 607 if( !target.isRunning ) return; // 沒在 Run 608 target.shouldDie = target.dieIM = false; 609 target.pause = true; 610 ((Button)e.getSource()).setLabel(CONTINUE_M); 611 }// pbStopIM( 612 613 614 private void pbContinue(ActionEvent e) { 615 //if( !target.isRunning ) return; // 沒在 Run 616 target.shouldDie = target.dieIM = false; 617 if(target.speedUp) target.faster( ); else target.slower( ); 618 //try{Thread.sleep(8);}catch(Exception ee) { } 619 target.pause = false; 620 ((Button)e.getSource()).setLabel(PAUSE_M); 621 }// pbStopIM( 622 623 public final String STOP_IM = "立即停"; // "StopIM" 624 public final String PAUSE_M = "Pause"; // "暫停" 625 public final String CONTINUE_M = "Continue"; // "繼續" 626 }//class ControlPanel 627 628 // 這個 Thread 用來執行 gHanoiOK 的 doHanoi(nDisks); 629 class Sister extends Thread { 630 gHanoiOK target; 631 int nDisks = 3; 632 boolean putOnly = false; 633 static Sister him=null; // static variable is shared 634 635 Sister( gHanoiOK target, int nDisks){ 636 this.target = target; 637 this.nDisks = nDisks; 638 }//Sister 639 // 注意 Thread 的啟動點是 run( ), 要用 .start( ) 啟動! 640 public void run( ) { 641 int cnt = activeCount( ); 642 //if(him!=null && him.isAlive()) return; //do nothing 643 // 只允許一個 Thread 做 hanoi, 不然會亂七八糟糕 644 if( target.isRunning ) return; // ignore it when moving 645 if(him == null) { // 若 user 一直按 Start ? 646 him = this; 647 target.delayTime = 3; target.step = 2; 648 target.isRunning = true; target.pause = false; 649 target.shouldDie = target.dieIM = false; 650 if(putOnly) target.haInit(nDisks); // doNot move 651 else target.doHanoi(nDisks); 652 target.isRunning = false; 653 him = null; // 讓下次又可做 doHanoi( ) 654 }// if 655 }//run( 656 Sister( gHanoiOK target, int nDisks, boolean putOnly){ 657 // new this constructor will initialize Disks ONLY 658 this.target = target; this.nDisks = nDisks; this.putOnly = true; 659 }//Sister 660 }//class Sister 661 662 class WCC extends WindowAdapter{ // 用來關閉窗 Only 663 public void windowClosing(WindowEvent e){System.exit(0);} 664 } 665 666 class MyTimeBTN extends Canvas implements Runnable { 667 MyTimeBTN( ) { setSize(50,15); setVisible(true); } 668 public void paint(Graphics g) { 669 String t = "" + new Date( ); 670 g.drawString(t.substring(10,19), 0, 12); 671 } 672 public void run( ) { 673 while (true) { 674 try { Thread.sleep(58); } catch (Exception e) { } 675 repaint(); 676 } 677 }//run( 678 }//MyTimeBTN