0

I am trying to solve a similar problem to the Knight-Tour-Problem. The problem:

A knight is placed on the upper-left square of a chess board. You are given a vector of numbers(the numbers represent the squares of the chess board, as numbered from left to right, from 1 to 64). The knight has to get to those squares in the vector, one after the other, and at the end you should output the path the knight took. Note that the knight might visit a square more than once.

I tried solving this problem similar to the Knight-Tour Problem, using backtracking. However I got stuck at the "visit a square more than once". If I don´t put any condition, the knight just jumps back and forth between 2 squares and never gets anywhere. I also tried somehow restricting the knight from returning to the square it came before, but then I got a larger loop. Is there something I am missing or is backtracking in general wrong in this particular case?

Below is my code. Note that I used only the lower-right square as the target for the knight to reach it, as a simple test and even then the program failed and debugger showed me the knight was still walking in endless loops.

#include <iostream>
#include <cmath>
using namespace std;

const int n = 8;
bool found = 0;
int *path = new int[n*n];
int pathindex=0;
bool visited[n][n];

void print(int (*matrica)[n]); //function to print a matrix
void printpath(int path[n*n]){
    for(int i=0;i<pathindex;i++)
        cout<<path[i]<<" ";
        cout<<endl;
}

void knight(int (*matrica)[n], int x, int y, int path[n*n], int &pathindex){

if(found){
 return;
}
    if (x==7 && y == 7){ //if knight landed on the target, output the result
       found = 1;
       path[pathindex]=matrica[7][7];
       pathindex++;
       printpath(path);
       return;
      } 
     if(x > n-1 || y > n-1 || x < 0 || y < 0){ //if coordinates out of bounds, dismiss
        return;
    }
    path[pathindex]= matrica[x][y];
    pathindex++;
                                        //all possible knight moves     
        if(path[pathindex-1]!=matrica[x-1][y+2])   //conditions to test if the next square was the one we came from
        knight(matrica, x-1, y+2, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x-2][y+1])
        knight(matrica, x-2, y+1, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x+1][y+2])
        knight(matrica, x+1, y+2, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x+2][y+1])
        knight(matrica, x+2, y+1, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x+2][y-1])
        knight(matrica, x+2, y-1, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x+1][y-2])
        knight(matrica, x+1, y-2, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x-1][y-2])
        knight(matrica, x-1, y-2, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x-2][y-1])
        knight(matrica, x-2, y-1, path, pathindex);
    pathindex--;    
}


int main(){

int matrica[n][n];
int k = 1;
  for(int i=0;i<n;i++){  //number the chess board
    for(int j=0;j<n;j++){
        matrica[i][j] = k;
        k++;}
}
    print(matrica); 
    knight(matrica, 0, 0, path, pathindex);
    if(!found)
    cout<<"No Solution!";
    return 0;
}
void print(int (*matrica)[n]){
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(matrica[i][j]<10)
            cout<<" "<<matrica[i][j]<<" ";
            else
            cout<<matrica[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<endl<<endl;
}

How can I implement the part where the knight can use the same square more than once, yet it cannot walk on loops where it was?

Please note that this is no homework or school related project whatsoever, It´s just for my own personal fun.

underscore_d
  • 6,309
  • 3
  • 38
  • 64

1 Answers1

1

If the squares are visited in order, this is easy; work out how to get from a to b. Basic pathfinding. Then concatinate.

If the number of squares is smallish, just do the above for every permutation. Sort cost of a to b for all pairs (b to a is identical). Then solve travelling salesman to find shortest route.

Assuming the first, or if you don't care about shortest, this is "pathfind from a to b". When doing that you can assume it never loops, because then not doing the loop would also work.

The easy solution is to just paint. Have a 8x8 grid full of -1. Write 0. Then write 1 on all knight's moves from 0 that are -1. Then write 2 on all knight's moves from 1 that are -1. Repeat.

If you want to get really fancy, you can instead paint with bit operations. Have 8 8 bit values. Draw a 1 bit where the knight starts. A series of shifts and masks can translste "knight can reach" mask blindly. Store the reachable mask for each set of moves until you reach the target square.

Now backtrack - move from the target square to any legal move in the pervious snapshot. Then repeat untik you get tomthe original knight square.

newrow[i]=row[i-2]<<1 | row[i-2]>>1 | row[i+2]<<1 | row[i+2]>>1 | row[i-1]<<2 | row[i-1]>>2 | row[i+1]<<2 | row[i+1]>>2;

throw in bounds checks so row[out of bounds] is 0 and cap to 8 bits, and loop for each 8 rows, and you take a reachable knight mask forward or backwards 1 step.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Thanks for your answer! I finally realized that for the knight to go from A to B, then the knight doesn´t revisit the same square twice(if he did, then the route would be impossible), so I ended up doing simple BFS and shortest path between each two pairs. In the end, I output the concatenated path! – infinitedreamer666 May 06 '21 at 05:30