473,395 Members | 1,696 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Knight's Tour recursive problem

Hi, I'm trying to write a program to solve (or whatever) the Knight's Tour. I know this is a pretty common problem, but I haven't found a solution that I can really compare mine to and isolate what the problem(s) is/are. I have an idea as to what the problem is, but let me first post my code:

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <iomanip>
  3.  
  4. using namespace std;
  5.  
  6. void InitializeBoard(int **board, int xSize, int ySize);
  7. void DisplayBoard(int **board, int xSize, int ySize);
  8. bool KnightsTour(int **board, int xCoor, int yCoor, int xSize, int ySize, int moveNum);
  9. bool MoveIsValid(int **board, int xCoor, int yCoor, int xSize, int ySize);
  10.  
  11. int main()
  12. {
  13.     int xSize, ySize, xCoor, yCoor;
  14.     int **board;
  15.  
  16.     do
  17.     {
  18.         cout << "Enter length and height of board, seperated by a" << endl
  19.              << "space (each greater than zero): ";
  20.         cin >> xSize >> ySize;
  21.     } while ((xSize < 1) || (ySize < 1));
  22.  
  23.     do
  24.     {
  25.         cout << "Enter starting X coordinate in the range of 1-"
  26.              << xSize << ": ";
  27.         cin >> xCoor;
  28.     } while ((xCoor > xSize) || (xCoor < 1));
  29.  
  30.     do
  31.     {
  32.         cout << "Enter starting Y coordinate in the range of 1-"
  33.              << ySize << ": ";
  34.         cin >> yCoor;
  35.     } while ((yCoor > ySize) || (yCoor < 1));
  36.  
  37.     cout << "X: " << xSize << "; Y: " << ySize << endl;
  38.     cout << "X Coor: " << xCoor << "; Y Coor: " << yCoor << endl;
  39.  
  40.     // Convert to zero-based coordinates (as opposed to one-based).
  41.     xCoor--;
  42.     yCoor--;
  43.  
  44.     cout << "---------------------------------------------------" << endl << endl;
  45.  
  46.     board = new int *[xSize];
  47.     int **temp = board;
  48.  
  49.     for (int a = 0; a < xSize; a++)
  50.     {
  51.         *temp = new int[ySize];
  52.         (temp)++;
  53.     }
  54.  
  55.     InitializeBoard(board, xSize, ySize);
  56.     DisplayBoard(board, xSize, ySize);
  57.  
  58.     cout << endl << "---------------------------------------------------" << endl;
  59.     cout << "Executing Knight's Tour..." << endl;
  60.  
  61.     if (KnightsTour(board, xCoor, yCoor, xSize, ySize, 1))
  62.     {
  63.         cout << "Solution found: " << endl << endl;
  64.         DisplayBoard(board, xSize, ySize);
  65.     }
  66.     else
  67.     {
  68.         cout << "No solution found." << endl << endl;
  69.         DisplayBoard(board,xSize,ySize);
  70.     }
  71.  
  72.     for(int i = 0; i < xSize; i++)
  73.     {
  74.         delete [] (*temp);
  75.         (temp)++;
  76.     }
  77.  
  78.     delete board;
  79.  
  80.     cout << "Press any key to continue...";
  81.     cin.ignore(1000,'\n');
  82.     cin.get();
  83.  
  84.     return 0;
  85. }
  86.  
  87. void InitializeBoard(int **board, int xSize, int ySize)
  88. {
  89.     int x, y;
  90.  
  91.     for (x = 0; x < xSize; x++)
  92.     {
  93.         for (y = 0; y < ySize; y++)
  94.         {
  95.             board[x][y] = 0;
  96.         }
  97.     }
  98. }
  99.  
  100. void DisplayBoard(int **board, int xSize, int ySize)
  101. {
  102.     int x, y;
  103.  
  104.     for (x = 0; x < xSize; x++)
  105.     {
  106.         for (y = 0; y < ySize; y++)
  107.         {
  108.             cout << setw(3) << board[x][y];
  109.         }
  110.         cout << endl;
  111.     }
  112. }
  113.  
  114. bool MoveIsValid(int **board, int xCoor, int yCoor, int xSize, int ySize)
  115. {
  116.     if ((xCoor < 0) || (xCoor >= xSize))
  117.     {
  118.         return false;
  119.     }
  120.  
  121.     if ((yCoor < 0) || (yCoor >= ySize))
  122.     {
  123.         return false;
  124.     }
  125.  
  126.     if (board[xCoor][yCoor] != 0)
  127.     {
  128.         return false;
  129.     }
  130.  
  131.     return true;
  132. }
  133.  
  134. bool KnightsTour(int **board, int xCoor, int yCoor, int xSize, int ySize, int moveNum)
  135. {
  136.     if (!MoveIsValid(board, xCoor, yCoor, xSize, ySize))
  137.     {
  138.         return false;
  139.     }
  140.  
  141.     board[xCoor][yCoor] = moveNum;
  142.  
  143.     if ((xSize * ySize) == moveNum)
  144.     {
  145.         return true;
  146.     }
  147.  
  148.     cout << "KT: " << yCoor << ", " << xCoor << ", " << moveNum << endl;
  149.  
  150.     if (!KnightsTour(board, (xCoor - 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  151.         if (!KnightsTour(board, (xCoor - 2), (yCoor - 1), xSize, ySize, (moveNum + 1)))
  152.             if (!KnightsTour(board, (xCoor - 2), (yCoor + 1), xSize, ySize, (moveNum + 1)))
  153.                 if (!KnightsTour(board, (xCoor - 1), (yCoor + 2), xSize, ySize, (moveNum + 1)))
  154.                     if (!KnightsTour(board, (xCoor + 1), (yCoor + 2), xSize, ySize, (moveNum + 1)))
  155.                         if (!KnightsTour(board, (xCoor + 2), (yCoor + 1), xSize, ySize, (moveNum + 1)))
  156.                             if (!KnightsTour(board, (xCoor + 2), (yCoor - 1), xSize, ySize, (moveNum + 1)))
  157.                                 if (!KnightsTour(board, (xCoor + 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  158.                                     return false;
  159.  
  160.     moveNum = 0;
  161.     return true;
  162. }
  163.  
Here is the program's output:

Expand|Select|Wrap|Line Numbers
  1. Enter length and height of board, seperated by a
  2. space (each greater than zero): 5 5
  3. Enter starting X coordinate in the range of 1-5: 1
  4. Enter starting Y coordinate in the range of 1-5: 1
  5. X: 5; Y: 5
  6. X Coor: 1; Y Coor: 1
  7. ---------------------------------------------------
  8.  
  9.   0  0  0  0  0
  10.   0  0  0  0  0
  11.   0  0  0  0  0
  12.   0  0  0  0  0
  13.   0  0  0  0  0
  14.  
  15. ---------------------------------------------------
  16. Executing Knight's Tour...
  17. KT: 0, 0, 1
  18. KT: 2, 1, 2
  19. KT: 4, 0, 3
  20. KT: 3, 2, 4
  21. KT: 1, 1, 5
  22. KT: 3, 0, 6
  23. KT: 4, 2, 7
  24. KT: 3, 4, 8
  25. KT: 1, 3, 9
  26. KT: 0, 1, 10
  27. KT: 2, 0, 11
  28. KT: 4, 1, 12
  29. KT: 3, 3, 13
  30. KT: 1, 2, 14
  31. KT: 3, 1, 15
  32. KT: 1, 0, 16
  33. KT: 2, 2, 17
  34. KT: 4, 3, 18
  35. KT: 2, 4, 19
  36. KT: 0, 3, 20
  37. KT: 1, 4, 18
  38. KT: 0, 2, 19
  39. KT: 2, 3, 20
  40. KT: 4, 4, 21
  41. KT: 0, 4, 21
  42. No solution found.
  43.  
  44.   1 16 11  6  3
  45.  10  5  2 15 12
  46.  19 14 17  4  7
  47.  20  9 20 13 18
  48.  21 18 19  8 21
  49. Press any key to continue...
  50.  
It appears moveNum is being reset somewhere (it goes from 1 to 20, then back to 18 again, and 21 is also repeated), but I can't figure out where. Any help on this would be greatly appreciated.
Feb 14 '07 #1
17 19600
AdrianH
1,251 Expert 1GB
Hi, I'm trying to write a program to solve (or whatever) the Knight's Tour. I know this is a pretty common problem, but I haven't found a solution that I can really compare mine to and isolate what the problem(s) is/are. I have an idea as to what the problem is, but let me first post my code:

...
It appears moveNum is being reset somewhere (it goes from 1 to 20, then back to 18 again, and 21 is also repeated), but I can't figure out where. Any help on this would be greatly appreciated.
Interesting. I've not heard of this problem till you brought it up. Your code seems to be fairly good stylistically, but I would suggest comments on sections that are not straight forward such as:
Expand|Select|Wrap|Line Numbers
  1.     if (!KnightsTour(board, (xCoor - 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  2.         if (!KnightsTour(board, (xCoor - 2), (yCoor - 1), xSize, ySize, (moveNum + 1)))
  3.             if (!KnightsTour(board, (xCoor - 2), (yCoor + 1), xSize, ySize, (moveNum + 1)))
  4.                 if (!KnightsTour(board, (xCoor - 1), (yCoor + 2), xSize, ySize, (moveNum + 1)))
  5.                     if (!KnightsTour(board, (xCoor + 1), (yCoor + 2), xSize, ySize, (moveNum + 1)))
  6.                         if (!KnightsTour(board, (xCoor + 2), (yCoor + 1), xSize, ySize, (moveNum + 1)))
  7.                             if (!KnightsTour(board, (xCoor + 2), (yCoor - 1), xSize, ySize, (moveNum + 1)))
  8.                                 if (!KnightsTour(board, (xCoor + 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  9.  
Anyway, this is an AI search problem which requires backtracking as you would not be able to determine ahead of time what the result is. I don't have time right now, but I'll look at your code later. Please add comments to your code to make my (and others) reading easier.

Thanks,


Adrian
Feb 14 '07 #2
Thanks for your reply. I've added some commenting. Hopefully this helps:

Expand|Select|Wrap|Line Numbers
  1.  
  2. #include <iostream>
  3. #include <iomanip>
  4.  
  5. using namespace std;
  6.  
  7. // Function prototypes.
  8. void InitializeBoard(int **board, int xSize, int ySize);
  9. void DisplayBoard(int **board, int xSize, int ySize);
  10. bool KnightsTour(int **board, int xCoor, int yCoor, int xSize, int ySize, int moveNum);
  11. bool MoveIsValid(int **board, int xCoor, int yCoor, int xSize, int ySize);
  12.  
  13. int main()
  14. {
  15.     int xSize, ySize, xCoor, yCoor;
  16.     int **board;
  17.  
  18.     // Loop until user enters usable input for board's width, height,
  19.     // and starting coordinates.
  20.     do
  21.     {
  22.         cout << "Enter length and height of board, seperated by a" << endl
  23.              << "space (each greater than zero): ";
  24.         cin >> xSize >> ySize;
  25.     } while ((xSize < 1) || (ySize < 1));
  26.  
  27.     do
  28.     {
  29.         cout << "Enter starting X coordinate in the range of 1-"
  30.              << xSize << ": ";
  31.         cin >> xCoor;
  32.     } while ((xCoor > xSize) || (xCoor < 1));
  33.  
  34.     do
  35.     {
  36.         cout << "Enter starting Y coordinate in the range of 1-"
  37.              << ySize << ": ";
  38.         cin >> yCoor;
  39.     } while ((yCoor > ySize) || (yCoor < 1));
  40.  
  41.     // Display debug information.
  42.     cout << "X: " << xSize << "; Y: " << ySize << endl;
  43.     cout << "X Coor: " << xCoor << "; Y Coor: " << yCoor << endl;
  44.  
  45.     // Convert to zero-based coordinates (as opposed to one-based).
  46.     xCoor--;
  47.     yCoor--;
  48.  
  49.     cout << "---------------------------------------------------" << endl << endl;
  50.  
  51.     // Make two-dimensional array out of pointers (assignment requirement).
  52.     board = new int *[xSize];
  53.     int **temp = board;
  54.  
  55.     for (int a = 0; a < xSize; a++)
  56.     {
  57.         *temp = new int[ySize];
  58.         (temp)++;
  59.     }
  60.  
  61.     // More debug information to make sure board is created and populated
  62.     // with zeroes correctly.
  63.     InitializeBoard(board, xSize, ySize);
  64.     DisplayBoard(board, xSize, ySize);
  65.  
  66.     // Run Knight's Tour algorithm...
  67.     cout << endl << "---------------------------------------------------" << endl;
  68.     cout << "Executing Knight's Tour..." << endl;
  69.  
  70.     if (KnightsTour(board, xCoor, yCoor, xSize, ySize, 1))
  71.     {
  72.         cout << "Solution found: " << endl << endl;
  73.         DisplayBoard(board, xSize, ySize);
  74.     }
  75.     else
  76.     {
  77.         cout << "No solution found." << endl << endl;
  78.         DisplayBoard(board,xSize,ySize);
  79.     }
  80.  
  81.     // Free up memory allocated for board.
  82.     for(int i = 0; i < xSize; i++)
  83.     {
  84.         delete [] (*board);
  85.         (board)++;
  86.     }
  87.  
  88.     cout << "Press any key to continue...";
  89.     cin.ignore(1000,'\n');
  90.     cin.get();
  91.  
  92.     return 0;
  93. }
  94.  
  95. // Function to initialize board (populate two-dimensional array
  96. // with zeroes).
  97. void InitializeBoard(int **board, int xSize, int ySize)
  98. {
  99.     int x, y;
  100.  
  101.     for (x = 0; x < xSize; x++)
  102.     {
  103.         for (y = 0; y < ySize; y++)
  104.         {
  105.             board[x][y] = 0;
  106.         }
  107.     }
  108. }
  109.  
  110. // Display the board.
  111. void DisplayBoard(int **board, int xSize, int ySize)
  112. {
  113.     int x, y;
  114.  
  115.     for (x = 0; x < xSize; x++)
  116.     {
  117.         for (y = 0; y < ySize; y++)
  118.         {
  119.             cout << setw(3) << board[x][y];
  120.         }
  121.         cout << endl;
  122.     }
  123. }
  124.  
  125.  
  126. // Check to see if the move is valid (i.e. check to see if the coordinates
  127. // aren't out of the board's bounds, and that the space isn't already occupied
  128. // by a move number).
  129. bool MoveIsValid(int **board, int xCoor, int yCoor, int xSize, int ySize)
  130. {
  131.     if ((xCoor < 0) || (xCoor >= xSize))
  132.     {
  133.         return false;
  134.     }
  135.  
  136.     if ((yCoor < 0) || (yCoor >= ySize))
  137.     {
  138.         return false;
  139.     }
  140.  
  141.     if (board[xCoor][yCoor] != 0)
  142.     {
  143.         return false;
  144.     }
  145.  
  146.     return true;
  147. }
  148.  
  149.  
  150. // Knight's Tour algorithm.
  151. bool KnightsTour(int **board, int xCoor, int yCoor, int xSize, int ySize, int moveNum)
  152. {
  153.     if (!MoveIsValid(board, xCoor, yCoor, xSize, ySize))
  154.     {
  155.         return false;
  156.     }
  157.  
  158.     board[xCoor][yCoor] = moveNum;
  159.  
  160.     if ((xSize * ySize) == moveNum)
  161.     {
  162.         return true;
  163.     }
  164.  
  165.     cout << "KT: " << yCoor << ", " << xCoor << ", " << moveNum << endl;
  166.  
  167.     // Each call to KnightsTour() looks for another potential square to move
  168.     // onto.
  169.     if (!KnightsTour(board, (xCoor - 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  170.         if (!KnightsTour(board, (xCoor - 2), (yCoor - 1), xSize, ySize, (moveNum + 1)))
  171.             if (!KnightsTour(board, (xCoor - 2), (yCoor + 1), xSize, ySize, (moveNum + 1)))
  172.                 if (!KnightsTour(board, (xCoor - 1), (yCoor + 2), xSize, ySize, (moveNum + 1)))
  173.                     if (!KnightsTour(board, (xCoor + 1), (yCoor + 2), xSize, ySize, (moveNum + 1)))
  174.                         if (!KnightsTour(board, (xCoor + 2), (yCoor + 1), xSize, ySize, (moveNum + 1)))
  175.                             if (!KnightsTour(board, (xCoor + 2), (yCoor - 1), xSize, ySize, (moveNum + 1)))
  176.                                 if (!KnightsTour(board, (xCoor + 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  177.                                     // At this point, there are no good moves left.
  178.                                     return false;
  179. }
  180.  
As a little bit of background, the Knight's Tour is a sequence of moves by a knight (that is, the chess piece) that will visit every square exactly once. The program is supposed to output a matrix of non-repeating numbers, from 1 to the number of squares on the board, because the "knight" leaves a non-zero number on each square it has visited.
Feb 14 '07 #3
Ganon11
3,652 Expert 2GB
I'm pretty sure the reason moveNum is reseting is because of the recursion involved. For instance, if I've found a good path from 20-23. but move 24 is impossible, I should be able to backtrack and try a new path from 20 - but your function has already set 21, 22, and 23 in the board, so those spaces will count as occupied. You might be able to change your condition (board[xCoor][yCoor] == 0) to board[xCoor][yCoor] < moveNum.

This is a very interesting problem...
Feb 14 '07 #4
AdrianH
1,251 Expert 1GB
I'm pretty sure the reason moveNum is reseting is because of the recursion involved. For instance, if I've found a good path from 20-23. but move 24 is impossible, I should be able to backtrack and try a new path from 20 - but your function has already set 21, 22, and 23 in the board, so those spaces will count as occupied. You might be able to change your condition (board[xCoor][yCoor] == 0) to board[xCoor][yCoor] < moveNum.

This is a very interesting problem...
Sorry, I've still not read this programme. However, if what Ganon11 is saying is correct, then it should be easy to fix this by zeroing the cell when backtracking.

A simple solution for this would be to have:
  • a function moveFrom() that passes the board and the count (unless you make those global or make it implicit by creating an object which contains this information), and the current position. moveFrom() will then:
    • set the current position with the current count
    • increment the count
    • determine a valid position to go to in a systematic way
    • and call moveFrom() with the new found valid position.
    • if moveFrom() returns false, then it couldn't find a path, so try next valid position.
    • if a complete path was not found and no more valid positions are found, then set current cell to 0 (if count is global or implicit, don’t forget to decrement it) and return false, otherwise, return true.
A complete path is determined if the count is equal to the total number of squares on the board.

Again, I apologise for not looking at your code. It was easier to spit out the algorithm and I've got to go.


Adrian
Feb 14 '07 #5
Thanks for your replies.

I'm pretty sure the reason moveNum is reseting is because of the recursion involved. For instance, if I've found a good path from 20-23. but move 24 is impossible, I should be able to backtrack and try a new path from 20 - but your function has already set 21, 22, and 23 in the board, so those spaces will count as occupied. You might be able to change your condition (board[xCoor][yCoor] == 0) to board[xCoor][yCoor] < moveNum.

This is a very interesting problem...
I don't see that condition anywhere. There is (board[xCoor][yCoor] != 0), and I tried modifying that to (< moveNum), but then the board was changed completely to zeroes.

Sorry, I've still not read this programme. However, if what Ganon11 is saying is correct, then it should be easy to fix this by zeroing the cell when backtracking.
  • a function moveFrom() that passes the board and the count (unless you make those global or make it implicit by creating an object which contains this information), and the current position. moveFrom() will then:
    • set the current position with the current count
    • increment the count
    • determine a valid position to go to in a systematic way
    • and call moveFrom() with the new found valid position.
    • if moveFrom() returns false, then it couldn't find a path, so try next valid position.
    • if a complete path was not found and no more valid positions are found, then set current cell to 0 (if count is global or implicit, don’t forget to decrement it) and return false, otherwise, return true.

A complete path is determined if the count is equal to the total number of squares on the board.

Adrian
Thanks for your time. That's pretty much what the KnightsTour() function that I have now does, I think. One thing it doesn't do, though, is set the cell to zero. I tried adding code earlier that set board[xCoor][yCoor] = 0, but I didn't know where to put it. I tried putting it after the last recursive KnightsTour() call, but then the matrix produced had zeroes in it.

Here are some notes from my class as to how the program should be written:
  • Check to make sure it's not out of bounds (handled by MoveIsValid())
  • Check to make sure sure you haven't been there before (also handled by MoveIsValid())
  • Check to see if this move is the last (handled by ((xSize * ySize) == moveNum) condition).
  • Eight recursive calls to KnightsTour()
  • At the end, all eight moves are bad
  • Remove number from board; board[xCoor][yCoor] = 0 (don't know where to put this)
  • Have a default return statement (handled by "return false;")

As far as I can tell, I have everything implemented, except for the "remove number from the board" part.

Thanks again.
Feb 14 '07 #6
I solved it (I think). I changed the last line in KnightsTour() to "return false;" to this:

Expand|Select|Wrap|Line Numbers
  1. if (!KnightsTour(board, (xCoor + 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  2. {
  3.     board[xCoor][yCoor] = 0;
  4.     return false;
  5. }
  6.  
Thanks for all your help.
Feb 14 '07 #7
nmadct
83 Expert
Generally speaking, a recursive solution like this is much easier to write if you avoid passing around a data structure that is modified using side effects (i.e. changing the values of variables). The side effects make it much more complicated to backtrack to a previous state, since you've overwritten the previous state. If you made a new copy of the board matrix every time you plotted a successful move, then you'd never have to worry about "undoing" moves when the code follows a dead-end path and has to backtrack.
Feb 14 '07 #8
willakawill
1,646 1GB
I solved it (I think). I changed the last line in KnightsTour() to "return false;" to this:

Expand|Select|Wrap|Line Numbers
  1. if (!KnightsTour(board, (xCoor + 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  2. {
  3.     board[xCoor][yCoor] = 0;
  4.     return false;
  5. }
  6.  
Thanks for all your help.
You have not solved the problem. Try again.
The fact that the recursion steps you back to a space from where you have a viable move left does not necessarily have to be a problem. I imagine that this could be a very useful 'feature' of your algorithm if implimented correctly. Each time you get stuck the program will go back to a previous position and start again. One of the things you have to do, as you have already been advised, is to reset the squares to zero that you have backtracked over. Another would be to ensure that you don't keep repeating the same two scenarios ad infinitum.
Good luck
Feb 15 '07 #9
AdrianH
1,251 Expert 1GB
Generally speaking, a recursive solution like this is much easier to write if you avoid passing around a data structure that is modified using side effects (i.e. changing the values of variables). The side effects make it much more complicated to backtrack to a previous state, since you've overwritten the previous state. If you made a new copy of the board matrix every time you plotted a successful move, then you'd never have to worry about "undoing" moves when the code follows a dead-end path and has to backtrack.
nmadct,

You are correct that it can be easier and when using a functional language (one that doesn't have object and global variables) it is actually required, but computationally, it is more resource intensive. So, for efficency, undoing a state change that was done to get there is actually a better idea.

Adrian
Feb 15 '07 #10
AdrianH
1,251 Expert 1GB
You have not solved the problem. Try again.
The fact that the recursion steps you back to a space from where you have a viable move left does not necessarily have to be a problem. I imagine that this could be a very useful 'feature' of your algorithm if implimented correctly. Each time you get stuck the program will go back to a previous position and start again. One of the things you have to do, as you have already been advised, is to reset the squares to zero that you have backtracked over. Another would be to ensure that you don't keep repeating the same two scenarios ad infinitum.
Good luck
Hi willakawill,

What exactly do you mean by "keep repeating the same two scenarios ad infinitum"? What two are you referring to?

Are you suggesting a heuristic? or perhaps detecting a similar sub-board configuration and discard the ones known to not lead to the goal? If so, what you are describing is using pattern recognition for board subsets.

It may possible, no doubt about it, but it also may not be trivial. AI is a course I really enjoyed in University and the discussion of search and how to implement it is a huge part of the course. In fact I think that was the course, because to reach the goal is to search for it.

Heuristics could be a viable way of doing this, but sometimes heuristics could not only cut off large portions of the search tree, but if not a good heuristic, it could also cut off the goal. However, there may be more than one path to the goal, so pruning some of the search branches which may have one or more goal paths may still not mean you have a bad heuristic, as it still may lead you to the goal faster.

But the question is, what is a good heuristic? Or are you thinking about getting the computer to detect it for you? That is also not trivial. However, this is all interesting, and I would suggest that you try it if interested. I can tell you this much, given Government and Wars, we need all the intelligence we can get, artificial or otherwise. :)


Adrian
Feb 15 '07 #11
AdrianH
1,251 Expert 1GB
I solved it (I think). I changed the last line in KnightsTour() to "return false;" to this:

Expand|Select|Wrap|Line Numbers
  1. if (!KnightsTour(board, (xCoor + 1), (yCoor - 2), xSize, ySize, (moveNum + 1)))
  2. {
  3.     board[xCoor][yCoor] = 0;
  4.     return false;
  5. }
  6.  
Thanks for all your help.
No problem. Glad to help.


Adrian
Feb 15 '07 #12
nmadct
83 Expert
nmadct,

You are correct that it can be easier and when using a functional language (one that doesn't have object and global variables) it is actually required, but computationally, it is more resource intensive. So, for efficency, undoing a state change that was done to get there is actually a better idea.

Adrian
"Computationally" both methods are equivalent, in the sense that in the abstract they requre the same amount of computation. In terms of implementation, the cost of copying memory will slow things down. On a multi-CPU system, the copying approach would make parallelization feasible and would thus offer a great potential speedup. Granted, in any architecture, the copying method requires more memory. Which approach is a "better idea" depends on where you expect your program to run. A destructively updating appraoch will probably perform better on your home desktop, so you'd probably prefer it if you're writing AI for a game, but if you're planning to do a long-running computation on a supercomputer then you'll consider how you can parallelize your program.
Feb 15 '07 #13
willakawill
1,646 1GB
Hi willakawill,

What exactly do ...Adrian
When we step back to a position with a viable move we have 2 options:
1. we go with the new move just detected and then reset higher move numbers to zero
2. we reset higher move numbers to zero and allow the choice of all available moves except the move number we are replacing

Either way we are onto a potential infinite loop. Even though I am not suggesting an heuristic approach, I am pointing to the potential pitfalls of the current approach. Not for me to solve this puzzle. There are many brave attempts already online.
Feb 15 '07 #14
nmadct
83 Expert
A tip for you on this problem. When you have a program that you think is correct, test if for a smaller board first. I've written a solution, and if I run it for boards 5, 6 or 7 squares across, it starts spitting out solutions right away. It takes WAY longer for an 8 square board, too long to be useful for testing. (Don't try a board smaller than 5 squares because there are no solutions.)
Feb 16 '07 #15
AdrianH
1,251 Expert 1GB
When we step back to a position with a viable move we have 2 options:
1. we go with the new move just detected and then reset higher move numbers to zero
2. we reset higher move numbers to zero and allow the choice of all available moves except the move number we are replacing

Either way we are onto a potential infinite loop. Even though I am not suggesting an heuristic approach, I am pointing to the potential pitfalls of the current approach. Not for me to solve this puzzle. There are many brave attempts already online.
I still don't see. In the algorithm implemented, the squares that were moved upon were marked as squares that could not be moved upon again. Upon failure of finding a solution, backtracking occurred clearing the squares where the move didn't work to a point where there was another possible move that was not tried.

Perhaps if you stated an example for your 2 points, it would be clearer. I would like to understand what you are referring to.


Adrian
Feb 16 '07 #16
AdrianH
1,251 Expert 1GB
"Computationally" both methods are equivalent, in the sense that in the abstract they requre the same amount of computation. In terms of implementation, the cost of copying memory will slow things down. On a multi-CPU system, the copying approach would make parallelization feasible and would thus offer a great potential speedup. Granted, in any architecture, the copying method requires more memory. Which approach is a "better idea" depends on where you expect your program to run. A destructively updating appraoch will probably perform better on your home desktop, so you'd probably prefer it if you're writing AI for a game, but if you're planning to do a long-running computation on a supercomputer then you'll consider how you can parallelize your program.
I buy that. The algorithm devised needs to be scaled to the system you are planning to use it on. The abstract is only part of the problem, as one has to also consider computational limitations based on the hardware they are running on. Since most people don't have a supercomputer with multi-processor core architecture, to break up a non-IO bounded computation would actually be detrimental to the system, as you start gaining significant overhead when moving from one thread to another (which in this case far exceeds copying of structures which use memory). Though on a duel-core processor, you probably be able to increase the throughput by just under 2 time (probably closer to 1.5-1.75 times).


Adrian
Feb 16 '07 #17
willakawill
1,646 1GB
I still don't see. In the algorithm implemented, the squares that were moved upon were marked as squares that could not be moved upon again. Upon failure of finding a solution, backtracking occurred clearing the squares where the move didn't work to a point where there was another possible move that was not tried.

Perhaps if you stated an example for your 2 points, it would be clearer. I would like to understand what you are referring to.


Adrian
The squares were not cleared after backtracking. This gave us the 2 possible scenarios
Feb 16 '07 #18

Sign in to post your reply or Sign up for a free account.

Similar topics

19
by: Carlos Ribeiro | last post by:
Hello all, Here I am using some deeply nested, tree-like data structures. In some situations I need to traverse the tree; the old-style way to do it is to write a recursive method on the node...
7
by: Jon Slaughter | last post by:
#pragma once #include <vector> class empty_class { }; template <int _I, int _J, class _element, class _property> class RDES_T {
1
by: Jon Slaughter | last post by:
I've managed to put together a template class that basicaly creates a recursive tree that lets you easily specify the "base" class of that tree and and ending notes and lets you stop the recursive...
0
by: googlegroups111 | last post by:
This is an EXCERPT from the story of the Philip Bartlett the Knight in Shining Armour from the days of hoary olde England, a story adapted by an author who shall remain nameless..... One day...
9
by: whitehatmiracle | last post by:
im stuck, thers a prob with the backtrack function. #include <iostream.h> #include <conio.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #define size 5
4
by: Xah Lee | last post by:
A Lambda Logo Tour (and why LISP languages using λ as logo should not be looked upon kindly) Xah Lee, 2002-02 Dear lispers, The lambda character λ, always struck a awe in me, as with...
18
by: Bert | last post by:
This is a past question from a programming competition. On a chess board (8 squares by 8 squares), there's is a knight sitting on b1 (2 from the left of the bottom row). To cut the crap, find out...
3
by: sliever | last post by:
hey! to anyone out there who might be able to help me with my problem about the knight's tour using php pls. help me.. i've come up with a long solution... ?> $chessboard=array ( ...
0
by: slapsh0t11 | last post by:
Hello, I know this is a popular problem with a lot of solutions, but I don't want to be pointed to a post by someone else with THEIR solution. I want to figure out how to make my own code work. ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.