ハノイの塔10 (アニメ)

Bou.java の拡張

前のバージョンをBouとして残すためクラス名をTouに変更します。

ファイル名 Tou.java

import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.awt.image.*; //BufferedImageを使うため

public class Tou extends JPanel{ 
   static int dmax;
   char name;
   LinkedList<Integer> pile = new LinkedList<Integer>();
   BufferedImage buffimg = new BufferedImage(
                   200,200,BufferedImage.TYPE_INT_RGB);
   Graphics2D bfg = buffimg.createGraphics();
   
   public Tou(char nam,int maisuu) { 
      name = nam;
      while ( maisuu >0 ){
         pile.add(maisuu);
         maisuu--;
      }
      drawPile(); //コンストラクトと同時に絵も作ります。
   }
   public Tou(char nam) { 
      name = nam;
      pile.clear();
      drawPile(); //コンストラクトと同時に絵も作ります。
   }
   public String toString(){ //このメソッドはつかっていません
       String x = name + ":";
       for ( int p : pile ){
           x= x + p + " ";
       }
       return x;
   }
   public int rmDisk(){
      int diskn = pile.removeLast();
      AnimeRemove(diskn);    //1枚取り去るアニメを呼ぶ
      System.out.println("exec rmDisk "+ diskn);
      drawPile();    //改めて絵を作る。
      return diskn;
   }
   public void addDisk(int diskn){
      AnimeAdd(diskn);    //1枚加えるアニメを呼ぶ
      pile.add(diskn);
      System.out.println("exec addDisk "+ diskn);
      drawPile();    //改めて絵を作る。
   }
   public int getMaisuu(){
      return pile.size();    //枚数を返すメソッド。
   }
   public Dimension getPreferredSize() {
      return new Dimension(200,200);
   }
   public void paintComponent(Graphics myg){
      super.paintComponent(myg);
      Graphics2D myg2 = (Graphics2D)myg;
      myg2.drawImage(buffimg,0,0,getSize().width,getSize().height,this);
       /* BufferedImageから絵をコピーするだけにする。 */
   }
   public void drawPile(){   //前にpaintComponentにあった絵を作る部分
      Color bg =new Color(0xee, 0xee, 0xee);
      bfg.setColor(bg);
      bfg.fillRect(0, 0, buffimg.getWidth(), buffimg.getHeight());
      double boux =buffimg.getWidth()/2;
      double minrad =boux*0.1;
      double dr     =boux*0.8/(dmax-1);
      double bottom =buffimg.getHeight()*0.9;
      double dh     =buffimg.getHeight()*0.8/dmax;
      Rectangle2D.Double rec = new Rectangle2D.Double();
      int mai = 0;
      for ( int diskn : pile ){
         mai++;
         int g =(int)(127+128/dmax*diskn);
         int b =(int)(255-255/dmax*(diskn-1));
         bfg.setColor(new Color(0,g,b));
         double radius = minrad+dr*(diskn-1);
         double x = boux-radius;
         double y = bottom-dh*mai;
         rec.setRect(x,y,radius*2,dh);
         bfg.fill(rec);
         bfg.setColor(Color.black);
         bfg.draw(rec);
      }
     repaint();  //paintComponenに描画を指示
   }


   public void AnimeRemove(int diskn){ //1枚取り去るアニメ
       Color bg =new Color(0xee, 0xee, 0xee);
       int     mai  = getMaisuu()+1; //取り去った後に呼ばれている
       double boux =buffimg.getWidth()/2;
       double minrad =boux*0.1;
       double dr     =boux*0.8/(dmax-1);
       double bottom =buffimg.getHeight()*0.9;
       double dh     =buffimg.getHeight()*0.8/dmax;
       double radius = minrad+dr*(diskn-1);
       double x = boux-radius;
       double y = bottom-dh*mai;
       int g =(int)(127+128/dmax*diskn);
       int b =(int)(255-255/dmax*(diskn-1));
       Color diskcolor = new Color(0,g,b));
       Rectangle2D.Double rec =
           new Rectangle2D.Double(x,y,radius*2,dh-1  );
       bfg.setColor(bg);
       bfg.fill(rec);
       bfg.draw(rec);
       double movdh=(bottom-dh*(mai))/8;
       int movn=0;
       while(y+dh>0){
           movn++;
           y = bottom-dh*mai -movdh*movn;
           rec.setRect(x,y,radius*2,dh);
           bfg.setColor(diskcolor);
           bfg.fill(rec);
           repaint();
           try {Thread.sleep(100);}
           catch(InterruptedException ex) {System.err.println(ex);}
           bfg.setColor(bg);
           bfg.fill(rec);
           bfg.draw(rec);
       }
   }
   public void AnimeAdd(int diskn){  //1枚加えるアニメ
       Color bg =new Color(0xee, 0xee, 0xee);
       int   mai  = getMaisuu()+1;
       double boux =buffimg.getWidth()/2;
       double minrad =boux*0.1;
       double dr     =boux*0.8/(dmax-1);
       double bottom =buffimg.getHeight()*0.9;
       double dh     =buffimg.getHeight()*0.8/dmax;
       double radius = minrad+dr*(diskn-1);
       double x = boux-radius;
       double y = 0;
       Rectangle2D.Double rec
          = new Rectangle2D.Double(x,y,radius*2,dh);
       int ct = 0;
       double movdh=(bottom-dh*(mai))/8;
       int g =(int)(127+128/dmax*diskn);
       int b =(int)(255-255/dmax*(diskn-1));
       Color diskcolor = new Color(0,g,b);
       while(bottom-dh*(mai)>y){
           bfg.setColor(diskcolor);
           bfg.fill(rec);
           bfg.setColor(Color.black);
           bfg.draw(rec);
           //paintImmediately((int)x,(int)y,(int)(radius*2),(int)dh);
           repaint();
           try {Thread.sleep(100);}
           catch(InterruptedException ex) {System.err.println(ex);}
           bfg.setColor(bg);
           bfg.fill(rec);
           bfg.draw(rec);
           ct++;
           y = movdh*ct;
           rec.setRect(x,y,radius*2,dh);
      }
   }
}

変数説明図

HanoiTou.java。

ファイル名 HanoiTou.java

import java.awt.*;
import javax.swing.*;
public class HanoiTou { 
   long ct = 0;
   public void idou(int n,Tou src,Tou dst,Tou tmp){
      if (n > 0){
         idou(n-1,src,tmp,dst);
         
         int disk=src.rmDisk();
         dst.addDisk(disk);
         try {
             Thread.sleep(500);
           }
         catch(InterruptedException ex) {
             System.err.println(ex);
           }
         ct++;
         idou(n-1,tmp,dst,src);
       }
   } 
   public HanoiTou(int maisuu){
      Tou.dmax=maisuu;
      Tou tou1 = new Tou('A',maisuu);
      Tou tou2 = new Tou('B');
      Tou tou3 = new Tou('C');
      JFrame  dai  = new JFrame("Hanoi");
      dai.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      dai.setLayout(new GridLayout(1,3,0,0));
      dai.add(tou1);
      dai.add(tou2);
      dai.add(tou3);
      dai.pack();
      dai.setVisible(true);
      try { Thread.sleep(500); }
      catch(InterruptedException ex) { System.err.println(ex); }
      idou(maisuu,tou1,tou3,tou2);
   }
   public static void main( String[] args ) {
      int n = Integer.parseInt(args[0]);
      HanoiTou hanoi = new HanoiTou(n);
      System.out.println(hanoi.ct + "回");
   }
}

課題

  1. デバッグのためのコンソールへの文字列を表示しなくする
  2. 枠の無い部分の枠を描く
  3. 加えるときの影を追加

32枚の場合

$ java Hanoi8 32

もくじ

聖愛中学高等学校
http://www.seiai.ed.jp/
Last Modified