Open In App

Knight’s Tour Problem in C++

Last Updated : 05 Aug, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

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 using the C++ language.

Example:

Consider an 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.

Knight’s Tour using Backtracking in C++

A knight can move in an "L" shape, i.e., two squares in one direction and then one square perpendicular to that direction. Suppose the current position of the knight is (i,j). The possible moves are:

(i+2, j+1), (i+2, j-1), (i-2, j+1), (i-2, j-1),
(i+1, j+2), (i+1, j-2), (i-1, j+2), (i-1, j-2)

To solve this problem using backtracking, 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 Backtracking

The following C++ program demonstrates how we can solve the Knight’s tour problem using backtracking.

C++
// C++ program to solve  Knight’s tour problem using backtracking

#include <iomanip>
#include <iostream>
#include <vector>

#define N 8

using namespace std;

// Function to check if (x, y) is a valid move for the knight
bool isSafe(int x, int y, vector<vector<int>> &sol)
{
    return (x >= 0 && x < N && y >= 0 && y < N && sol[x][y] == -1);
}

// Function to print the solution matrix
void printSolution(vector<vector<int>> &sol)
{
    for (int x = 0; x < N; x++)
    {
        for (int y = 0; y < N; y++)
            cout << " " << setw(2) << sol[x][y] << " ";
        cout << endl;
    }
}

// Utility function to solve the Knight's Tour problem
bool solveKTUtil(int x, int y, int movei, vector<vector<int>> &sol, const vector<int> &xMove,
                 const vector<int> &yMove)
{
    int k, next_x, next_y;
    if (movei == N * N)
        return true;

    // 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))
                return true;
            else
                sol[next_x][next_y] = -1; // Backtracking
        }
    }
    return false;
}

// This function solves the Knight's Tour problem using Backtracking
bool solveKT()
{
    vector<vector<int>> sol(N, vector<int>(N, -1));

    // xMove[] and yMove[] define the next move of the knight.
    vector<int> xMove = {2, 1, -1, -2, -2, -1, 1, 2};
    vector<int> yMove = {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))
    {
        cout << "Solution does not exist" << endl;
        return false;
    }
    else
        printSolution(sol);

    return true;
}

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(8^(N^2)), where N is the size of the chessboard. This complexity arises because for each cell, we try up to 8 possible moves.
Auxiliary Space: O(N^2), as we use a 2D array to store the knight's path.

Knight’s Tour using Warnsdorff’s Algorithm in C++

Warnsdorff’s rule is a heuristic method to solve the Knight’s Tour problem. The rule states that the knight should always move to the square from which the knight will have the fewest onward moves. This minimizes the branching factor and reduces the likelihood of running into a dead end.

Approach:

  • Set the initial position of the knight randomly on the board.
  • Mark the board at the starting position with the move number “1”.
  • For each subsequent move number from 2 to the total number of squares on the board:
    • Determine all possible positions the knight can move to from the current position.
    • Choose the position with the minimum number of onward moves.
    • Mark the board at this new position with the current move number.
  • Return the marked board, where each square is marked with the move number on which it was visited.

C++ Program to Solve Knight’s Tour using Warnsdorff’s Rule

The following C++ program demonstrates how we can solve the Knight’s tour problem using Warnsdorff’s algorithm.

C++
// C++ program to solve the Knight’s tour problem using Warnsdorff’s algorithm.

#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <vector>

#define N 8

using namespace std;

// Move pattern on basis of the change of x 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 to restrict 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
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
    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)
            cout << setw(2) << a[j * N + i] << "\t";
        cout << endl;
    }
}

// Checks its neighboring squares. If the knight ends on a square that is one knight's move from the beginning
// square, then the 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 the 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))
            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

17      38      13      50      33      36      11      48
14 51 16 37 12 49 32 35
39 18 59 56 53 34 47 10
58 15 52 41 60 63 54 31
19 40 57 64 55 46 9 62
4 1 22 45 42 61 30 27
23 20 3 6 25 28 43 8
2 5 24 21 44 7 26 29

Time Complexity: O(N^3), where N is the size of the chessboard. The complexity is reduced significantly due to the heuristic used.
Auxiliary Space: O(N^2), as we use a 2D array to store the knight's path.


Next Article
Article Tags :
Practice Tags :

Similar Reads