Encyclopedia > How to solve the knight's tour

  Article Content

How to solve the knight's tour

Table of contents

Introduction Historically, various methods have been used to solve the Knight's Tour problem. One frequently used method is to break up the 8x8 chessboard into smaller rectangles and solve the problem for the smaller rectangles in such a way that it is possible to combine the smaller paths into one grand path.

In the following we will see a method that is easy to learn and can be used to easily construct a knight's tour in less than 5 minutes. The tours so constructed will have the additional property that it is possible for the knight to step from the final square to the initial square, thus forming a closed path or a cycle.

Broadly, our strategy is to stay near the edges of the board as much as possible, so that towards the end, the squares that are remaining form a well-connected subgraph at the center of the board, enabling us to complete the last few moves by trial and error.

Step 1

  • Start from one of the edge squares (but not one of the corner squares).
  • Keep close to the edges of the board, and avoid the 16 central squares unless there is no alternative (e.g. move 13 of figure 1).
  • If you are one move away from a corner square, you must necessarily move to the corner square (See figure 1).
  • Follow these rules until all edge squares and all squares bordering an edge square have been visited. You should be in a position similar to figure 2.


Figure 1. If you can move to a corner square, you must do so.


Figure 2. Step 1 completed.

Step 2

  • 2a) Try to complete the tour by inspection. This is often not possible. If that is the case, read on.
  • 2b) Arbitrarily extend the path to get a cycle (i.e. without visiting all the remaining squares). In figure 3, the path has been extended to a cycle of length 54.
  • 2c) Find pairs of squares along the tour such that
    • they are one move away from each other.
    • each is one move away from some unvisited square.
  • 2d) Use such pairs to complete the tour by inserting new squares between the pair of squares. In figure 3, this has been done using the pairs (5,6) and (8,9).
  • 2e) Renumber the squares from 1 to 64 (see figure 4).
It might happen that there is no way to complete the tour in steps 2c and 2d. If that is the case, repeat step 2b until it is possible to get a complete tour.


Figure 3. The sequence 5->6 has been extended to 5->5a->5b->5c->5d->6 and 8->9 has been extended to 8->8a->8b->8c->8d->8e->8f->9 to complete the tour.


Figure 4. Completed and properly numbered tour.

A heuristic

One popular heuristic for solving the knight's tour problem is the Warnsdorff rule. According to this rule, at each step the knight must move to that square which has the lowest degree (the degree of a square is the number of squares to which the knight can move from that square). The rationale for this is that towards the end, we will be left with squares having a high degree, and so there is a smaller chance of arriving at a square from which there is no move. The Warnsdorff rule is particularly suitable for writing computer programs to solve the knight's tour. Below is an example C program which uses this heuristic.

Example C program for solving the knight's tour using the Warnsdorff rule

 #include <stdio.h>
 #include <stdlib.h>
 
 /* The dimensions of the chess board */
 #define BWID 8
 #define BHEIT 8
 /* The moves of the knight */
 #define JWID 1
 #define JHEIT 2
 
 /* Macros for convenience */
 #define isinboard(board,x,y) ((x)>=0 && (y)>=0 && (x)<BWID && (y)<BHEIT)
 #define isfree(board,x,y) (isinboard(board,x,y) && board[y * BWID + x] < 0)
 
 /* These arrays define the set of neighbors of a square */
 static int incx[8] = {JWID, JWID, JHEIT, JHEIT, -JWID, -JWID, -JHEIT, -JHEIT};
 static int incy[8] = {JHEIT, -JHEIT, JWID, -JWID, JHEIT, -JHEIT, JWID, -JWID};
 
 /* The number of neighbors of a square to which we can move */
 int get_nbr_cnt(int *board, int x, int y)
 {
     int i, cnt = 0;
     for (i=0; i<8; i++)
         if (isfree(board, x+incx[i], y+incy[i]))
             cnt++;
     return cnt;
 }
 
 /* Make a move according to the smallest degree heuristic */
 int make_move(int *board, int *x, int *y)
 {
     int start, cnt, i, best = -1, nbrs, min_nbrs = 9, newx, newy;
     start = random() % 8;
     for (cnt=0; cnt<8; cnt++)
     {
         i = (start+cnt) % 8;
         newx = *x + incx[i];
         newy = *y + incy[i];
         if (isfree(board, newx, newy) && 
                 (nbrs = get_nbr_cnt(board, newx, newy)) < min_nbrs)
         {
             best = i;
             min_nbrs = nbrs;
         }
     }
     if (min_nbrs == 9)
         return 0;
     newx = *x + incx[best];
     newy = *y + incy[best];
     board[newy * BWID + newx] = board[*y * BWID + *x] + 1;
     *x = newx;
     *y = newy;
     return 1;
 }
 
 /* Print the solved position */
 void print_board(int *board)
 {
     int i, j;
     for(i=0; i<BWID; i++)
     {
         for(j=0; j<BHEIT; j++)
             printf ("%d\t", board[j * BWID + i]);
         printf ("\n");
     }
 }
 
 /* Check if 2 squares are neighbors of each other */
 int is_nbr (int x1, int y1, int x2, int y2)
 {
     int i;
     for (i=0; i<8; i++)
         if (x1 + incx[i] == x2 && y1 + incy[i] == y2)
             return 1;
     return 0;
 }

     
 /* Generate a path with a random starting square and each square 
  * chosen according to the smallest degree rule. If a hamiltonian
  * cycle results, print the solution and return 1. Else return 0.
  */
 int gen_sol()
 {
     /* board[y * BWID + x] represents the move number in which
        the square (x, y) was visited. It is -1 if the square has
        not been visited so far */
     int board[BWID*BHEIT];
     /* x and y represent the coordinates of the square being
        currently visited */
     int i, x, y, startx, starty;
     for(i=0; i<BWID*BHEIT; i++)
         board[i] = -1;
     startx = x = random() % BWID;
     starty = y = random() % BHEIT;
     board[y * BWID + x] = 1;
     for(i=0; i<BWID*BHEIT-1; i++)
         if (make_move(board, &x, &y) == 0)
             return 0;
     if (!is_nbr (x, y, startx, starty))
         return 0;
     print_board(board);
     return 1;
 }
 
 /* Loop endlessly until a solution is found */
 int main(void)
 {
     while (!gen_sol())
         ;
     return 0;
 }

Note that the above program is not restricted to 8x8 chessboards; the parameters BWID and BHEIT control the width and the height respectively.

One solution obtained using the above program is shown below.


Figure 5. Computer solution using the Warnsdorff heuristic.

External links



All Wikipedia text is available under the terms of the GNU Free Documentation License

 
  Search Encyclopedia

Search over one million articles, find something about almost anything!
 
 
  
  Featured Article
Ludvika

... of 1500.7 km². Of the total population of 26450, 13112 are male, and 13338 are female. The population density of the community is 18 inhabitants per km². ...

 
 
 
This page was created in 39.6 ms