Design and implement a graphic version of the Towers of Hanoi puzzle. Allow the
ID: 664505 • Letter: D
Question
Design and implement a graphic version of the Towers of Hanoi puzzle. Allow the user to set the number of disks used in the puzzle. The use should be able to interact with the puzzle in two main ways. The user can move the disks from one peg to another using the mouse, in which case the program should ensure that each move is legal. The user can also watch a solution take place as an animation, with pause/resume buttons. Permit the user to control the speed of the animation.
If you need to review fractals there are many illustrations and tutorials on line including this one: http://fractalfoundation.org/resources/what-are-fractals/
Explanation / Answer
/*
<APPLET CODE=hanoi.class WIDTH=400 HEIGHT=400>
</APPLET>
*/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class hanoi extends Applet {
private TextArea textA; // text output display
private Checkbox peg_a_src;
private Checkbox peg_b_src;
private Checkbox peg_c_src;
private Checkbox peg_a_dest;
private Checkbox peg_b_dest;
private Checkbox peg_c_dest;
private Disk[] diska; // disk characteristics object array
private Font font;
private static final int MAX_DISKS = 10; // maximum # disks permitted
private int numDisks;
private static final int INIT_NUM_DISKS = 2; // initial number of disks
private TextField textNDisks;
private static final int WIDTH_FACTOR = 8; // how wide disks show
// Disks indicate what peg and postition, mostly independent of graphics
// settings which are in paint(). Note that pegWidth is a graphical
// width in pixels, however.
class Disk {
private int pegNum; // 1, 2, or 3 for A, B, or C
private int pegStep; // which position: 1 at base, 2 next up, etc.
private int pegWidth; // graphical width set by constructor
Disk(int num, int step) {
pegNum = num;
pegStep = step;
pegWidth = 0;
}
void setPegNum(int num) {
pegNum = num;
}
void setPegStep(int step) {
pegStep = step;
}
void setPegWidth(int width) {
pegWidth = width;
}
int getPegNum() {
return pegNum;
}
int getPegStep() {
return pegStep;
}
int getPegWidth() {
return pegWidth;
}
}
// Create GUI, define button press event methods, initialize
public void init() {
setLayout(new BorderLayout());
setBackground(Color.white);
font = new Font("Helvetica", Font.BOLD, 24);
Panel p1 = new Panel();
p1.setLayout(new GridLayout(1, 3));
p1.setBackground(Color.cyan);
add("South", p1);
// Create A-B-C checkboxes in panels and labels
CheckboxGroup src_group = new CheckboxGroup();
peg_a_src = new Checkbox("A", false, src_group);
peg_b_src = new Checkbox("B", false, src_group);
peg_c_src = new Checkbox("C", false, src_group);
Panel pSrc = new Panel();
pSrc.setLayout(new GridLayout(3, 1));
pSrc.add(peg_a_src);
pSrc.add(peg_b_src);
pSrc.add(peg_c_src);
CheckboxGroup dest_group = new CheckboxGroup();
peg_a_dest = new Checkbox("A", false, dest_group);
peg_b_dest = new Checkbox("B", false, dest_group);
peg_c_dest = new Checkbox("C", false, dest_group);
Panel pDest = new Panel();
pDest.setLayout(new GridLayout(3, 1));
pDest.add(peg_a_dest);
pDest.add(peg_b_dest);
pDest.add(peg_c_dest);
Panel pChecks = new Panel();
pChecks.setLayout(new GridLayout(1, 2));
Label srcLabel = new Label("Source:");
Label destLabel = new Label("Dest:");
pChecks.add(pSrc);
pChecks.add(pDest);
Panel pCheckL = new Panel();
pCheckL.setLayout(new FlowLayout());
pCheckL.add(srcLabel);
pCheckL.add(destLabel);
Panel pCheckArea = new Panel();
pCheckArea.setLayout(new FlowLayout());
pCheckArea.add(pCheckL);
pCheckArea.add(pChecks);
// Move button and button press action
Button bMove = new Button("MOVE");
bMove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Insert disk movement message "backwards", including disks that
// are involved in the move
String message = " ";
textA.insert(" ", 0);
int i1 = 0;
int i2 = 0;
if (peg_a_src.getState() == true) {
message += "A->";
//textA.insert("A->", 0);
i1 = 1;
}
if (peg_b_src.getState() == true) {
message += "B->";
//textA.insert("B->", 0);
i1 = 2;
}
if (peg_c_src.getState() == true) {
message += "C->";
textA.insert("C->", 0);
i1 = 3;
}
if (peg_a_dest.getState() == true) {
message += "A";
//textA.insert("A", 0);
i2 = 1;
}
if (peg_b_dest.getState() == true) {
message += "B";
//textA.insert("B", 0);
i2 = 2;
}
if (peg_c_dest.getState() == true) {
message += "C";
//textA.insert("C", 0);
i2 = 3;
}
// Actual move occurs in here, and a message string such as "Disk
// moved" or "Failed" returned to display to the user.
textA.setText(towerMove(i1, i2) + message);
repaint();
}
});
// Reset button just places all pegs on first tower upon
// button action
Button bReset = new Button("RESET");
bReset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int i1;
for (i1 = 0; i1 < numDisks; i1++) {
diska[i1].setPegNum(1);
diska[i1].setPegStep(i1+1);
}
repaint();
// Get the number of disks from the # disks text input. Reset peg
// widths which may grow or shrink; make sure entry is not too large
// or small. Non-numeric entry resets to initial # of disks.
try {
numDisks = Integer.parseInt(textNDisks.getText());
}
catch (IllegalArgumentException ex) {
numDisks = INIT_NUM_DISKS;
}
if (numDisks > MAX_DISKS) {
numDisks = MAX_DISKS;
}
if (numDisks < 1) {
numDisks = 1;
}
textNDisks.setText("" + numDisks);
SetDiskWidths();
textA.insert("All disks RESET" + " ", 0);
}
});
// Create then initially set the number of disks
Label textL = new Label("# disks:");
textNDisks = new TextField("0");
textNDisks.setText("" + INIT_NUM_DISKS);
numDisks = Integer.parseInt(textNDisks.getText());
// Create buttons panel
Panel pOpts = new Panel();
pOpts.setLayout(new FlowLayout());
pOpts.add(bMove);
pOpts.add(bReset);
pOpts.add(textL);
pOpts.add(textNDisks);
textA = new TextArea("", 10, 40);
// Add panels to overall control panel
p1.add(pCheckArea);
p1.add(pOpts);
p1.add(textA);
// Initial disk object creation: create all of them now even if
// some aren't used for the initial number of disks
diska = new Disk[MAX_DISKS];
int i3;
for (i3 = 0; i3 < MAX_DISKS; i3++) {
diska[i3] = new Disk(1, i3 + 1);
}
SetDiskWidths();
}
// Upon redraw event this redraws based on current disk information
public void paint(Graphics g) {
// Draw titles in drawing area
g.setColor(Color.blue);
g.setFont(font);
g.drawString("Towers of Brahma", 105, 25);
g.drawString("A", 95, 190);
g.drawString("B", 195, 190);
g.drawString("C", 295, 190);
// Draw pegs with bases as simple black lines
g.setColor(Color.black);
g.fillRect(0, 200, 400, 4);
g.fillRect(60, 160, 84, 4);
g.fillRect(100, 40, 4, 124);
g.fillRect(160, 160, 84, 4);
g.fillRect(200, 40, 4, 124);
g.fillRect(260, 160, 84, 4);
g.fillRect(300, 40, 4, 124);
// Draw disks based on which peg they are on and their
// position on the pegs
g.setColor(Color.blue);
int i1;
for (i1 = 0; i1 < numDisks; i1++) {
g.fillRect(diska[i1].getPegNum() * 100 - diska[i1].getPegWidth() / 2 +2,
160 - diska[i1].getPegStep() * 10, diska[i1].getPegWidth(), 9);
}
}
// Set disk widths for when the number of disks is set or reset
public void SetDiskWidths() {
int i1;
for (i1 = 0; i1 < numDisks; i1++) {
diska[i1].setPegWidth((numDisks - i1) * WIDTH_FACTOR);
}
}
// Move from one peg to another: return status string
public String towerMove(int pegSrc, int pegDest) {
if (pegSrc == 0 || pegDest == 0)
return "No source/dest";
if (pegSrc == pegDest)
return "Same pegs";
//get source peg disk number
int i1;
for (i1 = numDisks - 1; i1 >= 1 - 1; i1--) {
if (diska[i1].getPegNum() == pegSrc)
break;
}
if (i1 < 0)
return "No source disk";
int i2;
for (i2 = numDisks - 1; i2 >= 1 - 1; i2--) {
if (diska[i2].getPegNum() == pegDest)
break;
}
// See if a larger base or no disk is on the destination
// peg
int pegWidth1;
int pegWidth2;
pegWidth1 = diska[i1].getPegWidth();
if (i2 >= 0) {
pegWidth2 = diska[i2].getPegWidth();
if (pegWidth1 >= pegWidth2) {
return "Disk too large";
}
}
// The disk can be moved to the new peg
if (i2 >= 0)
diska[i1].setPegStep(diska[i2].getPegStep() + 1);
else
diska[i1].setPegStep(1);
diska[i1].setPegNum(pegDest);
//check for win
int flag = 0;
for (i2 = numDisks - 1; i2 >= 0; i2--) {
if(diska[i2].getPegNum() != 3){
flag = 1;
break;
}
}
if(flag == 0) return "You Won !";
else return "Moved disk";
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.