import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Stack;
import javax.swing.*;
public class HanoiFrame extends JComponent implements Runnable{
private static final long serialVersionUID = 1L;
private final Stack<Integer> src=new Stack<Integer>(); //A柱
private final Stack<Integer> mid=new Stack<Integer>(); //B柱
private final Stack<Integer> tag=new Stack<Integer>(); //C柱
private JFrame jf = new JFrame("演示汉诺塔问题");
private JPanel jp_right = new JPanel();
private JLabel jl = new JLabel("圆盘数:");
private JTextField jtf = new JTextField(8);
private JLabel jl1 = new JLabel("间隔毫秒:");
private JTextField jtf1 = new JTextField(8);
private JLabel jl2 = new JLabel("移动次数:");
private JTextField jtf2 = new JTextField(8);
private JLabel jl3 = new JLabel("手动解题:");
private JLabel jl4 = new JLabel("------------------------------------------");
private JButton jb = new JButton("自动解题");
private JButton jb2 = new JButton("播放");
private JButton jb3 = new JButton("暂停");
private JButton jb4 = new JButton("确认");
public void Action() {
jf.addWindowListener(new WindowAdapter() //关闭程序时释放资源
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
);
jf.setBounds(800, 300, 700, 400);
jp_right.setLayout(null); //面板设置成绝对布局
jp_right.setBounds(500,100,200,250);
jp_right.add(jl);jl.setBounds(10,0,60,30);
jp_right.add(jtf);jtf.setBounds(70,0,110,30);jtf.setText("5");
jp_right.add(jl1);jl1.setBounds(10,40,80,30);
jp_right.add(jtf1);jtf1.setBounds(70,40,110,30);jtf1.setText("300");
jp_right.add(jl2);jl2.setBounds(10,80,80,30);
jp_right.add(jtf2);jtf2.setBounds(70,80,110,30);
jp_right.add(jl4);jl4.setBounds(10,185,320,30); //分界线
jp_right.add(jl3);jl3.setBounds(10,210,80,30); //手动解题
jtf2.setEditable(false);
jp_right.add(jb);jb.setBounds(15,120,160,35);//解题按钮
final HanoiFrame c=new HanoiFrame();
jb.addActionListener(new ActionListener() //创建解题监听器
{
public void actionPerformed(ActionEvent e)
{
try {
c.start(Integer.parseInt(jtf.getText()),Integer.parseInt(jtf1.getText()),jtf2);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
jp_right.add(jb2);jb2.setBounds(15,160,70,30); //播放
jb2.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try {
c.resume();
}catch (Exception e1){
e1.printStackTrace();
}
}
});
jp_right.add(jb3);jb3.setBounds(105,160,70,30); //暂停
jb3.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try {
c.suspend();
}catch (Exception e2) {
e2.printStackTrace();
}
}
});
jp_right.add(jb4);jb4.setBounds(75, 210, 70, 30);
jb4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
try {
count=Integer.parseInt(jtf.getText());
HandleHanoi.Bction();
}catch(Exception e3) {
e3.printStackTrace();
}
}
});
jf.add(jp_right);
jf.add(c);
jf.setVisible(true);
}
/***********************************************************************************************************************/
/***********************************************************************************************************************/
/***********************************************************************************************************************/
private int moveCount;
void move(Stack<Integer> src,Stack<Integer> tag){
while(suspend==1)
try {
Thread.sleep(5);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try{
Thread.sleep(sleep); //移动的间隔时间sleep
}
catch(InterruptedException e){
}
tag.push(src.pop()); //将A柱src出栈的压栈到C柱tag
moveCount++; //记录移动次数
if(timesComp != null){
timesComp.setText("" + (moveCount)); //打印移动次数
}
repaint(); //重绘Component(图形发生变化,盘子移动)
}
public int n=1;
public void move(int count,Stack<Integer> src,Stack<Integer> tag,Stack<Integer> mid){
if(count == 1){
move(src,tag); //递归起点(最上面的盘子移动)
}
else{
move(count - 1,src,mid,tag);
move(src,tag);
move(count - 1,mid,tag,src);
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(count <= 0){
return; //不画盘子
}
int w=470; //给予演示汉诺塔问题的板块宽度
int h=350; //给予演示汉诺塔问题的板块高度
int maxW=w / 3; //每个盘子的最大宽度
int maxH=h / count; //每个盘子的最大高度
paintTower(g,src,w * 1 / 6,h,maxW,maxH); //一个盘子最大占1/3 所以盘子的x坐标从1/6开始
paintTower(g,mid,w * 3 / 6,h,maxW,maxH);
paintTower(g,tag,w * 5 / 6,h,maxW,maxH);
}
public double getTopTowerPositionX(Stack<Integer> data,int maxW) {
int len=data.size();
int w = 0;
for(int i=0;i<len;i++) {
Integer n=data.get(i);
w=maxW-((maxW/2)*n/count);
}
return (470/6-w/2+20);
}
public double getTopTowerPositionY(Stack<Integer> data,int maxH) {
int len=data.size();
for(int i=0;i<len;i++) {
y-=maxH;
}
return (y);
}
public double getTopTowerPositionX1(Stack<Integer> data,int maxW) {
int len=data.size();
int w = 0;
for(int i=0;i<len;i++) {
Integer n=data.get(i);
w=maxW-((maxW/2)*n/count);
}
return (470/6-w/2+20+w);
}
public double getTopTowerPositionY1(Stack<Integer> data,int maxH) {
int len=data.size();
for(int i=0;i<len;i++) {
y-=maxH;
}
return (y+maxH);
} //X、Y是最上方盘子的左下角坐标 X1、Y1是右上角坐标
private void paintTower(Graphics g,Stack<Integer> data,int x,int y,int maxW,int maxH){
int len=data.size(); //参数(画笔g,栈data,盘子的x,板块的高度y,盘子的最大宽度maxW,盘子的最大高度maxH)
for(int i=0;i < len;i++){
Integer n=data.get(i);
int w=maxW - ((maxW / 2) * n / count); //每个盘子的宽度在减少
g.setColor(Color.BLUE);
g.drawRect(x - w / 2+20,y - maxH,w,maxH); //画一个盘子
y-=maxH;
}
}
static int count;
private int sleep;
private JTextField timesComp;
/**
* @param n 数目
* @param sleep 间隔时间
*/
public void start(int n,int sleep,JTextField timesComp){
if(inWork){
return;
}
this.count=n;
this.sleep=sleep;
this.timesComp=timesComp; //引入用户输入的参数:圆盘数目、间隔时间,填充移动次数的文本框timesComp
this.moveCount=0; //初始化用于反馈的移动次数moveCount
src.clear();
mid.clear();
tag.clear();
for(int i=0;i < count;i++){
src.push(i); //压栈src:从0到count-1
}
new Thread(this).start(); //启动线程,调用run()
}
boolean suspended=false;
boolean inWork;
public void run(){ //实现线程
inWork=true;
try{
move(count,src,tag,mid);
}
finally{
inWork=false;
}
}
int suspend;
int action=1;
public void suspend() { //暂停
suspend=1;
}
public void resume(){ //继续
suspend=2;
action=2;
}
/***********************************************************************************************************************/
/*******************************手动解题*********************************************************************************/
/***********************************************************************************************************************/
Boolean isImpact=false; //标记鼠标是否在盘子上
Boolean isPressed=false; //标记鼠标是否按下
public int x,y