
/**
 * This class implements the model for the Knight's Tour problem.
 */
public class KnightsTourBoard
{
    protected int m_width;
    protected int m_height;
    protected int[][] m_board;

    /**
     * Construct a Knight's Tour Board object
     * @param width the width of the board
     * @param height the height of the board
     */
    KnightsTourBoard(int width, int height)
    {
        m_width = width;
        m_height = height;
        m_board = new int[width][height];
    }

    /**
     * @return the width of the board
     */
    public int getWidth() { return m_width; }

    /**
     * @return the height of the board
     */
    public int getHeight() { return m_height; }

    /**
     * @param x the x coordinate of the position in question
     * @param y the y coordinate of the position in question
     * @return the step number at the given position in the board
     */
    public int getStepAt(int x, int y) { return m_board[x][y]; }

    /**
     * Attempt to run a Knight's Tour from the starting position
     * @param startx the x coordinate of the starting position
     * @param starty the y coordinate of the starting position
     * @return true if it was possible to perform the tour, otherwise false
     */
    public boolean tour(int startx, int starty)
    {
        for (int x = 0; x < m_width; x++)
            for (int y = 0; y < m_height; y++)
                m_board[x][y] = 0;
        m_board[startx][starty] = 1;
        return tourFrom(2, startx, starty);
    }

    /* recursive helper function to tour()
     * which stores the current step number */
    private boolean tourFrom(int nextStep, int startx, int starty)
    {
//        System.out.println("tourFrom(" + nextStep + ", " +
//                startx + ", " + starty + ")");
        final int[] xoffsets = {-2, -1, 1, 2, -2, -1, 1, 2};
        final int[] yoffsets = {-1, -2, -2, -1, 1, 2, 2, 1};

        for (int moveIndex = 0; moveIndex < 8; moveIndex++)
        {
            int x = startx + xoffsets[moveIndex];
            int y = starty + yoffsets[moveIndex];

            if (x >= 0 && x < m_width && y >= 0 && y < m_height)
            {
                if (m_board[x][y] == 0) /* if space has not been visited yet */
                {
                    m_board[x][y] = nextStep; /* we just took step number
                                               * nextStop, stop if that is all
                                               * we needed to do */
                    if (nextStep == m_width * m_height)
                        return true;
                    if (tourFrom(nextStep + 1, x, y)) /* else walk from there */
                        return true;
                    m_board[x][y] = 0; /* this step did not lead to a solution */
                }
            }
        }

        return false;
    }
}
