0

I'm trying to code a program that finds for the God's Algorithm that solves a particular puzzle -- shortest sequence that leads current state until its solved state.

To do this, I have to map all permutations/states (nodes) with its respectively distances until solved (depth).

I'm using some breadth-first search concepts to get the permutations that puts the puzzle in a different/notVisited permutation and looping this until don't get any new position.

Beyond this, I'm using two algorithms to encode the permutations to a single index and retrieve the permutation back, aiming using this to putz depths values in a array. The following pseudo-code can demonstrate what I'm doing:

Fill table completely with -1
table[pos2idx(theSolvedPermutation)] = 0
depth = 0
loopbegin {
    numOfVisitedPositions = 0
        for (i = 1 to N_PERMUTATIONS) {
            if (table[i] == depth) then {
                for (each available movement m) {
                    current = pos2idx(m applied to idx2pos(i))
                    if (table[current]= -1) then {
                        numOfVisitedPositions++
                        table[current] = depth + 1
                    } endif
                } endfor
            } endif
        } endfor
    depth++
    print numOfVisitedPositions " positions at distance " depth
} loop while numOfVisitedPositions > 0

However, seems there are too many information to be processed using this approach in this mapping/indexing step.

Here is , respectively, the pseudos for pos2idx() and idx2pos() methods:

pos2idx(permutation[])
    index = 0
    for i = 1 to length - 2
        index *= (length - i + 1)
        for j = i + 1 to length
            if permutation[i] > permutation[j] then
                index += 1
        endfor
    endfor
return index

idx2pos(index, length)
    n = length
    perm[n]     = 2
    perm[n - 1] = 1
    sum = 0

    for i = n - 2 to 1
        perm[i] = 1 + (index % (n - i + 1))
        sum += perm[i] - 1
        index/= (n - i + 1)
        for j = i + 1 to n
            if perm[j] >= perm[i] then
                perm[j]++
        endfor
    endfor

    if sum % 2 = 1 then
        swap perm[n] with perm[n - 1]

    return perm

The puzzle have 12 "moving pieces", 8 different movements and parity restriction. This last means that we can't get permutations with a odd number of swaps (e.g. [1,2,4,3,...,12], an valid can be be [1,2,4,3,12,...11]), what I think that can be expressed with the value 12!/2. But, probably in terms of complexity, the algorithm doesn't finishes with this amount of data: my notebook i3 with 6GB ram spent 6 min to get a JavaHeapSizeException hahaha.

I just applied the same approach considering the puzzle have only 8 elements with 4 different movements (then would be 8!/2 permutations) and I successfully reached something like between 130000 and 145000 solutions per second.

Then, there are any hint for how to process/index this amount of permutations in this algorithm or this algorithm can't finish in a large processing like that? Any help is apreciated!

Some reference: - Computer Puzzling - Indexing - Useful Mathematics

Lucas Sousa
  • 192
  • 3
  • 14

1 Answers1

1

One consideration that would lower the number of configurations to look at:

Your current code regards two states to be distinct when they are really the same from a human point of view; this is when you can make the transition by just turning the whole cube. Such a transition does not count as a move, so these two states should be regarded the same. This reduces the number of distinct states by a factor of 12.

You could for instance require that one particular piece always remains at the same coordinate. This would mean you have to redefine some of the available moves so they do not touch this particular piece. For instance, let's say you will keep piece number 12 always fixed at position 12 (it never gets permuted), and that you currently have a move encoded as a permutation of pieces 10, 11, and 12. Then redefine that move as a permutation of pieces 1..9, as if you would first turn the whole cube in the opposite direction of the intended move (around that corner), and then perform the move (bringing back piece 12 into its home slot).

This means you don't have to store anything about piece 12: length can be 11 instead. At the same time your table will be 12 times smaller.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • I didn't understand very well about how to refactor the permutations anyways, in your case, the max permutations becomes to ```11!/2```? I tested make a loop for 0 to max only converting current index to permutation and converting it to index back just to perform the check with a non-empty loop body and it finished in around 30 seconds. When I put to store the results of indexing conversions on a array it took spent several minutes to get a HeapSpace exception. Even I didn't refactoring the permutations very well this range appears to be a big amount of data do be processed at once yet! – Lucas Sousa Oct 05 '19 at 22:54
  • As seen [here](https://www.jaapsch.net/puzzles/dinocube.htm) I believe is possible process this is someway, once the author managed to calculate the number of turns to get the puzzle solved. Probably he performed some of techinicals explained in the short reference I provided at the question. What do you think? – Lucas Sousa Oct 05 '19 at 22:56
  • 1
    Yes, max `11!/2`. Speed will depend on how you perform a move. For instance, you could imagine representing the array as a single integer, where each group of 4 bits is one value: you'd need 4x11 bits = 44, which fits in an 64-bit integer. Performing a move would then be a series of bit shifts, which might be more efficient then building and manipulating an array. – trincot Oct 06 '19 at 08:58
  • I'm backing to the project after a break. If I consider the array (puzzle state) as a single 64-bit number I can't understand how to associate it with its depths. For example, in the main example, the arrays are converted to an integer to be used as a index in another array, which wills contains its respective depth. Turning the state in a single number results in a large value (or even negative), that can't be a index in, e.g., Java. How to deal with it? – Lucas Sousa Aug 01 '20 at 22:29
  • This comment section is not really intended for follow-up questions, but the number does not need to be negative if you use an unsigned data type. Of course, if you plan to store 11!/2 = 19,958,400 entries with some info like depth, you'll need to have the memory available. If you need two bytes per entry, then you're looking at 40MB of memory. Not only is memory a challenge, also the time your algorithm needs to spend on each of those entries will be considerable. – trincot Aug 02 '20 at 10:14