/** Knight.java - The Knight's tour problem. The parameter to the puzzle is * the dimension of the (square) chessboard. It turns out an 8x8 solution * will take too long! Start a knight at one point (say the upper left * corner) and see how to move the knight so that it visits all n^2 squares * exactly once. The numbers inside the board indicate the sequence of * visits 1-n^2. We keep track of current as well as proposed position of * the knight while finding solutions. * How many invocations of solve are needed to solve the problem? * 41 for 5x5, 5422 for 6x6, 11272348 for 7x7, 3242065 for 8x8 * (No solution for 4x4, giving up after 2223 invocations.) */ public class Knight { public static int [][] board; public static int row, col, newRow, newCol; public static boolean done; public static int visit; // the next number to place on board public static int invocation; // how many times we entered solve() public static int size = 6; // default size of board public static void main(String [] args) { // The user might supply the size of the board at the command line. if (args.length > 0) size = Integer.parseInt(args[0]); // Create the puzzle board. Initialize parameters of the problem, // such as the starting point (0,0). // Start solve, and finally print out resulting board. board = new int[size][size]; row = 0; col = 0; board[row][col] = 1; visit = 1; invocation = 0; solve(); printBoard(); System.out.printf("%d invocations of solve\n", invocation); } public static void solve() { ++invocation; if (invocation % 1000000 == 0) System.out.printf("%d\n", invocation); // System.out.printf("solve() invocation %d starting with visit = %d\n", // invocation, visit); int direction; if (visit == size*size) done = true; else { done = false; direction = 0; // From the current board position, find the next place // where the knight can go. Note that no matter how big // the board is, there are always 8 directions to go. while (direction < 8 && ! done) { if (beenThere(direction)) ++direction; else { board[newRow][newCol] = ++visit; // printBoard(); row = newRow; col = newCol; solve(); // If we didn't find solution, backtrack: take off the // most recent knight placement and try it again. // Also need to remember where we were! if (! done) { clearVisit(visit); --visit; setPosition(visit); //board[newRow][newCol] = 0; //System.out.printf("clearing [%d][%d]\n", newRow, newCol); ++direction; } } } } } /* return true if that new position is off the board, or * its board value is NOT zero. */ public static boolean beenThere(int direction) { findNewPosition(direction); boolean returnVal = newRow < 0 || newRow > (size - 1) || newCol < 0 || newCol > (size - 1) || board[newRow][newCol] != 0; // System.out.println("visit = " + visit + " @ [" + row + "][" + col + // "], dir = " + direction + // ", been there returns " + returnVal); return returnVal; } /** The 8 possible new positions for the knight are like going * around the clock. */ public static void findNewPosition(int direction) { switch(direction) { case 0 : newRow = row - 2; newCol = col + 1; break; case 1 : newRow = row - 1; newCol = col + 2; break; case 2 : newRow = row + 1; newCol = col + 2; break; case 3 : newRow = row + 2; newCol = col + 1; break; case 4 : newRow = row + 2; newCol = col - 1; break; case 5 : newRow = row + 1; newCol = col - 2; break; case 6 : newRow = row - 1; newCol = col - 2; break; case 7 : newRow = row - 2; newCol = col - 1; break; } } // setPositon - Given a visit number, set row and col to that place. public static void setPosition(int v) { for (int i = 0; i < size; ++i) for (int j = 0; j < size; ++j) if (board[i][j] == v) { row = i; col = j; } } // clearVisit -- When we backtrack, we need to erase the most recently // placed knight. public static void clearVisit(int v) { for (int i = 0; i < size; ++i) for (int j = 0; j < size; ++j) if (board[i][j] == v) { // System.out.println("clearing [" + row + "][" + col + "]"); board[i][j] = 0; } } public static void printBoard() { for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) System.out.printf("%3d", board[i][j]); System.out.printf("\n"); } } }