In JAVA - Use the Towers of Hanoi Recursive algorithm. Instead of printing messa
ID: 3577019 • Letter: I
Question
In JAVA - Use the Towers of Hanoi Recursive algorithm. Instead of printing messages to the console, draw disks and towers, and show the disks moving in accord with the algorithm. (Please have comments.) Thanks for your help.
The Towers of Hanoi Recursive algorithm is below
public class RecursionTower {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
tower(3, 'A', 'B', 'C');
}
public static void tower(int numDisk, char from, char use, char to) {
if (numDisk == 1) {
move(numDisk, from, to);
} else {
tower(numDisk - 1, from, to, use);
move(numDisk, from, to);
tower(numDisk - 1, use, from, to);
}
}
public static void move(int num, char from, char to) {
System.out.println(" Disk " + num + " moved from " + from + " to " + to);
}
}
Explanation / Answer
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.BufferedImage;
public class TowersOfHanoi extends JPanel implements Runnable, ActionListener {
public static void main(String[] args) {
JFrame window = new JFrame("Towers Of Hanoi");
window.setContentPane(new TowersOfHanoi());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.pack();
window.setResizable(true);
window.setLocation(300,200);
window.setVisible(true);
}
private static Color BACKGROUND_COLOR = new Color(255,255,180); // 4 colors used in drawing.
private static Color BORDER_COLOR = new Color(100,0,0);
private static Color DISK_COLOR = new Color(0,0,180);
private static Color MOVE_DISK_COLOR = new Color(180,180,255);
private BufferedImage OSC; // The off-screen canvas. Frames are drawn here, then copied to the screen.
private int status; // Controls the execution of the thread; value is one of the following constants.
private static final int GO = 0; // a value for status, meaning thread is to run continuously
private static final int PAUSE = 1; // a value for status, meaning thread should not run
private static final int STEP = 2; // a value for status, meaning thread should run one step then pause
private static final int RESTART = 3; // a value for status, meaning thread should start again from the beginning
/*
The following variables are the data needed for the animation. The
three "piles" of disks are represented by the variables tower and
towerHeight. towerHeight[i] is the number of disks on pile number i.
For i=0,1,2 and for j=0,1,...,towerHeight[i]-1, tower[i][j] is an integer
representing one of the ten disks. (The disks are numbered from 1 to 10.)
During the solution, as one disk is moved from one pile to another,
the variable moveDisk is the number of the disk that is being moved,
and moveTower is the number of the pile that it is currently on.
This disk is not stored in the tower variable. It is drawn in a
different color from the other disks.
*/
private int[][] tower;
private int[] towerHeight;
private int moveDisk;
private int moveTower;
private Display display; // A subpanel where the frames of the animation are shown.
private JButton runPauseButton; // 3 control buttons for controlling the animation
private JButton nextStepButton;
private JButton startOverButton;
/**
* This class defines the panel that is used as a display, to show
* the frames of the animation. The paintComponent() method in this
* class simply copies the off-screen canvas, OSC, to the screen.
* This display will be given a preferred size of 430-by-143, which
* is the same size as the canvas. But to allow for possible small
* variations from this size, OSC is drawn centered on the panel.
*/
private class Display extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (getWidth() - OSC.getWidth())/2;
int y = (getHeight() - OSC.getHeight())/2;
g.drawImage(OSC, x, y, null);
}
}
/**
* Create the panel, containing a display panel and, beneath it,
* a sub-panel containing the three control buttons. This
* constructor also creates the off-screen canvas, and creates
* and starts the animation thread.
*/
public TowersOfHanoi () {
OSC = new BufferedImage(430,143,BufferedImage.TYPE_INT_RGB);
display = new Display();
display.setPreferredSize(new Dimension(430,143));
display.setBorder(BorderFactory.createLineBorder(BORDER_COLOR, 2));
display.setBackground(BACKGROUND_COLOR);
setLayout(new BorderLayout());
add(display, BorderLayout.CENTER);
JPanel buttonBar = new JPanel();
add(buttonBar, BorderLayout.SOUTH);
buttonBar.setLayout(new GridLayout(1,0));
runPauseButton = new JButton("Run");
runPauseButton.addActionListener(this);
buttonBar.add(runPauseButton);
nextStepButton = new JButton("Next Step");
nextStepButton.addActionListener(this);
buttonBar.add(nextStepButton);
startOverButton = new JButton("Start Over");
startOverButton.addActionListener(this);
startOverButton.setEnabled(false);
buttonBar.add(startOverButton);
new Thread(this).start();
}
/**
* Event-handling method for the control buttons. Changes in the
* value of the status variable will be seen by the animation thread,
* which will respond appropriately.
*/
synchronized public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == runPauseButton) { // Toggle between running and paused.
if (status == GO) { // Animation is running. Pause it.
status = PAUSE;
nextStepButton.setEnabled(true);
runPauseButton.setText("Run");
}
else { // Animation is paused. Start it running.
status = GO;
nextStepButton.setEnabled(false); // Disabled when animation is running
runPauseButton.setText("Pause");
}
}
else if (source == nextStepButton) { // Set status to make animation run one step.
status = STEP;
}
else if (source == startOverButton) { // Set status to make animation restart.
status = RESTART;
}
notify(); // Wake up the thread so it can see the new status value!
}
/**
* The run() method for the animation thread. Runs in an infinite loop.
* In the loop, the thread first sets up the initial state of the "towers"
* and of the buttons. This includes setting the status to PAUSED, and
* calling checkStatus(), which will not return until the user clicks the
* "Run" button or the "Next" Button. Once this happens, it calls
* the solve() method to run the recursive algorithm that solve the
* Towers Of Hanoi problem. During the solution, checkStatus() is
* called after each move. If the user clicks the "Start Again" button,
* checkStatus() will throw an IllegalStateException, which will cause
* the solve() method to be aborted. The exception is caught to prevent
* it from crashing the thread.
*/
public void run() {
while (true) {
runPauseButton.setText("Run");
nextStepButton.setEnabled(true);
startOverButton.setEnabled(false);
setUpProblem(); // Sets up the initial state of the puzzle
status = PAUSE;
checkStatus(); // Returns only when user has clicked "Run" or "Next"
startOverButton.setEnabled(true);
try {
solve(10,0,1,2); // Move 10 disks from pile 0 to pile 1.
}
catch (IllegalStateException e) {
// Exception was thrown because user clicked "Start Over".
}
}
}
synchronized private void checkStatus() {
while (status == PAUSE) {
try {
wait();
}
catch (InterruptedException e) {
}
}
// At this point, status is RUN, STEP, or RESTART.
if (status == RESTART)
throw new IllegalStateException("Restart");
// At this point, status is RUN or STEP.
}
synchronized private void setUpProblem() {
moveDisk= 0;
tower = new int[3][10];
for (int i = 0; i < 10; i++)
tower[0][i] = 10 - i;
towerHeight = new int[3];
towerHeight[0] = 10;
if (OSC != null) {
Graphics g = OSC.getGraphics();
drawCurrentFrame(g);
g.dispose();
}
display.repaint();
}
private void solve(int disks, int from, int to, int spare) {
if (disks == 1)
moveOne(from,to);
else {
solve(disks-1, from, spare, to);
moveOne(from,to);
solve(disks-1, spare, to, from);
}
}
synchronized private void moveOne(int fromStack, int toStack) {
moveDisk = tower[fromStack][towerHeight[fromStack]-1];
moveTower = fromStack;
delay(120);
towerHeight[fromStack]--;
putDisk(MOVE_DISK_COLOR,moveDisk,moveTower);
delay(80);
putDisk(BACKGROUND_COLOR,moveDisk,moveTower);
delay(80);
moveTower = toStack;
putDisk(MOVE_DISK_COLOR,moveDisk,moveTower);
delay(80);
putDisk(DISK_COLOR,moveDisk,moveTower);
tower[toStack][towerHeight[toStack]] = moveDisk;
towerHeight[toStack]++;
moveDisk = 0;
if (status == STEP)
status = PAUSE;
checkStatus();
}
/**
* Simple utility method for inserting a delay of a specified
* number of milliseconds.
*/
synchronized private void delay(int milliseconds) {
try {
wait(milliseconds);
}
catch (InterruptedException e) {
}
}
private void putDisk(Color color, int disk, int t) {
Graphics g = OSC.getGraphics();
g.setColor(color);
g.fillRoundRect(75+140*t - 5*disk - 5, 116-12*towerHeight[t], 10*disk+10, 10, 10, 10);
g.dispose();
display.repaint();
}
synchronized private void drawCurrentFrame(Graphics g) {
g.setColor(BACKGROUND_COLOR);
g.fillRect(0,0,430,143);
g.setColor(BORDER_COLOR);
if (tower == null)
return;
g.fillRect(10,128,130,5);
g.fillRect(150,128,130,5);
g.fillRect(290,128,130,5);
g.setColor(DISK_COLOR);
for (int t = 0; t < 3; t++) {
for (int i = 0; i < towerHeight[t]; i++) {
int disk = tower[t][i];
g.fillRoundRect(75+140*t - 5*disk - 5, 116-12*i, 10*disk+10, 10, 10, 10);
}
}
if (moveDisk > 0) {
g.setColor(MOVE_DISK_COLOR);
g.fillRoundRect(75+140*moveTower - 5*moveDisk - 5, 116-12*towerHeight[moveTower],
10*moveDisk+10, 10, 10, 10);
}
}
} // end class TowersOfHanoi
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.