📄 hanoi11.java
字号:
/**********************************************************
Hanoi11.java - Tower of Hanoi puzzle
Version 1.1
by Bob Kirkland
bob@mazeworks.com
1.1 - added Timer, Title bar
removed CC class
**********************************************************/
import java.applet.* ;
import java.awt.* ;
import java.net.* ;
import java.util.* ;
/******** HANOI11 ********
main class: initializes applet panel, starts games,
runs autosolve thread, handles disc moving events
*/
public class Hanoi11 extends Applet implements Runnable {
static final Font titleFont=new Font("Helvetica", Font.BOLD, 12),
textFont=new Font("Helvetica", Font.PLAIN, 11),
monoFont=new Font("Courier", Font.BOLD, 12) ;
static final int CANVAS_WIDTH=450, CANVAS_HEIGHT=250, TABLE_TOP=225,
PEG1=0, PEG2=1, PEG3=2, MIN_DISCS=3, MAX_DISCS=12 ;
private boolean gameOver ;
private int sourceDisc, sourcePeg, targetPeg ;
private String gameStatus ;
private Panel cpBack, titlePanel ;
private Label titleLabel ;
private Board bd ;
private BoardCanvas bc ;
private StatusPanel sp ;
private ControlPanel cp ;
private Image boardImage ;
private String boardImageFile = "board.gif" ;
private 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.black) ;
Panel mainPanel = new Panel() ;
mainPanel.setLayout(new BorderLayout(0,0)) ;
// BoardCanvas
bc = new BoardCanvas(this) ;
bc.resize(CANVAS_WIDTH,CANVAS_HEIGHT) ;
// Title panel
titlePanel = new Panel() ;
titlePanel.setLayout(new GridLayout(1,1)) ;
titlePanel.setBackground(Color.gray) ;
titlePanel.setFont(titleFont) ;
titlePanel.add(titleLabel=new Label(" Tower of Hanoi 1.1",Label.LEFT)) ;
titleLabel.setForeground(Color.white) ;
// Control Panel
cpBack = new Panel() ;
cpBack.setBackground(Color.gray) ;
cp = new ControlPanel(this) ;
cpBack.add(cp) ;
// Status panel
sp = new StatusPanel(this) ;
sp.setBackground(Color.gray) ;
// construct applet panel
mainPanel.add("Center",bc) ;
mainPanel.add("North",titlePanel) ;
mainPanel.add("East",cpBack) ;
mainPanel.add("South",sp) ;
add(mainPanel) ;
validate() ;
newGame() ;
}
// startup
void newGame() {
int discs = cp.getDiscs() ;
System.gc() ;
gameOver = false ;
bd = new Board(discs,this) ;
bc.drawBoard(bd,boardImage,0,0,0) ;
sp.setMoveCount(0) ;
if (cp.isTimerOn()) timer = new Timer(cp) ;
else cp.setTimer(" ") ;
if (solveThread == null)
sp.setStatus("Move all " + discs + " discs to the rightmost peg.") ;
bc.requestFocus() ;
}
// handle Reset event
void restartGame() {
stop() ;
cp.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() {
newGame() ;
sp.setStatus("Autosolving ...") ;
solve(cp.getDiscs(),PEG1,PEG2,PEG3) ;
sp.setStatus("Finished!") ;
gameOver = true ;
solveThread = null ;
cp.setAutoSolveEnable(true) ;
}
// here's the famous algorithm
void solve(int discs,int source,int aux,int target) {
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
bc.drawBoard(bd,boardImage,0,0,0) ;
try { solveThread.sleep(cp.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 ;
}
}
/******** TIMER ********
controls Timer thread
*/
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 ControlPanel cp ;
// constructor
Timer(ControlPanel cp) {
this.cp = cp ;
cp.setTimer(setTime(0)) ;
}
// run thread
public void run() {
startTime = System.currentTimeMillis() ;
while (true) {
try { Thread.sleep(ONE_SECOND) ; }
catch (InterruptedException e) {}
cp.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 ;
}
}
/******** BOARD ********
controls disc positions, rules for moving discs
*/
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 Hanoi11 main ;
// constructor
Board(int discs,Hanoi11 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 ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -