import java.applet.*; import java.awt.*; import java.awt.event.*; import java.net.*; /** An applet that finds a Hamiltonian cycle for the knight on a chess board. Uses a simple and intuitive graphical user interface, letting the user resize the board, choose the start square for searching, optionally view the process as an animation, and pause at will.

This class provides a functioning environment for the KnightThread and GraphicalBoard objects that do the actual work. Note that using a GUI is not mandatory: the program could be implemented as a text-mode application as well. @author Markku Vähäaho @version 1.0 @see KnightThread @see GraphicalBoard */ public class KnightsTour extends Applet implements BoardListener, ActionListener, ItemListener { private GraphicalBoard board; private Image image; private KnightThread thread; private final Label label = new Label("Starting Knight's Tour...", Label.CENTER); private final Panel panel = new Panel(); private final Button clearButton = new Button("Clear"); private final Button pauseButton = new Button(" Pause "); private final Checkbox animCheckbox = new Checkbox("Animation", true); private int width = 8, height = 8; private boolean running = false, anim = true; /** Initializes the applet. Loads the knight image and creates a set of buttons, a GraphicalBoard and a KnightThread. The image name is specified in the applet parameters with the tag 'image'. */ public void init() { setVisible(false); panel.add(clearButton); panel.add(pauseButton); panel.add(animCheckbox); clearButton.addActionListener(this); pauseButton.addActionListener(this); animCheckbox.addItemListener(this); image = this.getImage(this.getDocumentBase(), this.getParameter("image")); board = new GraphicalBoard(width, height, image); board.setBoardListener(this); board.setClickable(true); board.setResizable(true); setLayout(new BorderLayout()); add("North", label); add("Center", board); add("South", panel); thread = new KnightThread(board, label); thread.setAnimation(anim); setVisible(true); } /** Frees applet resources. Stops the thread, if running, and flushes the knight image from memory. */ public void destroy() { thread.stop(); image.flush(); } /** Starts the KnightThread thread. */ public void start() { if (thread.isAlive() && running) { thread.update(); thread.resume(); } } /** Suspends the KnightThread thread. */ public void stop() { if (thread.isAlive() && running) thread.suspend(); } /** Returns textual information of the applet. @return a short two-lined copyright notice. */ public String getAppletInfo() { return "Knight's Tour V1.0 (C) 1999 Markku Vähäaho\n" + "University of Helsinki, Department of Computer Science"; } /** Returns information of acceptable applet parameters that can be specified in the HTML file. @return an array describing the parameters this applet looks for. */ public String[][] getParameterInfo() { String[][] paraminfo = { { "image", "gif/jpeg file", "Knight image" } }; return paraminfo; } /** Creates a new board of the specified size and initializes a new thread for it. As a part of the BoardListener interface, the method is invoked by GraphicalBoard when the board is resized by the user. @param new_width new width of the board in squares. @param new_height new height of the board in squares. */ public void boardResized(int new_width, int new_height) { board.removeBoardListener(); thread.stop(); setVisible(false); remove(board); board = new GraphicalBoard(width = new_width, height = new_height, image); board.setBoardListener(this); board.setClickable(true); board.setResizable(true); add("Center", board); pauseButton.setLabel(" Pause "); validate(); setVisible(true); thread = new KnightThread(board, label); thread.setAnimation(anim); running = false; } /** Sets the start square that the user chose and starts the KnightThread threaed. As a part of the BoardListener interface, the method is invoked by GraphicalBoard when a square is clicked on by the user. Clicks are disabled from here on. @param x x-index of the clicked square. @param y y-index of the clicked square. @see BoardListener */ public void boardClicked(int x, int y) { board.setClickable(false); board.setResizable(false); thread.setStartSquare(x, y); thread.start(); running = true; } /** Takes appropriate action when the user selects a button. The effect of selecting the 'Clear' button is the same as if the board had just been resized. Also suspends or resumes the KnightThread thread when the user selects the 'pause' button. @param e button event received from AWT. @see java.awt.ActionListener */ public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == clearButton) boardResized(width, height); else if (source == pauseButton && thread.isAlive()) { if (running) { thread.suspend(); thread.update(); board.setResizable(true); label.setText("Paused."); label.repaint(); pauseButton.setLabel("Resume"); panel.validate(); panel.repaint(); running = false; } else { pauseButton.setLabel(" Pause "); panel.validate(); panel.repaint(); board.setResizable(false); thread.update(); thread.resume(); running = true; } } } /** Toggles animation on or off when the 'Animation' checkbox state changes. @param e checkbox event received from AWT. */ public void itemStateChanged(ItemEvent e) { if (e.getSource() == animCheckbox) { anim = animCheckbox.getState(); if (thread != null) { thread.setAnimation(anim); if (running) thread.update(); } } } }