import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.border.*; public class KnightsTour extends JFrame { private KnightsTourBoard m_ktBoard = new KnightsTourBoard(5, 5); private Thread m_tourThread; /* GUI elements */ private ActionEventHandler m_handler = new ActionEventHandler(this); private JTextField m_widthField; private JTextField m_heightField; private JTextField m_startXField; private JTextField m_startYField; private JButton m_startButton; private JButton m_cancelButton; private JPanel m_mainPanel; private JPanel m_boardPanel; private JLabel m_statusLabel; public KnightsTour() { super("Josh's Knights Tour project for CS621"); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(500, 600); /* set up the main window contents */ getContentPane().add(m_mainPanel = new JPanel(new BorderLayout()) {{ setBorder(BorderFactory.createEmptyBorder(9, 9, 9, 9)); add(new JPanel() {{ setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 7)); add(new JPanel() {{ /* board size panel */ setBorder(BorderFactory.createTitledBorder("Board Size")); add(new JPanel() {{ setBorder(BorderFactory.createEmptyBorder()); setLayout(new GridLayout(2, 2, 5, 5)); add(new JLabel("Width:", SwingConstants.RIGHT)); add(m_widthField = new JTextField("5")); add(new JLabel("Height:", SwingConstants.RIGHT)); add(m_heightField = new JTextField("5")); }}); }}); add(new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 0))); add(new JPanel() {{ /* starting position panel */ setBorder(BorderFactory.createTitledBorder("Starting Position")); add(new JPanel() {{ setBorder(BorderFactory.createEmptyBorder()); setLayout(new GridLayout(2, 2, 5, 5)); add(new JLabel("Column (X):", SwingConstants.RIGHT)); add(m_startXField = new JTextField("2")); add(new JLabel("Row (Y):", SwingConstants.RIGHT)); add(m_startYField = new JTextField("2")); }}); }}); add(new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 0))); add(new JPanel() {{ /* start button panel */ setBorder(BorderFactory.createTitledBorder("Start")); add(new JPanel() {{ setBorder(BorderFactory.createEmptyBorder()); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); add(m_startButton = new JButton("Start Knight's Tour")); m_startButton.addActionListener(m_handler); add(m_cancelButton = new JButton("Cancel Knight's Tour")); m_cancelButton.addActionListener(m_handler); m_cancelButton.setVisible(false); add(new Box.Filler(new Dimension(0, 4), new Dimension(0, 4), new Dimension(0, 4))); add(m_statusLabel = new JLabel()); }}); }}); add(new Box.Filler(new Dimension(0, 0), new Dimension(Short.MAX_VALUE, 0), new Dimension(10000, 10000))); }}, BorderLayout.NORTH); }}); createBoardPanel(); setVisible(true); } private void createBoardPanel() { int width = m_ktBoard.getWidth(); int height = m_ktBoard.getHeight(); JPanel oldBoardPanel = m_boardPanel; m_boardPanel = new JPanel(new GridLayout(height, width, 1, 1)); m_boardPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { JLabel l = new JLabel(m_ktBoard.getStepAt(x, y) == 0 ? "" : new Integer(m_ktBoard.getStepAt(x, y)).toString(), SwingConstants.CENTER); l.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); m_boardPanel.add(l); } } if (oldBoardPanel != null) m_mainPanel.remove(oldBoardPanel); m_mainPanel.add(m_boardPanel); m_mainPanel.validate(); } private class ActionEventHandler implements ActionListener { private KnightsTour m_kt; public ActionEventHandler(KnightsTour kt) { m_kt = kt; } public void actionPerformed(ActionEvent e) { if (e.getSource() == m_startButton) { m_statusLabel.setText("Running..."); /* first validate input text fields */ int width, height, startx, starty; try { width = Integer.parseInt(m_widthField.getText()); height = Integer.parseInt(m_heightField.getText()); startx = Integer.parseInt(m_startXField.getText()); starty = Integer.parseInt(m_startYField.getText()); } catch (NumberFormatException nfe) { m_statusLabel.setText("Non-numerical input!"); return; } if (width < 1 || height < 1 || startx < 0 || starty < 0 || startx >= width || starty >= height) { m_statusLabel.setText("Invalid input!"); return; } /* create a new KnightsTourBoard object */ m_ktBoard = new KnightsTourBoard(width, height); createBoardPanel(); /* run the tour in a separate thread */ m_startButton.setVisible(false); m_cancelButton.setVisible(true); m_tourThread = new Thread(new TourThread(startx, starty)); m_tourThread.start(); } else if (e.getSource() == m_cancelButton) { if (m_tourThread != null) { m_tourThread.stop(); m_tourThread = null; m_startButton.setVisible(true); m_cancelButton.setVisible(false); m_statusLabel.setText("Cancelled."); } } } } private class TourThread implements Runnable { int m_startx, m_starty; public TourThread(int startx, int starty) { m_startx = startx; m_starty = starty; } public void run() { if (m_ktBoard.tour(m_startx, m_starty)) { SwingUtilities.invokeLater(new Runnable() { public void run() { createBoardPanel(); m_statusLabel.setText("Finished."); m_startButton.setVisible(true); m_cancelButton.setVisible(false); } }); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { createBoardPanel(); m_statusLabel.setText("Solution not found!"); m_startButton.setVisible(true); m_cancelButton.setVisible(false); } }); } m_tourThread = null; } } public static void main(String[] args) { KnightsTour kt = new KnightsTour(); } }