📄 hanoitower.java
字号:
import java.applet.* ;
import java.awt.* ;
import java.net.* ;
import java.util.* ;
import javax.swing.*;
import java.awt.event.*;
public class HanoiTower extends JApplet implements Runnable //$主类用于初始化applet panel,开始游戏,
{ //$运行自动演示线程和处理用鼠标移动事件
static final Font titleFont=new Font("Helvetica", Font.BOLD, 20),//$定义一些字体常量
textFont=new Font("Helvetica", Font.PLAIN, 20),
monoFont=new Font("Courier", Font.BOLD, 20) ;
static final int CANVAS_WIDTH=450, CANVAS_HEIGHT=250, //$定义画布大小及盘子的最大最小值
TABLE_TOP=225,MIN_DISCS=3, MAX_DISCS=12 ;
public int PEG1=0, PEG2=1, PEG3=2; //$定义三个值代表三个柱子
private boolean gameOver,suspendFlag,stepFlag ;//$游戏结束、线程挂起、单步运行
private int sourceDisc, sourcePeg, targetPeg; //$源盘、源柱、目标柱
private String gameStatus ; //$游戏状态
private JPanel cp1Back,cp2Back, titlePanel ; //$控制面板1、2和标题面板
private JLabel titleLabel ; //$标题标签
private Board bd ; //$自定义类描述盘子存储结构
private BoardCanvas bc ; //$自定义类描述盘子外观
private StatusPanel sp ; //$自定义类描述状态面板
private ControlPanelOne cp1 ; //$自定义类描述控制面板1、2
private ControlPanelTwo cp2 ;
private Image boardImage ;
private String boardImageFile = "board.gif" ; //$背景图片
public Thread solveThread, timer ; //$自动线程和时间线程
public void init()
{
// load board image
MediaTracker tracker = new MediaTracker(this) ;//$装载并跟踪图片
URL url = getCodeBase() ;
boardImage = getImage(url,boardImageFile) ;
tracker.addImage(boardImage,0) ;
try { tracker.waitForID(0); }
catch (InterruptedException e) {}
// initialize applet layout
setBackground(Color.gray) ; //$主面板初始化
JPanel mainPanel = new JPanel() ;
mainPanel.setLayout(new BorderLayout(0,0)) ; //$BorderLayout布局
// BoardCanvas
bc = new BoardCanvas(this) ;
bc.resize(CANVAS_WIDTH,CANVAS_HEIGHT) ;
// Title panel
titlePanel = new JPanel() ;
titlePanel.setLayout(new GridLayout(1,1)) ;
titlePanel.setBackground(Color.gray) ;
titlePanel.setFont(titleFont) ;
titlePanel.add(titleLabel=new JLabel(" Tower of Hanoi made by Wangyue.",JLabel.CENTER)) ;
titleLabel.setForeground(Color.white) ;
// Control Panel one
cp1Back = new JPanel() ;
cp1Back.setBackground(Color.gray) ;
cp1 = new ControlPanelOne(this) ;
cp1Back.add(cp1) ;
//Control Panel two
cp2Back = new JPanel() ;
cp2Back.setBackground(Color.gray) ;
cp2 = new ControlPanelTwo(this) ;
cp2Back.add(cp2) ;
// Status panel
sp = new StatusPanel(this) ;
sp.setBackground(Color.gray) ;
// construct applet panel
mainPanel.add("Center",bc) ;
mainPanel.add("North",titlePanel) ;
mainPanel.add("West",cp1Back) ;
mainPanel.add("East",cp2Back) ;
mainPanel.add("South",sp) ;
add(mainPanel) ;
validate() ; //$使布局生效
newGame() ; //$开始游戏
}
// startup
void newGame() //$开始游戏
{
int discs = cp1.getDiscs() ;//$得到盘子数
System.gc() ; //$内存回收
gameOver = false ;
suspendFlag=false;
stepFlag=true;
bd = new Board(discs,this) ;
bc.drawBoard(bd,boardImage,0,0,0) ;
sp.setMoveCount(0) ;
if (cp2.isTimerOn) timer = new Timer(cp2) ; //$计时
else cp2.setTimer(" ") ;
if (solveThread == null) //$状态条
sp.setStatus("Move all " + discs + " discs to the rightmost peg.") ;
bc.requestFocus() ; //$得到焦点
}
// handle Reset event
void restartGame() //$重新开始游戏
{
stop() ;
cp1.setAutoSolveEnable(true) ;
newGame() ;
}
// kill all threads
public void stop() //$停止游戏
{
if (solveThread!=null) {
solveThread.stop() ;
solveThread = null ;
}
if (timer!=null) {
timer.stop() ;
timer = null ;
}
}
// spawn Autosolve thread
public void startSolveThread() //$自动运行
{
stop() ;
solveThread = new Thread(this) ;
solveThread.start() ;
}
// run Autosolve thread
public void run() //$start()调用
{
newGame() ;
sp.setStatus("Autosolving ...") ;
solve(cp1.getDiscs(),PEG1,PEG2,PEG3) ; //$递归
sp.setStatus("Finished!") ;
gameOver = true ;
solveThread = null ;
cp1.setAutoSolveEnable(true) ;
}
//when Autosolve to show status bar
public void showstatusbar(int source,int target) //$演示过程
{
sp.setStatus("Now move from peg"+(source+1) + " to peg" + (target+1)+ ".") ;
}
public void mysuspend() //$线程的挂起
{
suspendFlag=true;
}
synchronized void myresume() //$线程的返回
{
suspendFlag=false;
notify();
}
public void step() //$单步运行
{
//myresume();
suspendFlag=!suspendFlag;
notify();
//stepFlag=!stepFlag;
}
// here's the famous algorithm
void solve(int discs,int source,int aux,int target) //$递归
{
synchronized (this)
{
while(suspendFlag)
{
try
{
wait();
}
catch(InterruptedException e){}
}
}
if (discs==0) return ; // base to end recursion
solve(discs-1,source,target,aux) ; // recursive call #1
bd.moveDisc(source,target) ; // move disc
sp.setMoveCount(bd.getMoveCount()) ; // update display
showstatusbar(source,target);
bc.drawBoard(bd,boardImage,0,0,0) ;
try { solveThread.sleep(cp1.getDelay()) ; } // Autosolve delay
catch (InterruptedException e) {}
/*while(!stepFlag)
{
try { solveThread.sleep(cp1.getDelay()) ; } // Autosolve delay
catch (InterruptedException e) {}
}*/
solve(discs-1,aux,source,target) ; // recursive call #2
}
// handle mouse drag event
void dragDisc(int x,int y) {
if (!gameOver&&(sourceDisc!=0)) //$如果源盘子存在
bc.drawBoard(bd,boardImage,sourceDisc,x,y) ;
}
// handle mouse down event
void selectDisc(int x,int y) {
if (!gameOver&&(solveThread==null)) {
if ((timer!=null)&&(!timer.isAlive())) timer.start() ;
sourcePeg = pixelToPeg(x,y) ;
if (bd.isStartPeg(sourcePeg)) //$如果此柱上有盘子
{
sourceDisc = bd.getTopDisc(sourcePeg) ;
bc.drawBoard(bd,boardImage,sourceDisc,x,y) ;
}
}
}
// handle mouse up event
void dropDisc(int x,int y)
{
if (!gameOver&&(sourceDisc!=0)) //$如果取到盘子
{
targetPeg = pixelToPeg(x,y) ;
if (bd.moveDisc(sourceDisc,sourcePeg,targetPeg))
{
gameStatus = bd.getBoardStatus() ;
sp.setMoveCount(bd.getMoveCount()) ;
if (gameStatus==null)
sp.setStatus("The minimum number of moves required is " +
bd.getMinMoves() + ".") ;
else
{
gameOver = true ;
stop() ;
sp.setStatus(gameStatus) ;
}
}
bc.drawBoard(bd,boardImage,0,0,0) ;
sourceDisc = 0 ;
}
}
// conversion for mouse down/up events
int pixelToPeg(int x,int y) //$是否在有效范围内
{
int peg = -1 ;
if ((y>40)&&(y<TABLE_TOP))
{
if ((x>50)&&(x<100)) peg = PEG1 ;
else if ((x>200)&&(x<250)) peg = PEG2 ;
else if ((x>350)&&(x<400)) peg = PEG3 ;
}
return peg ;
}
}
final class Timer extends Thread //$时间线程
{
static final int ONE_SECOND=1000 ; //$单位时间一秒
private long startTime, rem ;
private int hours, min, sec ;
private String sMin, sSec, sTime ;
private ControlPanelTwo cp2 ;
// constructor
Timer(ControlPanelTwo cp2) //$构造函数
{
this.cp2 = cp2 ;
cp2.setTimer(setTime(0)) ; //$设置时间
}
// run thread
public void run()
{
startTime = System.currentTimeMillis() ;
while (true) {
try { Thread.sleep(ONE_SECOND) ; } //$等待一秒
catch (InterruptedException e) {}
cp2.setTimer(setTime(System.currentTimeMillis() - startTime)) ;
}
}
// return h:mm:ss string from milliseconds
String setTime(long millisec) //$将毫秒数转化为对应小时、分、秒
{
hours = (int)(millisec/3600000) ;
rem = millisec - (hours*3600000) ;
min = (int)(rem/60000) ;
rem = rem - (min*60000) ;
sec = (int)(rem/1000) ;
sMin = Integer.toString(min) ;
if (sMin.length()==1) sMin = "0" + sMin ;
sSec = Integer.toString(sec) ;
if (sSec.length()==1) sSec = "0" + sSec ;
sTime = " " + Integer.toString(hours) + ":" + sMin + ":" + sSec ;
return sTime ;
}
}
final class Board //$自定义类描述盘子存储结构和移动规则
{
static final int PEGS=3,
DISC_SIZES[][]={ {68,18},{76,16},{84,14},{92,13},{100,12},
{108,12},{112,11},{116,10},{120,9},{124,9} } ;
private int peg[][], pegTop[]=new int[PEGS], discWidth[] ;
private int discs, moveCount, minMoves ;
private HanoiTower main ; //$主面板类
// constructor
Board(int discs,HanoiTower main) //$构造函数
{
this.discs = discs ;
this.main = main ;
peg = new int[discs][PEGS] ;
// put all the disks on the first peg
for (int i=0; i<discs; i++) //$存储结构初始化
peg[i][main.PEG1] = discs-i ;
pegTop[main.PEG1] = discs-1 ;//$记录每个柱子盘子
for (int i=1; i<PEGS; i++) pegTop[i] = -1 ;
// calculate disc widths
discWidth = new int[discs] ; //$计算盘子宽度
for (int i=discs-1; i>=0; i--)
discWidth[i] = DISC_SIZES[discs-main.MIN_DISCS][0] -
(DISC_SIZES[discs-main.MIN_DISCS][1] *
(discs-1-i)) ;
moveCount = 0 ;
// minimum moves is (2**discs)-1
minMoves = ((int)Math.pow(2.0,discs)) - 1 ; //$算出最少移动次数
}
void setDisc(int d,int p) { peg[++pegTop[p]][p] = d ; }
int getDisc(int d,int p) { return peg[d][p] ; }
int getTopDisc(int p) { return peg[pegTop[p]--][p] ; }
int getPegTop(int p) { return pegTop[p] ; }
int getMoveCount() {return moveCount ; }
int getMinMoves() {return minMoves ; }
int getDiscWidth(int d) { return discWidth[d-1] ; }
boolean isStartPeg(int i) //$是否有盘子
{
if ((i >= 0)&&(pegTop[i]>=0)) return true ;
else return false ;
}
String getBoardStatus() //$游戏结束返回状态信息
{
String status = null ;
if (pegTop[PEGS-1]==(discs - 1))
{
if (moveCount==minMoves)
status = "Congratulations!" ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -