2

#include <stdio.h>

#define SIDE 8

#define VISITED 1
#define NOT_VISITED 0

#define FALSE 0
#define TRUE !FALSE

void printBoard(int board[][SIDE]);
int goHorsie(int board[][SIDE], int x, int y, int step, int cor1, int cor2, int cor3);

int main(void)
{

    int board[SIDE][SIDE] = { NOT_VISITED };
    int found = 0;

    found = goHorsie(board, 0, 0, 1, 0, 0, 0);

    if (found)
    {
        printf("Yes, there is a path from 0,0 through all corners! Here it is:\n");
        printBoard(board);
    }
    else
    {
        printf("No path from 0,0 through all corners\n");
        printBoard(board);
    }

    getchar();
    return 0;
}

int goHorsie(int board[][SIDE], int x, int y, int step, int cor1, int cor2, int cor3)
{
    int res = FALSE, check = 1;
    if (board[x][y] != NOT_VISITED //We were here already!
        || x >= SIDE || y >= SIDE || x < 0 || y < 0)
    {
        res = FALSE;
        check = 0;
    }

    if (x == 7 && y == 7)
    {
        printf("1)found!\n");
        cor1 = 1;
    }
    if (x == 7 && y == 0)
    {
        printf("2)found!\n");
        cor2 = 1;
    }
    if (x == 0 && y == 7)
    {
        printf("3)found!\n");
        cor3 = 1;
    }
    if (cor1 == 1 && cor2 == 1 && cor3 == 1)
    {
        printf("FOUND ALL!\n");
        return TRUE;
    }

    else if(check == 1)
    {
        board[x][y] = step;
        step++;
        res =
            goHorsie(board, x + 1, y - 2, step, cor1, cor2, cor3) ||
            goHorsie(board, x + 2, y + 1, step, cor1, cor2, cor3) ||
            goHorsie(board, x + 2, y - 1, step, cor1, cor2, cor3) ||
            goHorsie(board, x + 1, y + 2, step, cor1, cor2, cor3) ||
            goHorsie(board, x - 2, y + 1, step, cor1, cor2, cor3) ||
            goHorsie(board, x - 2, y - 1, step, cor1, cor2, cor3) ||
            goHorsie(board, x - 1, y + 2, step, cor1, cor2, cor3) ||
            goHorsie(board, x + 1, y - 2, step, cor1, cor2, cor3);
            
        if (!res)
        {
            board[x][y] = NOT_VISITED;
        }
    }
    return res;
}


void printBoard(int board[][SIDE])
{
    int i = 0, j = 0;
    for (int i = 0; i < SIDE; i++)
    {
        for (int j = 0; j < SIDE; j++)
        {
            printf("%3d", board[i][j]);
        }
        printf("\n");
    }
}

I'm using recursion to find the path to all 3 corners.

I ran the program for about 20min now and it's still didn't get to the solution.

Ik why its taking too long but not sure if it will even get me to the answer, and I think it's looping forever.

So my question is did I make the function right and will it eventually give me the right answer (the path to all 3 corners), or what do I need to change in order to get to the answer.

What I mean by 3 corners is: top right, bottom right and bottom left.

  • 1
    You need to show how you initialize `board` and how you do the first function call – Support Ukraine May 10 '21 at 04:39
  • It's unclear to me what you are trying to find. Is it a) **one** path makess you visit all three corners or is b) three paths, i.e. one path for each corner? – Support Ukraine May 10 '21 at 04:43
  • Upvoting only because your code's function is so awesomely named: `goHorsie` – selbie May 10 '21 at 05:46
  • im trying to find 1 path that covers all 3 corners – Hillskiller May 10 '21 at 09:37
  • If you introduce macros (consts would be better) please use them to avoid magic numbers. E.g. 7 -> `SIDE-1`. If you start the concept of having a variable `res` stay consistent and do not have two returns. Your `if`-tree should have more `else if`s. The information you store in `cor123` is only kept for deeper recursions. If you leave one recursion, the information on found corners is lost. Use pointer to `int` for those. – Yunnosch May 10 '21 at 10:59
  • @Hillskiller See updated answer – Support Ukraine May 10 '21 at 19:55
  • ah i see thank you for help appreciate it a lot :) – Hillskiller May 11 '21 at 04:34

3 Answers3

0

There may be other bugs but here is one:

if (board[x][y] != NOT_VISITED || x >= SIDE || y >= SIDE || x < 0 || y < 0)

Evaluation of this expression starts with board[x][y] != NOT_VISITED. At that time x and y may have values that are outside the board. So you do out-of-bounds access.

Check the values of x and y before accessing the array.

Like:

if (x >= SIDE || y >= SIDE || x < 0 || y < 0 || board[x][y] != NOT_VISITED)

Another issue is that you check for "found" before you check whether you have already visited that corner once. That will give some unexpected prints of "found".

This line:

if (x >= SIDE || y >= SIDE || x < 0 || y < 0 || board[x][y] != NOT_VISITED)

shall be the very first statement in the function.

One more bug

        goHorsie(board, x + 1, y - 2, step, cor1, cor2, cor3) ||
        goHorsie(board, x + 2, y + 1, step, cor1, cor2, cor3) ||
        goHorsie(board, x + 2, y - 1, step, cor1, cor2, cor3) ||
        goHorsie(board, x + 1, y + 2, step, cor1, cor2, cor3) ||
        goHorsie(board, x - 2, y + 1, step, cor1, cor2, cor3) ||
        goHorsie(board, x - 2, y - 1, step, cor1, cor2, cor3) ||
        goHorsie(board, x - 1, y + 2, step, cor1, cor2, cor3) ||
        goHorsie(board, x + 1, y - 2, step, cor1, cor2, cor3);

the first and the last line are using the same expression, i.e. x + 1 and y - 2. So your code doesn't cover all 8 moves. It uses one move twice.

I ran the program for about 20min now and it's still didn't get to the solution.

Once you have fixed the bugs reported above, you can give it a try... but don't be surprised if you still next no solution within 20 minutes.

The thing is that there are so many paths to check that even modern computers will spend quite some time solving this.

Consider this:

step 1: 8 paths
step 2: 8 paths
step 3: 8 paths
...
step 16: 8 paths

In total 281.474.976.710.656 paths.... okay, it's not that bad because many of these path will stop before getting to step 16 because the horse leaves the board or returns to the same position. But still... there are many paths to check.

And can it be done in 16 steps? What it it requires 20 steps.. that is 1.152.921.504.606.846.976 or could it even require 64 steps!? 8^64 paths to check...

So to find a solution you should think differently than just brute force checking.

By fixing the order the corner was to be visited and by setting some restriction on the direction to move, I came up with this:

enter image description here

This solution shows that you can visit all 4 corners in 20 moves.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
0

This answer builds on the one by user 4386427, put them together to get a complete solution.

With int goHorsie(int board[][SIDE], int x, int y, int step, int cor1, int cor2, int cor3); you are always using copies of the information whether you found the three corners, from the current recursion. If you actually find one or two corners, but not all three in one recursive call, then the true values for those new finds are lost as soon as the recursion is left. In the next call you might find the missing corner(s) but not notice, because the info on previous finds is lost.

In order to keep infos on finds you could switch to pointer paramters.

int goHorsie(int board[][SIDE], int x, int y, int step, int* cor1, int* cor2, int* cor3);

and e.g. *cor1 = 1;

For that you need to introduce corresponding referencable variables inside main()

int maincor1 =0; etc.

and call from main() like found = goHorsie(board, 0, 0, 1, &maincor1, &maincor2, &maincor3);

and from inside still like

goHorsie(board, x + 1, y - 2, step, cor1, cor2, cor3)

which is identical code but uses the now pointer variables of same name as before.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
  • it's working better now but only at position (7,7) it stays 0 like it doesn't pass through it example output: https://pastebin.com/yzVasyBc – Hillskiller May 10 '21 at 14:21
  • You will probably have to ask a new question on the changed code. Make sure you incorporate the hints from both (all) answers here. Maybe you can update the question here, but be very careful not to invalidate any existing answer, i.e. it is necessary to keep the wrong code version discussed by the answers and only add more info like "EDIT: Incorporating the hints from the first few answers, I have this code .... and the misbehaviour now is ...". But that is risky. Better make a new question. You can accept an answer here (tough choice...) based on which fixed more problems. Comment other one. – Yunnosch May 10 '21 at 14:36
  • If you find two corners but not the most extreme one, I suspect that you miss the "twice the same" hint by the other answer. Please triple check 8 unique moves being checked. I mention this because I was particularily impressed by that part of the other answer. (Damn, I just gave reasons for accepting the other answer. Sigh.) – Yunnosch May 10 '21 at 14:38
  • i just fixed that still same problem: https://pastebin.com/0usfMdqx – Hillskiller May 10 '21 at 15:48
  • It seems you did not get the point of my comments, to ask a new question. Can I help you understand what I mean? – Yunnosch May 10 '21 at 16:23
  • ye sure why not – Hillskiller May 10 '21 at 16:54
  • OK. So what I mean is: Do not add infos here, especially not hidden in comments on an answer. Instead create a new question post, using https://stackoverflow.com/questions/ask Add all info there, especially all the info of changed code, the new behaviour and the insights you got from debugging it. – Yunnosch May 10 '21 at 17:11
0

Between other bugs that have been already said in the thread, you are missing something crucial: checking if the places have been found and returning if so. This is why the function runs forever. It should not take more than 30 seconds for it to find a solution.

Here is an updated working version of the code:

#include <stdio.h>
#include <stdlib.h>

#define SIDE 8
#define VISITED 1
#define NOT_VISITED 0

#define GOAL_X 0
#define GOAL_Y 7

#define FALSE 0
#define TRUE !FALSE

#define GOAL_FIRST_CORNER_X 0
#define GOAL_FIRST_CORNER_Y 7

#define GOAL_SECOND_CORNER_X 7
#define GOAL_SECOND_CORNER_Y 7


#define GOAL_THIRD_CORNER_X  7
#define GOAL_THIRD_CORNER_Y 0


void printBoard(int board[][SIDE]);

int goHorsie(int board[][SIDE], int x, int y, int step, int* foundFirst, int* foundSecond, int* foundThird);

int main(void)
{
    int board[SIDE][SIDE] = { NOT_VISITED };

    
    int* foundFirstCorner = (int*)malloc(sizeof(int) * 1);
    int* foundSecondCorner = (int*)malloc(sizeof(int) * 1);
    int* foundThirdCorner = (int*)malloc(sizeof(int) * 1);

    *foundFirstCorner = FALSE;
    *foundSecondCorner = FALSE;
    *foundThirdCorner = FALSE;

    if (goHorsie(board, 0, 0, 1, foundFirstCorner, foundSecondCorner, foundThirdCorner))
    {
        printf("Yes, there is a path passing through all the 3 corners without repeating\n");
        printBoard(board);
    }
    else
    {
        printf("No path passing through all corners without repating");
    }

    free(foundFirstCorner);
    free(foundSecondCorner);
    free(foundThirdCorner);
    getchar();
    return 0;
}

/*
Function checks if knight can travel from top left corner and travel through all corners
input: the board, the current x and y, the current step and pointers to ints representing if alredy found the first, second and third corners
output: whether a path was found
*/
int goHorsie(int board[][SIDE], int x, int y, int step, int* foundFirst, int* foundSecond, int* foundThird)
{
    int res = FALSE;

    if (*foundFirst && *foundSecond && *foundThird) // checks if has been to all the corners
    {
        res = TRUE;
    }
    else if (x >= SIDE || y >= SIDE || x < 0 || y < 0 || // out of the board
        board[x][y] != NOT_VISITED) // we were here already!
    {
        res = FALSE;
    }
    else if (x == GOAL_FIRST_CORNER_X && y == GOAL_FIRST_CORNER_Y) // checks if it is in the first corner
    {
        *foundFirst = TRUE;
        board[x][y] = step;
    }
    else if (x == GOAL_SECOND_CORNER_X && y == GOAL_SECOND_CORNER_Y) // checks if is in the second corner
    {

        *foundSecond = TRUE;
        board[x][y] = step;
    }
    else if (x == GOAL_THIRD_CORNER_X && y == GOAL_THIRD_CORNER_Y) // checks if it is in the third corner
    {

        *foundThird = TRUE;
        board[x][y] = step;
    }
    else
    {
        board[x][y] = step;
        step++;
        // changing order here will change the path, because once a condition is verified (TRUE) the rest aren't checked
        res = goHorsie(board, x + 2, y + 1, step, foundFirst, foundSecond, foundThird) ||
            goHorsie(board, x + 2, y - 1, step, foundFirst, foundSecond, foundThird) ||
            goHorsie(board, x + 1, y + 2, step, foundFirst, foundSecond, foundThird) ||
            goHorsie(board, x + 1, y - 2, step, foundFirst, foundSecond, foundThird) ||
            goHorsie(board, x - 2, y + 1, step, foundFirst, foundSecond, foundThird) ||
            goHorsie(board, x - 2, y - 1, step, foundFirst, foundSecond, foundThird) ||
            goHorsie(board, x - 1, y + 2, step, foundFirst, foundSecond, foundThird) ||
            goHorsie(board, x - 1, y - 2, step, foundFirst, foundSecond, foundThird);
        if (!res)
        {
            board[x][y] = NOT_VISITED;
        }
    }

    return res;
}


/*
Function prints the board
input: board to print
output: none
*/
void printBoard(int board[][SIDE])
{
    int i = 0, j = 0;
    for (i = 0; i < SIDE; i++)
    {
        for (j = 0; j < SIDE; j++)
        {
            printf("%3d", board[i][j]);
        }
        printf("\n");
    }
}
Nina
  • 79
  • 2
  • 10