【Java+swing】实现⾃动演⽰的汉诺塔⼩游戏
⽬录
1 算法与问题描述
1.1 问题描述
图1-1 汉诺塔
假设有三个命名为a(TOWER 1),b(TOWER 2),c(TOWER 3)的塔座如图1-1所⽰,在塔座X上有n个直径⼤⼩各不相同,依次从⼩到⼤编号为1,2,3,...,n的圆盘。现要求将a塔座上的n个圆盘移到c塔座上并按同样顺序叠排, 圆盘移动时必须遵循下列规则:
(1)每次只能移动⼀个圆盘;
(2)圆盘可以插在a,b,c中的任意塔座上;
(3)任何时刻都不能将⼀个较⼤的圆盘压在较⼩的圆盘之上。
1.2 递归算法
定义N为圆盘数量:
当N=1时,A>C;
当N=2时,A>B | | A>C | | B>C;
当N=3时,A>C,A>B,C>B | | A>C | | B>A,B>C,A>C;
...
代码及代码思路:
javaswing和javafxpublic static void hanoi(int n,char a,char b,char c ) {
if(n==1) System.out.println(a+">"+c);
else {
/
/1
hanoi(n-1,a,c,b);
//2
System.out.println(a+">"+c);
//3
hanoi(n-1,b,a,c);
}
}
利⽤了分治法的思想
第⼀步 对于执⾏最⼤盘(N)到C的操作之前,即把盘(N-1)从A到B操作;
第⼆步 执⾏最⼤盘(N) 到C的操作;
第三步 对于执⾏最⼤盘(N)到C的操作之后,即把盘(N-1)从B到C操作;
每次只关⼼上⼀层,上上层是到了上⼀层才考虑的事------递归
1.3 ⾮递归算法
⾮递归⽅式即规律:
A号柱有n 个盘⼦,叫做源柱.移往C 号柱,叫做⽬的柱.B 号柱叫做中间柱.
全部移往C 号柱要f(n) =(2^n)- 1 次.
最⼤盘n 号盘在整个移动过程中只移动⼀次,n-1 号移动2 次,i 号盘移动
2^(n-i)次.
1 号盘移动次数最多,每
2 次移动⼀次.
第2k+1 次移动的是1 号盘,且是第k+1 次移动1 号盘.
第4k+2 次移动的是2 号盘,且是第k+1 次移动2 号盘.
第(2^s)k+2^(s-1)次移动的是s 号盘,这时s 号盘已被移动了k+1 次.
每2^s 次就有⼀次是移动s 号盘.
第⼀次移动s 号盘是在第2^(s-1)次.
第⼆次移动s 号盘是在第2^s+2^(s-1)次.
第k+1 次移动s 号盘是在第k*2^s+2^(s-1)次.
A-->B,B-->C,C-->A叫做顺时针⽅向,A-->C,C-->B,B-->A叫做逆时针⽅向.
最⼤盘n 号盘只移动⼀次:A-->C它是逆时针移动.
n-1 移动2 次:A-->B,B-->C,是顺时针移动.
代码及代码思路:
public static void hanoi_f(int n) {
int s;// 从上到下⼏号盘
long i, t, k;
long res = (1 << n) - 1;
for (i = 1; i <= res; i++) {
for (t = 2, s = 1; s <= n; s++, t *= 2)
if (i % t == t / 2)
break;//第i步移动的s号盘
k = i / t;// 获得第s盘第⼏次移动
if (n % 2 == s % 2) {// 逆时针
if ((k + 1) % 3 == 0)
System.out.println(s + " from B to A");
if ((k + 1) % 3 == 1)
System.out.println(s + " from A to c");
if ((k + 1) % 3 == 2)
System.out.println(s + " from C to B");
} else {// 顺时针
if ((k + 1) % 3 == 0)
System.out.println(s + " from C to A");
if ((k + 1) % 3 == 1)
System.out.println(s + " from A to B");
if ((k + 1) % 3 == 2)
System.out.println(s + " from B to C");
}
}
}
枚举 1, 2, 3, 4·····i, i+1, i+2, ·····步。
第⼀步 先获取第i步移动的⼏号盘,根据 (2^s)k+2^(s-1)=i,转化⼀下,满⾜ i%(2^s) =2^(s-1) ,令t=2^s;则有i%t=t/2;第⼆步 再获得第S盘 第⼏次移动 ,根据 (2^s)k+2^(s-1)=i, k=i/(2^s) ,即 k=i/t;
第三步 最后根据周期T 与奇偶性 确定具体移动的步骤
2 游戏程序的总体设计
在设计hannoi塔时,需编写6个java源⽂件:HannoiWindow.java、Tower.java、TowerPoint.java、Disc.java、HandleMouse.java和AutoMoveDisc.java。
Hannoi塔除了要编写的6个Java源⽂件所给出的类外,还需要Java系统提供的⼀些重要的类,如JMenuBar、JMenu、JMenuItem和JButton。Hannoi塔所⽤到的⼀些重要的类以及之间的组合关系如图2-1所⽰:
图2-1 类之间的组合联系
2.1 HannoiWindow类设计
HannoiWindow类负责创建Hannoi塔的主窗⼝,该类含有main⽅法,Hannoi塔从该类开始执⾏。
HannoiWindow类的成员变量中有五种重要类型的对象、⼀个int基本型数据和⼀个char型数组。五种
类型的对象分别是:Tower、JMenuBar、JMenu、JMenuItem和JButton对象。
事件实现窗⼝间的变化,根据变量amountOfDisc的不同更换游戏级别,即disc的个数;
代码:
package hannuota;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
public class HannoiWindow extends JFrame implements ActionListener {
Tower tower = null;
int amountOfDisc = 3;
char[] towerName = { 'A', 'B', 'C' };
JMenuBar bar;
JMenu menuGrade;
JMenuItem oneGradeItem, twoGradeItem, threeGradeItem;
JMenuItem oneGradeItem, twoGradeItem, threeGradeItem;
JButton renew = null;
JButton autoButton = null;
JPanel center = new JPanel();
HannoiWindow() {
tower = new Tower(towerName);
tower.setAmountOfDisc(amountOfDisc);
tower.setMaxDiscWidth(120);
tower.setMinDiscWidth(50);
tower.setDiscHeight(16);
tower.putDiscOnTower();
add(tower, BorderLayout.CENTER);
bar = new JMenuBar();
menuGrade = new JMenu("选择级别");
oneGradeItem = new JMenuItem("初级");
twoGradeItem = new JMenuItem("中级");
threeGradeItem = new JMenuItem("⾼级");
menuGrade.add(oneGradeItem);
menuGrade.add(twoGradeItem);
menuGrade.add(threeGradeItem);
bar.add(menuGrade);
setJMenuBar(bar);
oneGradeItem.addActionListener(this);
twoGradeItem.addActionListener(this);
threeGradeItem.addActionListener(this);
renew = new JButton("重新开始");
renew.addActionListener(this);
autoButton = new JButton("⾃动演⽰");
autoButton.addActionListener(this);
JPanel north = new JPanel();
north.add(renew);
north.add(autoButton);
String mess = "将全部盘⼦从" + towerName[0] + "座搬运到" + towerName[1] + "座或" + towerName[2] + "座"; JLabel hintMess = new JLabel(mess, JLabel.CENTER);
north.add(hintMess);
add(north, BorderLayout.NORTH);
setResizable(false);
setVisible(true);
setBounds(60, 60, 460, 410);
//确保组件具有有效的布局
validate();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == oneGradeItem) {
amountOfDisc = 3;
tower.setAmountOfDisc(amountOfDisc);
tower.putDiscOnTower();
} else if (e.getSource() == twoGradeItem) {
amountOfDisc = 4;
tower.setAmountOfDisc(amountOfDisc);
tower.putDiscOnTower();
} else if (e.getSource() == threeGradeItem) {
amountOfDisc = 5;
tower.setAmountOfDisc(amountOfDisc);
tower.putDiscOnTower();
} else if (e.getSource() == renew) {
tower.setAmountOfDisc(amountOfDisc);
tower.putDiscOnTower();
} else if (e.getSource() == autoButton) {
tower.setAmountOfDisc(amountOfDisc);
tower.putDiscOnTower();
int x = Bounds().x + Bounds().width;
int y = Bounds().y;
int y = Bounds().y;
}
validate();
}
public static void main(String args[]) {
new HannoiWindow();
}
}
2.2 Tower类设计
Tower类是javax.swing包中Jpanel容器的⼦类,创建的容器被添加到HannoiWindow窗⼝的中⼼。
Tower类的成员变量中有四种重要类型的对象、⼀个int基本型数据和⼀个char型数组。四种类型的对象分别是:Disc、TowerPoint、HandleMouse、和AutoMoveDisc对象。
代码:
package hannuota;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Tower extends JPanel {
int amountOfDisc = 3;
Disc[] disc;
int maxDiscWidth, minDiscWidth, discHeight;
char[] towerName;
TowerPoint[] pointA, pointB, pointC;
HandleMouse handleMouse;
AutoMoveDisc autoMoveDisc;
Tower(char[] towerName) {
handleMouse = new HandleMouse(this);
setLayout(null);
setBackground(new Color(200, 226, 226));
}
public void setAmountOfDisc(int number) {
if (number <= 1)
amountOfDisc = 1;
else
amountOfDisc = number;
}
public void setMaxDiscWidth(int m) {
maxDiscWidth = m;
}
public void setMinDiscWidth(int m) {
minDiscWidth = m;
}
public void setDiscHeight(int h) {
discHeight = h;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论