2

I'm working on a search algorithm project, finding the solution for the 16 puzzle.

I have two lists of structs that contain a 2D array board[N][N]

The numbers in the list are unique in a range of 0-15, the difference is their order.

BoardA = 0  1  2  3           BoardB = 4  1  2  3  
         4  5  6  7                    0  5  6  7
         8  9 10 11                    8  9 10 11
        12 13 14 15                   12 13 14 15

As you can see, the only difference between boards will be the order of the numbers. Obviously it is possible to iterate through each board checking if

BoardA[i][j] == BoardB[i][j]

However, if there are hundreds or thousands of boards on a list, comparing them this way is undesirable.

Is there a way to quickly or efficiently compare two boards for sameness?

MKUltra
  • 312
  • 1
  • 12
  • `BoardA[i][j] != BoardB[i][j]` in what you've shown .. how are you defining "sameness"? Same numbers in each board regardless of their order? – yano Oct 30 '17 at 21:36
  • How large can be `N`? Is it always `4`? If so each board can be easily encoded as 8-byte (64-bit) numbers. But given the numbers are unique, even more efficient packing can be done. – Eugene Sh. Oct 30 '17 at 21:40
  • @yano, the numbers will always be 0-15, sameness as in same order. – MKUltra Oct 30 '17 at 21:45
  • 3
    `memcmp(BoardA, BoardB, sizeof BoardA) == 0` – mch Oct 30 '17 at 21:46
  • yeah I would go with [`memcmp`](https://linux.die.net/man/3/memcmp) then. – yano Oct 30 '17 at 21:47
  • What do you need to do with two lists of boards exactly? – DAle Oct 30 '17 at 21:47
  • @EugeneSh. In this program N will only be 4, numbers are unique in each board, always 0-15. – MKUltra Oct 30 '17 at 21:47
  • So there are 20922789888000 possible boards, safe an 64bit integer instead of the arrays and compare them. – mch Oct 30 '17 at 21:49
  • again. The question here not about "sameness" but about the data representation. It looks like you are mixing up the back-end and the front-end. For the back-end you should have your data packed such that the basic operations with it are easy to implement efficiently. For the front-end you need to unpack it, but this operation is not time and efficiency critical in most cases. – Eugene Sh. Oct 30 '17 at 21:50
  • https://stackoverflow.com/a/11117236/905902 the sixteenth prime number is not that large. [but: do you want permutations to compare as equal?] – wildplasser Oct 30 '17 at 21:58

2 Answers2

1

The elements of a two-dimensional array are located in a contiguous memory block. So to compare two arrays, you are just comparing two memory blocks. The fastest way to do it is with memcmp(). You did not specify what type each array element is, so I will use int and you can replace it with another type if your elements are not ints.

if (memcmp(BoardA, BoardB, sizeof(int) * N * N) == 0) {
  /* equal */
} else {
  not /* equal */
}
George
  • 2,090
  • 2
  • 12
  • 25
  • Do you know if there is a notable difference between memcmp(BoardA, BoardB, sizeof(int) * N * N) and memcmp(BoardA, BoardB, sizeof(BoardA)) – MKUltra Oct 30 '17 at 21:54
  • 2
    @MKUltra there is no difference between them, it is opinion based which one you prefer, I prefer `sizeof BoardA` without the parantheses. – mch Oct 30 '17 at 21:56
  • Depends on how you defined BoardA. If BoardA is a pointer, then you wouldn't want to use sizeof(BoardA). You can printf the values of sizeof(int) * N * N and sizeof(BoardA) to find out if they are the same. If they are, go with sizeof(BoardA). – George Oct 31 '17 at 15:21
0

You might save a few cycles with tricks like memcmp(), but really the simple, straightforward comparisons will optimize well. If you exit early on failure, then it will only compare all elements in the case where the arrays are equal, in which case every comparison is needed anyway, even with memcmp().

So keep it simple:

int equals(int (*a)[4], int (*b)[4]) {
    for (int i = 0; i < 4; i += 1) {
        for (int j = 0; i < 4; j += 1) {
            if (a[i][j] != b[i][j]) return 0;
        }
    }
    return 1;
}
Lee Daniel Crocker
  • 12,296
  • 1
  • 24
  • 47