A permutation puzzle (Rubik’s cube, 15-puzzle, Megaminx, Pyraminx, Top Spin…) is a set of moves, each a permutation of the stickers; the reachable positions form the group generated by the moves. Two questions: how many positions are reachable (group order: Schreier–Sims), and which ones (invariants: parity, orientation sums).

PuzzlePositionsNotes
Rubik’s cubethree invariants divide the naive count by
cubeone corner fixed (whole-cube rotations removed)
God’s number, 20 face turns (Rokicki, Kociemba, Davidson, Dethridge 2010); 26 quarter turns (2014)computer proofs with symmetry and cosets
God’s number, 11 face turns, 14 quarter turnsplain BFS over 3.67M states
group structureorientations, then permutations with equal parity

Invariants of the cube (with fixed centres): (1) the corner permutation and the edge permutation have the same parity; (2) the corner twists sum to ; (3) the edge flips sum to . Every position satisfying the three is reachable.

// Order of the permutation group generated by the added permutations (of 0..n-1), by Schreier-Sims.
// Level i: orbit of point i under G_i = stabilizer of 0..i-1, with transversal tr[i][j] mapping i -> j.
struct SchreierSims {
    using P = vector<int>;
    int n; vector<vector<P>> gens, tr;                       // gens[i]: strong generators lying in G_i
    SchreierSims(int n) : n(n), gens(n), tr(n, vector<P>(n)) { P id(n); iota(all(id), 0); for (int i = 0; i < n; i++) tr[i][i] = id; }
    static P mul(const P& a, const P& b) { P c(sz(a)); for (int i = 0; i < sz(a); i++) c[i] = a[b[i]]; return c; }   // a after b
    static P inv(const P& a) { P c(sz(a)); for (int i = 0; i < sz(a); i++) c[a[i]] = i; return c; }
    void add(const P& g) { sift(g, 0); }
    void sift(P p, int i) {                                  // p fixes 0..i-1; strip it through the transversals
        for (; i < n; i++) {
            int j = p[i];
            if (tr[i][j].empty()) { addGen(p, i); return; }
            p = mul(inv(tr[i][j]), p);
        }
    }
    void addGen(const P& g, int lvl) {                       // g fixes 0..lvl-1, so it lies in G_0, ..., G_lvl
        for (int i = lvl; i >= 0; i--) {
            gens[i].push_back(g);
            for (int j = 0; j < n; j++) if (!tr[i][j].empty()) { P t = tr[i][j]; extend(mul(g, t), i); }
        }
    }
    void extend(const P& t, int i) {                         // t in G_i maps i to t[i]
        int j = t[i];
        if (!tr[i][j].empty()) { sift(mul(inv(tr[i][j]), t), i + 1); return; }   // Schreier generator
        tr[i][j] = t;
        for (int k = 0; k < sz(gens[i]); k++) { P g = gens[i][k]; extend(mul(g, t), i); }
    }
    i128 order() const {
        i128 r = 1;
        for (int i = 0; i < n; i++) { int c = 0; for (auto& t : tr[i]) c += !t.empty(); r *= c; }
        return r;
    }
};
 
// The 6 outer-face quarter turns of the N x N x N cube as permutations of its 6N^2 stickers.
vector<vector<int>> cubeMoves(int N) {
    vector<array<int, 6>> st;                                // (position, outward normal); coordinates 1-N, 3-N, ..., N-1
    for (int x = 1 - N; x < N; x += 2) for (int y = 1 - N; y < N; y += 2) for (int z = 1 - N; z < N; z += 2) {
        array<int, 3> p{x, y, z};
        for (int a = 0; a < 3; a++) if (abs(p[a]) == N - 1) { array<int, 6> s{x, y, z, 0, 0, 0}; s[3 + a] = p[a] > 0 ? 1 : -1; st.push_back(s); }
    }
    sort(all(st));
    vector<vector<int>> moves;
    for (int a = 0; a < 3; a++) for (int sgn : {-1, 1}) {
        int b = (a + 1) % 3, c = (a + 2) % 3; vector<int> perm(sz(st));
        for (int i = 0; i < sz(st); i++) {
            auto s = st[i];
            if (s[a] == sgn * (N - 1)) {                     // in the turning layer: rotate 90 degrees about axis a
                s[b] = -st[i][c]; s[c] = st[i][b]; s[3 + b] = -st[i][3 + c]; s[3 + c] = st[i][3 + b];
            }
            perm[i] = int(lower_bound(all(st), s) - st.begin());
        }
        moves.push_back(perm);
    }
    return moves;
}

Feeding the six moves of cubeMoves(3) to SchreierSims(54) prints instantly; three moves of cubeMoves(2) give .