-1

My chess knight tour code using recursive-backtracking is not working.

#include <iostream>

using namespace std;
// goal: knight tour
#define N 8
void printArray(int board[N][N])
{
    for(int i = 0; i < N; i ++)
    {
        for(int j = 0; j < N; j ++)
        {
            cout << board[i][j] << " ";
        }
        cout << endl;
    }
}
void instArray(int board[N][N])
{
    for(int i = 0; i < N; i ++)
        for(int j = 0; j < N; j ++)
            board[i][j] = 0;
    board[0][0] = 1;
}
bool isValidMove(int posX, int posY, int moveX, int moveY, int board[N][N])
{
    int finalX = posX + moveX;
    int finalY = posY + moveY;
    if(finalX < 0 ||
       finalX > 7 ||
       finalY < 0 ||
       finalY > 7 ||
       board[finalY][finalX] != 0)
       return false;
    return true;
}
bool solveKnightTour(int board[N][N], int n, int posX, int posY, int 
moveX[N], int moveY[N])
{
    int next_x, next_y;
    if(n == 65) return true;//when n is equal to 62 the code compiles
    for(int i = 0; i < 8; i ++)
    {
        if(isValidMove(posX, posY, moveX[i], moveY[i], board))
        {
            next_x = posX + moveX[i];
            next_y = posY + moveY[i];
            board[next_y][next_x] = n;
            if(solveKnightTour(board, n + 1, next_x, next_y, moveX, moveY)) 
                 return true;
            else board[next_y][next_x] = 0;
        }
    }
    return false;
}
int main()
{
    int board[N][N];
    int moveX[8] = {1, 1, 2, 2, -1, -1, -2, -2};
    int moveY[8] = {2, -2, 1, -1, 2, -2, 1, -1};
    instArray(board);
    solveKnightTour(board, 2, 0, 0, moveX, moveY);
    printArray(board);
}

There is no error, but the code seems to endlessly loop. In solveKnightTour function, when n is equal to 62, the code compiles with printed board, but the result is not a completely solved knight tour.

false
  • 10,264
  • 13
  • 101
  • 209
Berry
  • 11
  • 1
  • 2
  • *There is no error,* -- Why say this when there *is* an error (somewhere)? – PaulMcKenzie Aug 03 '18 at 17:33
  • I meant that there is no compiler error. – Berry Aug 03 '18 at 17:34
  • 2
    This is a good time [to learn how to debug your programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). – Some programmer dude Aug 03 '18 at 17:35
  • *I meant that there is no compiler error.* -- So then you see that having no compiler errors means that your code has no syntax errors. Having no syntax errors has no bearing on whether the program will run correctly and have no logical errors. That is when you need to use the debugger to debug your code, and not see it as something "faulty" just because you have no compiler errors. – PaulMcKenzie Aug 03 '18 at 17:36
  • @Berry That's where your debugger comes into play. You inspect your running code line by line, and watch how variables change and if the values are what you expect. – πάντα ῥεῖ Aug 03 '18 at 17:36
  • 1
    _when n is equal to 62 the code compiles_ -- I am pretty sure it will compile for just about any number (within the `INT_MIN - INT_MAX` range). What you mean is that _the program works_ when n is equal to 62. Those two are _very_ different things... – DevSolar Aug 03 '18 at 17:41
  • `isValidMove` is wrong. A valid move would be (a) the calculated X and Y are in range of `[0..N)` (not `[0,,8)`), and the board slot is free. Changing `N` to anything besides `8` makes that check function improper. Assuming you're using a square board and `N` is the dimension of said same. – WhozCraig Aug 03 '18 at 17:43
  • when n is equal to 62 the code compiles -- I am pretty sure it will compile for just about any number (within the INT_MIN - INT_MAX range). What you mean is that the program works when n is equal to 62. Those two are very different things... – Berry Nov 16 '22 at 00:13

1 Answers1

1

Your program is taking a very long time to find a solution because of the very symmetrical ordering of your moveX and moveY arrays. If you put the combinations in this order instead, which traverses the directions in a circular manner:

int moveX[8] = {1, 2, 2, 1, -1, -2, -2, -1};
int moveY[8] = {-2, -1, 1, 2, 2, 1, -1, -2};

The program will find a solution almost instantly.

In your code, searching "up 2 right 1" first then "down 2 right 1" second the knight will zig-zag along the top of the board, from a8 to b6 to c8 to d6 etc. Certain squares along the top of the board become inaccessible and the program wastes time searching all these combinations that are guaranteed to fail.

Recursive backtracking is an inefficient algorithm to use here in the first place, as there is a massive number of combinations that could be played out. A 4x4 or 5x5 board would not run into these problems because it scales exponentially. But in this case, my provided answer only "just happens" to work. In general, brute forcing something of this scale tends to require way more computation than you have time for.

Edited to generalize/rework answer

Brendan Gregory
  • 93
  • 1
  • 1
  • 10
  • I don't think this answer generalizes. By setting a specific search order, you basically give part of the solution to the program. In the general case, it would be more useful to detect unreachable cells and backtrack, or provide guidance on why a specific move order is better – Jeffrey Aug 03 '18 at 19:17