Knight’s Tour problem is a classic puzzle in which the goal is to move a knight on a chessboard such that the knight visits every square exactly once. The knight moves in an L-shape: two squares in one direction and then one square perpendicular to that or vice versa. In this article, we will learn how to solve this problem in C language.
 Valid Moves of Knight Example:
Consider a 8×8 chessboard, and the knight starts at position (0, 0). The goal is to find a sequence of moves that allows the knight to visit each square exactly once.
Input: 8
Output: 0 59 38 33 30 17 8 63 37 34 31 60 9 62 29 16 58 1 36 39 32 27 18 7 35 48 41 26 61 10 15 28 42 57 2 49 40 23 6 19 47 50 45 54 25 20 11 14 56 43 52 3 22 13 24 5 51 46 55 44 53 4 21 12
To solve the Knight’s Tour problem there are two primary methods: Backtracking and Warnsdorff’s Rule. Here, we will discuss both methods using the C programming language.
As we know a knight can move in the cells which are shown in the above image in his single move. Suppose the current position of the knight is (i,j) then his possible moves are :
(i+2 , j+2), (i+2, j+2), (i-1,j+2), (i-2, j+1), (i-2, j-1), (i-1 , j-2), (i+1 , j-2), (i+2, j-1) So, to solve this kind of problem where we will need to try each of given options backtracking is the best strategy, where we try all possible moves for the knight and backtrack if we reach an invalid state. This method ensures that we explore all potential solutions.
Approach
- Create an empty solution matrix to track the knight’s path.
- Place the knight at the starting position.
- Try all possible moves from the current position.
- If a move is valid, mark the move in the solution matrix.
- Recursively attempt to solve the tour from the new position.
- If the tour is complete, return the solution.
- If no valid moves are available, backtrack and try the next move.
C Program to Solve Knight’s Tour using BacktrackingThe below program demonstrates how we can solve the Knight’s tour problem using backtracking in C language.
C
// C Program to Solve Knight’s Tour using Backtracking
#include <stdio.h>
#define N 8
// Function to check if (x, y) is a valid move for the
// knight
int isSafe(int x, int y, int sol[N][N])
{
return (x >= 0 && x < N && y >= 0 && y < N
&& sol[x][y] == -1);
}
// Function to print the solution matrix
void printSolution(int sol[N][N])
{
for (int x = 0; x < N; x++) {
for (int y = 0; y < N; y++)
printf(" %2d ", sol[x][y]);
printf("\n");
}
}
// Utility function to solve the Knight's Tour problem
int solveKTUtil(int x, int y, int movei, int sol[N][N],
int xMove[N], int yMove[N])
{
int k, next_x, next_y;
if (movei == N * N)
return 1;
// Try all next moves from the current coordinate x, y
for (k = 0; k < 8; k++) {
next_x = x + xMove[k];
next_y = y + yMove[k];
if (isSafe(next_x, next_y, sol)) {
sol[next_x][next_y] = movei;
if (solveKTUtil(next_x, next_y, movei + 1, sol,
xMove, yMove)
== 1)
return 1;
else
// Backtracking
sol[next_x][next_y] = -1;
}
}
return 0;
}
// This function solves the Knight's Tour problem using
// Backtracking
int solveKT()
{
int sol[N][N];
// Initialization of solution matrix
for (int x = 0; x < N; x++)
for (int y = 0; y < N; y++)
sol[x][y] = -1;
// xMove[] and yMove[] define the next move of the
// knight xMove[] is for the next value of x coordinate
// yMove[] is for the next value of y coordinate
int xMove[8] = { 2, 1, -1, -2, -2, -1, 1, 2 };
int yMove[8] = { 1, 2, 2, 1, -1, -2, -2, -1 };
// Starting position of knight
sol[0][0] = 0;
// Start from (0, 0) and explore all tours using
// solveKTUtil()
if (solveKTUtil(0, 0, 1, sol, xMove, yMove) == 0) {
printf("Solution does not exist");
return 0;
}
else
printSolution(sol);
return 1;
}
int main()
{
solveKT();
return 0;
}
Output
0 59 38 33 30 17 8 63 37 34 31 60 9 62 29 16 58 1 36 39 32 27 18 7 35 48 41 26 61 10 15 28 42 57 2 49 40 23 6 19 47 50 45 54 25 20 11 14 56 43 52 3 22 13 24 5 51 46 55 44 53 4 21 12 Time Complexity: O(8N^2), as there are N^2 Cells and for each, we have a maximum of 8 possible moves to choose from, so the worst running time is . Auxiliary Space: O(N^2)
Warnsdorff’s rule is a heuristic method to solve the Knight’s Tour problem. The rule says that the knight should always move to the square from which the knight will have the fewest onward moves. We cannot count steps that return to a square that has already been visited when calculating the number of onward moves for each candidate square.
Approach
- Set P to be a random initial position on the board
- Mark the board at P with the move number “1”
- Do following for each move number from 2 to the number of squares on the board:
- let S be the set of positions accessible from P.
- Set P to be the position in S with minimum accessibility
- Mark the board at P with the current move number
- Return the marked board — each square will be marked with the move number on which it is visited.
C Program to Solve Knight’s Tour using Warnsdorff’s RuleThe below program demonstrates how we can solve the Knight’s tour problem using Warnsdorff’s algorithm in C language.
C
// C Program to Solve Knight’s Tour using Warnsdorff’s Rule
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 8
// Move pattern on basis of the change of
// x coordinates and y coordinates respectively
static int cx[N] = { 1, 1, 2, 2, -1, -1, -2, -2 };
static int cy[N] = { 2, -2, 1, -1, 2, -2, 1, -1 };
// function restricts the knight to remain within
// the 8x8 chessboard
bool limits(int x, int y)
{
return ((x >= 0 && y >= 0) && (x < N && y < N));
}
/* Checks whether a square is valid and empty or not */
bool isempty(int a[], int x, int y)
{
return (limits(x, y)) && (a[y * N + x] < 0);
}
/* Returns the number of empty squares adjacent to (x, y) */
int getDegree(int a[], int x, int y)
{
int count = 0;
for (int i = 0; i < N; ++i)
if (isempty(a, (x + cx[i]), (y + cy[i])))
count++;
return count;
}
// Picks next point using Warnsdorff's heuristic.
// Returns false if it is not possible to pick next point.
bool nextMove(int a[], int* x, int* y)
{
int min_deg_idx = -1, c, min_deg = (N + 1), nx, ny;
// Try all N adjacent of (*x, *y) starting from a random
// adjacent. Find the adjacent with minimum degree.
int start = rand() % N;
for (int count = 0; count < N; ++count) {
int i = (start + count) % N;
nx = *x + cx[i];
ny = *y + cy[i];
if ((isempty(a, nx, ny))
&& (c = getDegree(a, nx, ny)) < min_deg) {
min_deg_idx = i;
min_deg = c;
}
}
// If we could not find a next cell
if (min_deg_idx == -1)
return false;
// Store coordinates of next point
nx = *x + cx[min_deg_idx];
ny = *y + cy[min_deg_idx];
// Mark next move
a[ny * N + nx] = a[(*y) * N + (*x)] + 1;
// Update next point
*x = nx;
*y = ny;
return true;
}
/* displays the chessboard with all the legal knight's moves
*/
void print(int a[])
{
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j)
printf("%2d\t", a[j * N + i]);
printf("\n");
}
}
/* checks its neighbouring squares */
/* If the knight ends on a square that is one knight's move
* from the beginning square, then tour is closed */
bool neighbour(int x, int y, int xx, int yy)
{
for (int i = 0; i < N; ++i)
if (((x + cx[i]) == xx) && ((y + cy[i]) == yy))
return true;
return false;
}
/* Generates the legal moves using Warnsdorff's heuristics.
* Returns false if not possible */
bool findClosedTour()
{
// Filling up the chessboard matrix with -1's
int a[N * N];
for (int i = 0; i < N * N; ++i)
a[i] = -1;
// Random initial position
int sx = rand() % N;
int sy = rand() % N;
// Current points are same as initial points
int x = sx, y = sy;
a[y * N + x] = 1; // Mark first move.
// Keep picking next points using Warnsdorff's heuristic
for (int i = 0; i < N * N - 1; ++i)
if (nextMove(a, &x, &y) == 0)
return false;
// Check if tour is closed (Can end at starting point)
if (!neighbour(x, y, sx, sy))
return false;
print(a);
return true;
}
int main()
{
// To make sure that different random initial positions
// are picked.
srand(time(NULL));
// While we don't get a solution
while (!findClosedTour()) {
;
}
return 0;
}
Output
45 8 27 24 41 10 29 14 26 23 44 9 28 13 42 11 7 46 25 40 43 52 15 30 22 39 56 51 48 31 12 53 57 6 47 32 61 54 49 16 38 21 60 55 50 33 62 1 5 58 19 36 3 64 17 34 20 37 4 59 18 35 2 63 Time complexity: O(N^3) Auxiliary Space: O(N^2)
|