// This is the towers of Hanoi problem
// using recursion

import java.awt.Toolkit;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

/**
 * A helper class to hold the disks
 */
class TowerStack extends Stack<Integer> {

    public void display(int x, int y, Graphics g) {
        for (int i = 0; i < size(); i++) {
            int width = 20 * get(i);
            g.setColor(Color.red);
            g.fillRoundRect(x - width / 2, y - 10 * (i + 1), width + 1, 10, 10, 10);
            g.setColor(Color.black);
            g.drawRoundRect(x - width / 2, y - 10 * (i + 1), width + 1, 10, 10, 10);
        } // end for
    } // end display
} // end TowerStack

/**
 * This program show the moves of the Towers of Hanoi puzzle
 * @author Bill Kraynek
 */
public class TowersOfHanoi {

    JFrame theFrame;
    JLabel promptN;
    int n;
    int moves;
    JTextField inputN;
    JPanel thePanel;
    JScrollPane inputPane;
    int width;
    int height;
    int xLeft;
    int xMiddle;
    int xRight;
    int yBottom;
    int yTop;
    int pegWidth;
    int pegSpace;
    Graphics g;
    TowerStack peg1 = new TowerStack();
    TowerStack peg2 = new TowerStack();
    TowerStack peg3 = new TowerStack();

    public TowersOfHanoi() {
        theFrame = new JFrame("Towers of Hanoi");
        Toolkit tk = Toolkit.getDefaultToolkit();
        width = tk.getScreenSize().width / 2;
        height = tk.getScreenSize().height / 2;
        theFrame.setSize(width, height);
        theFrame.setLocation(tk.getScreenSize().width / 4, tk.getScreenSize().height / 4);
        theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        theFrame.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
        xLeft = (int) (0.2 * width);
        xMiddle = (int) (0.5 * width);
        xRight = (int) (int) (0.8 * width);
        yBottom = (int) (0.75 * height);
        yTop = yBottom - 100;
        pegWidth = xLeft;
        pegSpace = (int) ((width - 3 * pegWidth) / 4.0);
        thePanel = new JPanel();
        promptN = new JLabel("Enter the number of disks (1-10) > ");
        thePanel.add(promptN);
        inputN = new JTextField(5);
        inputN.addActionListener(new inputNAction());
        thePanel.add(inputN);
        thePanel.setBackground(Color.orange);
        inputPane = new JScrollPane(thePanel);
        theFrame.add(thePanel);
        theFrame.setVisible(true);
        g = theFrame.getGraphics();
    }// end constructor

    public static void main(String[] args) {
        new TowersOfHanoi();
    } // end main

    public void moveDisks(int n, TowerStack start, TowerStack finish, TowerStack aux) {
        if (n == 0) {
            return;
        }
        moveDisks(n - 1, start, aux, finish);
        finish.push(start.pop());
        moves++;
        drawTowers(g);
        moveDisks(n - 1, aux, finish, start);
    } // end moveDisks

    public void drawLines(Graphics g) {
        g.drawLine(xLeft, yBottom, xLeft, yTop);
        g.drawLine(xMiddle, yBottom, xMiddle, yTop);
        g.drawLine(xRight, yBottom, xRight, yTop);
        g.drawLine(pegSpace, yBottom, pegSpace + pegWidth, yBottom);
        g.drawLine(2 * pegSpace + pegWidth, yBottom, 2 * pegSpace + 2 * pegWidth, yBottom);
        g.drawLine(3 * pegSpace + 2 * pegWidth, yBottom, 3 * pegSpace + 3 * pegWidth, yBottom);
    }

    public void drawTowers(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 75, width, height - 75);
        g.setColor(Color.red);
        drawLines(g);
        peg1.display(xLeft, yBottom, g);
        peg2.display(xMiddle, yBottom, g);
        peg3.display(xRight, yBottom, g);
        try {
            Thread.sleep(501);
        } catch (Exception e) {
        }
    } // end drawTowers

    class inputNAction implements ActionListener {

        public void actionPerformed(ActionEvent A) {
            try {
                n = Integer.parseInt(inputN.getText());
            } catch (NumberFormatException e) {
                inputN.setText("1 to 10");
                inputN.selectAll();
                return;
            } // end try/catch
            if (n < 1 || n > 10) {
                inputN.setText("1 to 10");
                inputN.selectAll();
                return;
            }
            inputN.setText("");
            moves = 0;
            peg1.setSize(0);
            for (int i = n; i > 0; i--) {
                peg1.push(i);
            }
            peg2.setSize(0);
            peg3.setSize(0);
            drawTowers(g);
            moveDisks(n, peg1, peg2, peg3);
            String out = "___________________________" + n + " disks took " + moves + " move" + (moves > 1 ? "s" : "") + "___________________________";
            int x = (width - 6 * out.length()) / 2;
            g.drawString(out, x >= 0 ? x : 0, thePanel.getHeight() + (yTop - thePanel.getHeight()) / 2 + 10);
        } // end actionPerformed
    } // end inputNAction
} // end TowersOfHanoi


